Showing posts with label css. Show all posts
Showing posts with label css. Show all posts

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?

Sunday, February 03, 2008

Minify Rails Javascript and CSS with YUI Compressor

Here is a simple rake task to minify your javascript and css in a rails application using the YUI Compressor. You will need to have java set up correctly on the system and have the YUI Compressor jar in the lib directory of your Rails application to run this code.



You could drop this in lib/tasks/minify.rake and run it when deploying to production. If deploying with Capistrano, you might put it in the :after_update_code task:



This technique should work fine with Rails asset caching (explained here by the guys at maintainable software). Couple that with gzip compression by your web server and you should get dramatically reduced download times for your javascript and CSS.

A couple of caveats --

First, some javascript may not minify without problems. For example read this post by Andrew Dupont which talks about compressing prototype. I didn't seem to have a problem using the YUI Compressor with prototype but I haven't thoroughly tested it yet.

Second, I would prefer if the code above placed the minified version in different output directories. (Primarily so you don't accidentally check your minified versions into your SCM system.) Originally I did this putting the minified code in public/javascriptx and public/stylesheetx, respectively. Then I looked into how to get rails to easily look in different directories for javascript and css files. I found the JAVASCRIPTS_DIR and STYLESHEETS_DIR constants and thought I was all set -- then I then ran into the problem that changing:



in an initializer didn't really work as expected. Due to what looks to me like a bug in Rails 2.0 the files are still fetched from the original locations in spite of changing these constants - so I decided to stop messing with it and watch the Super Bowl.

If you don't like messing with Java to do something like this and are only concerned with compressing javascript then I would recommend reading this article by the guys at maintainable software. They give an example of using jsmin.rb for javascript minification.