Spritebaker has been doing the rounds a fair bit in web development circles over the past few weeks, for the simple reason that it’s a great idea, done well. The best desciption comes from the site itself:
It parses your css and returns a copy with all external media “baked” right into it as Base64 encoded datasets. The number of time consuming http-requests on your website is decreased significantly, resulting in a massive speed-boost.
While baking images into your CSS to lower HTTP requests reduces the rendering time of your site overall, the downside is that CSS files block the initial rendering of your site. While an unbaked site may render and be built up as external images load, a baked site will not render until both the CSS and baked images have loaded. This has the strange effect of making it seem like the page is actually taking longer to load.
I’ve thrown together a quick example of an unbaked page and its baked equivalent. In this example, the unbaked page begins rendering earlier than its baked counterpart but finishes later.
In an attempt to kick off rendering earlier, I tried what I’ve named a half-baked idea: splitting the standard CSS into one file and the baked images into another. My hope was that browsers would render the standard CSS while the other was still loading. As you can see on the example page, this failed.
With CSS only solutions delaying rendering of the page, it’s time to pull JavaScript out of our toolbox. Anyone whose read my article on delaying loading of print CSS will find the solution eerily familiar. The CSS files are still split into the standard files and the file containing the baked-in images, the one with the baked in images is wrapped in <noscript> tags in the HTML head.
<link rel="stylesheet" href="halfbaked-1.css" type="text/css" />
<noscript><link rel="stylesheet" href="jshalfbaked-2.css" type="text/css" /></noscript>
This prevents the second/baked stylesheet from loading during the initial rendering of the page. Without this file blocking rendering, this version of the example begins rendering as quickly as the first, unbaked, example.
The second/baked stylesheet needs to be added using the JavaScript below:
<script type="text/javascript">
window.onload = function(){
var cssNode = document.createElement('link');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.href = 'jshalfbaked-2.css';
cssNode.media = 'all';
document.getElementsByTagName("head")[0].appendChild(cssNode);
}
</script>
Using the method above for baking images into your CSS will give you the best of both worlds, your page will render quickly with a basic structure before a single HTTP request is used to load all of your images.
I used Web Page Test to measure the first-run load times using IE9 Beta, averaged over 10 tests. On the test pages, with only a few images, the advantage of a baked stylesheet isn’t apparent, on a site with more images it would quickly become so.
Version | Starts Render | Fully Loaded |
---|---|---|
Unbaked | 0.490s | 1.652s |
Baked | 1.862s | 1.836s |
Half baked | 2.138s | 2.114s |
JS baked | 0.499s | 1.993s |
As the Spritebaker info page says, IE versions prior to IE8 don’t understand data-URIs, so you’ll need to use a generous sprinkling of conditional comments to load images the old fashioned way in these browsers.
The examples above were tested on IE9 Beta, Chrome 6.0, Safari 5.0, Opera 10.10 and Firefox 3.6.9. Individual results may vary.
We’d love to hear of your experiences with baking stylesheets, or other techniques you use to speed up apparent rendering of your page, especially if it slows the total load/rendering time.
Comments
One response to “A half-baked (CSS) idea”
On a production site I’d use a cross-browser event listener for the final code block. I’ve used window.onload in the example above to keep things brief.