Wandering Thoughts archives


Notes to myself about progressive JavaScript

Now that I am starting to add various bits of JavaScript to our account request system, I'm being faced with the issues of making things still work gracefully if JavaScript isn't enabled at all. This is not exactly a new issue, especially given that I'm more than a decade late to this particular party, and so I'm writing things down here just to get them fixed in my mind.

(I'm punting on browser-dependent issues by assuming that JQuery will make them go away for any modern browser. As a pragmatic matter I just don't have the time and expertise to do better than this for what are relatively unimportant website augmentations.)

I can split my JavaScript usage into three different classes; things that are augmented by JavaScript, things that are replaced or modified by JavaScript, and things that don't work at all without JavaScript. The cases I need to worry about are the latter two (since augmentation should decay gracefully on its own provided that the augmented feature is not essential).

Let's suppose (not hypothetically) that we have an account request form that asks people for, among other things, their graduate student number. Of course you only have a graduate student number if you're actually a graduate student, so we'd like people to only be prompted for it if they set their status to 'graduate student'. There are at least two approaches to this: we could have that form field hidden in the HTML (or not present at all) and then revealed or created by JavaScript on the fly, or we could have the form field visible in the HTML, hidden on initial page load by JavaScript, and then revealed and hidden again by JS later. If we assume that JavaScript will always run (and run right), the first case is simpler and clearer. But the second case degrades better if the JS doesn't work because the graduate student number field is still there and usable.

(One way we can approach this is to get the actual feature right. Here the feature we really want is 'JavaScript hides the graduate student number if you're not a graduate student', not 'JavaScript reveals the graduate student number if you are'.)

So the rule is: for HTML elements that are replaced or modified by JavaScript, the base element should be present (and visible) on the page with JavaScript hiding or modifying it as needed when (and if) it runs. Or to put it shortly, hiding things degrades better than revealing them.

For things that don't work without JavaScript at all, another example. In the account request system there is a page for handling a bunch of pending requests together where I've added options for 'approve all' and 'reject all'. These options need some visible HTML widgets and they can't work (at least safely) without JavaScript. There are again at least two options: the basic HTML elements could be on the page to start with and made functional by JavaScript, or they could be missing from the base HTML and created by JavaScript when the page is loaded. Again the first option is simpler if we assume that JavaScript always works but the second option degrades better; if JavaScript doesn't run we don't have non-functional HTML elements on the page.

(Among other advantages of the first approach is that it lets you design and lay out the final HTML in one place.)

So the rule is: for things that don't work at all without JavaScript, the supporting HTML shouldn't be on the page at all; it should all be set up on the fly on page load (or whenever) when the JavaScript runs. Or in short, I should never allow non-functional elements to be visible.

(There are actually two options here; you can have the HTML created entirely in JavaScript or you can have it hidden with CSS styling and then revealed by JavaScript. My personal twitch is that I would rather not count on CSS keeping things hidden in all possible browsers, so I prefer the HTML to be entirely absent. However there are probably situations where this doesn't work very well, eg if you are laying out a complex form and you really want to keep all of the HTML in one spot instead of trying to spread it across a base HTML file and various chunks of HTML in your JavaScript.)

Sidebar: the basics of sane modern JavaScript

As far as I can tell, the basics of sane modern JavaScript are basically how a library like JQuery wants you to work:

  • put no or almost no JavaScript into your HTML; have it in an external file that the HTML pulls in with appropriate <script> tags.
  • do not embed JavaScript stuff inline in various HTML elements as, eg, onchange attributes; instead attach them on the fly when JQuery runs your code after page load finishes. Find the HTML elements to attach to through either id, class, or other selectable attributes.

I have a bit of JavaScript code on some pages but that's just there to set some variables, and the reason it's in the HTML is because I'm generating HTML from Django templates and I want to do variable insertion for things like JSON query URLs (because that makes it easy to switch them around between production and test environments).

(I have no desire to generate my JavaScript source through Django templating.)

Sidebar: an example of what I mean by (pure) augmentation

As part of the account request form, people are asked for the login they want. Obviously they can't get a login that's already taken (or reserved). The web application validates their chosen login when they submit the form (re-serving the form with appropriate error messages if there's a problem), but this is a little bit unfriendly; faster feedback would be nice. So I've augmented the login field with a bit of JavaScript that tries to validate your chosen login on the fly, inserting either an error message or a 'looks good' message into the form as applicable.

This is pure augmentation because it needs no additional HTML elements added to the page and the existing HTML elements remain completely functional even if JavaScript isn't running. JavaScript just adds a bonus feature that makes things friendlier.

web/ProgressiveJavaScriptNotes written at 21:25:28; Add Comment

Page tools: See As Normal.
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.