Live Stylesheets

Even after working with DTML for over a year, I'm still constantly astounded by how dynamic it actually is. The most important thing to keep in the back of your head as a DHTML programmer is that the same mechanisms used by the browser to build an HTML document at load time are available to your in-page scripts. So, really, the static loading of your pages when you access a url is just the HTML parser invoking the same methods on the same objects that are available to your javascript code.

Take this static HTML code:

This is my div

The same result can be achieved dynamically:

Nothing mind-blowing there; indeed, this technique is the cornerstone of DHTML. But it takes awhile to let it sink in to the point where using it is one of your first strategies to solving a problem. Specifically, you can use it not only to dynamically change layout-related HTML elements (span, div, ul, table, et al...), but also to create/modify behavioral elements(link, script, meta, etc...)

That said, I was recently trying to create a CSS stylesheet at runtime, and enable it so that its rules would be active in the page. At first, I was trying to use the W3C DOM CSS interface, the idea being to create a stylesheet object, add a bunch of rules to it corresponding to the rules that I wanted, and then put it into the stylesheets array. Unfortunately, doing this in a cross-platform way is borderline impossible. After pounding my head against that for awhile and getting nowhere, I figured, "why not just create the whole thing as a top-level html element, and let the browser just take it away from there?" The basic strategy is this: create a style DOM Element dynamically, add text content to it representing the actual stylesheet, and then pop it into the HTML DOM. With a few caveats, it works like a charm. The browser parses the text as CSS, and links in into the live cascade.

I mentioned caveats.. well, of course there are the obligatory cross-browser compatibility issues to be aware of:

  • In Internet Explorer, you can't just append a Text Node to a Style element, you have to use some trickery to get it to work.
  • KHTML & Safari do not honor style elements that are not contained in the HEAD element of the document.
  • While IE and Mozilla always create a HEAD element for you if one doesn't exist, Opera and KHTML do not.
  • While Opera will honor a dynamically created HEAD element, KHTML will not. (That's a bug in KHTML as far as I'm concerned as it violates the DHTML principle that I've been talking about.)

All in all, they're nothing to worry about and do not stand in the way of the fundamental technique. I've created a demo page showing this code in action. As a nice side effect, it works as quick way of playing around with CSS properties and how they effect the styling of elements.

Here is the source snippet implementing the technique I've described here:

var style = document.createElement('style') style.setAttribute('type', 'text/css')

var cssText = $('cssText').value if (style.styleSheet) { //IE only style.styleSheet.cssText = cssText } else { //for some reason this fails in IE. var text = document.createTextNode(cssText) style.appendChild(text) }