Thursday, September 11, 2008

Javascript - Change your Stylesheet not your Style

Most Javascript code that interacts with the CSS of a document does it by interacting with the individual elements on the page. For example, a Prototype script to change the background color of a specific element on the page might look like this:

While this works well, in some cases you may be wanting to apply the same style to 100s of elements. Recently I ran into this problem when coding a Prototype version of the Flickr Photo Demo. (Hey, sorry this might be foobar on IE, I just haven't had time to take a look at cross browser issues for IE on this demo.) The demo has a slider in the upper right corner that changes the size of the displayed images. My first cut at the demo can be found here. On a fast modern computer, this works pretty well, however, given the loops that are needed to apply new pixel sizes to the images and the divs that contain them, the slider can be jumpy on an average system. This demo only displays 20 images at a time, so it is easy to see how this problem could get very noticeable when more elements are involved. The key code applying the styling changes looks like this:

This had me thinking of ways to get the slider to work more smoothly. The first solution I thought of was to use different classes for the containing "#content div" which would result in the needed style changes to the contained div and img tags. The new code looked like this:

Look mom! No loops. The new code is fast and the slider operates very smoothly. As the astute reader may have figured out, however, this required me to have a very large stylesheet for this page. The reason is that the class for the "#content div" is being changed to sizeXXXpx where XXX can be any number from 50 to 250. How big is the stylesheet? Well picture 402 lines of this kind of stuff:

This version of the Flickr Photo Demo can be found here.

Without my emacs fu this file would have been a pain to create - but no matter what its still ugly. This got me thinking about another solution - surely Javascript will let you modify the rules in the stylesheet dynamically, right? After a little googling I found out it is possible but it doesn't seem like it is a very popular technique. I quickly hacked together the following general function for modifying the rules of a stylesheet:

On thing to keep in mind about this code is that it stops searching for the rule to change once it finds the first matching selector that it runs into. This is of course going to be a problem if you have the same selector defining css rules at multiple places in your stylesheets. You may need to adjust the above function if you don't have control over how your stylesheets have been defined.

This allowed me to change my slider code to the following:

Wow, it works, no loops, fast, and my stylesheet is back to being slim and sexy. This version of the Flickr Photo Demo can be found here.

This got me to wondering how cross browser this technique would be. To test this out I made this page which implements the most bare bones demonstration of this technique and tried it out on a few different browsers. It worked fine on all the browsers I tried it on. I wanted to do one last test that targets more browsers so I made this page and submitted it to Browsershots. (Browsershots is cool, you submit it a page and tell which browsers to take screenshots for - then sit back and wait for the results to roll in). This final test put the stylesheet modifying code in the window.onload event and changed the background from red to green. This would make the browser shot screenshots show in green on a browser that handles the technique and show in red on a browser that trips up on it. It worked in every browser I asked Browsershots to test it on.

So there you have it, you apparently can dynamically change the rules in stylesheets rather than changing the styles on individual DOM elements. So now I'm wondering, why is the usage of this technique not more prevalent?