@madpilot rants

Use CSS to speed your unobtrusive JavaScript

Unobtrusive JavaScript does for JavaScript what CSS did for HTML design. Separating the design and business logic client side means better re-use and compatibility.

To make a truly unobtrusive site, you should start with a base, non-JavaScript version of the site, and then add functionality dynamically. One of the issues with this is quite often you are left with elements that are required for HTML-only functions, but not for the JS version. Obviously, it’s easy to traverse the DOM tree and hide elements that not required like this:

var elementToHide = document.getElementById('hide_me');

if(elementToHide) {
    elementToHide.style.display = 'none';
}

but this can be pretty slow if you have lot of elements to hide. Sure, you could use XPath, but it isn’t supported in many browsers.

CSS is pretty darn quick when applying styles (well, you would hope so – that’s what it is designed for), so by dynamically including a CSS file via JavaScript we can hide (and show) elements really quickly. It’s all pretty simple:

  1. Create the style sheet (We’ll call it /stylesheets/css.js)
  2. Set up the desired styles in the style sheet as you would any another CSS file
  3. Drop the following code is to a JavaScript file and include it in your header
function unobtrusiveCSS() {
    head = document.getElementsByTagName('head');
    head = head[0];
    link = document.createElement('link')
    link.href = '/stylesheets/js.css';
    link.setAttribute('media', 'screen')
    link.setAttribute('rel', 'stylesheet');
    link.setAttribute('type', 'text/css');
    head.appendChild(link);
  }

  FastInit.addOnLoad(unobtrusiveCSS);

Now, you might have noticed that I’m using the FastInit library (written by the ever so talented Andrew Tetlaw). Because we are modifying the DOM, we need to wait for it to load before we can append anything. I could have used window.onload, but that would defeat the purpose, as we would have to wait for all of the images on the page to load, negating the speed up we would get.

The FastInit library will fire the JavaScript as soon as the DOM is loaded. (Go to the site to find out how it works – it’s quite ingenious), At the end of the day, you would need to a library like this regardless of whether you use the CSS include hack.

Caveat: Another way of doing it would be to use document.write, which would eliminate the need for an external library, but hacks like that make baby jeebus cry.