Data URIs and Dynamic Stylesheets

This a quick follow-up to a post I wrote a few months ago about embedding data URIs in stylesheets and a potential performance hazard regarding the way non data URI images are positioned in the network waterfall.  What I found was that under certain circumstances the performance penalty was great enough to not only negate the benefits of using data URIs for images, but to actually increase the overall load time.

My solution was a hack: put the data URI images in a separate stylesheet and place the link to the stylesheet at the bottom of the page, after a script reference. This caused the browser to render the page after the main stylesheet (the one without the data URI images) and download the data URI stylesheet and other images in parallel. The result was a fast loading, progressively rendered page. But, in addition to producing invalid HTML, it went against the widely accepted best practice of keeping stylesheet references within the head.

Despite some great discussion in the comments, there didn’t seem to be a decent answer to the problem. I forgot about it for a couple of months and then the other day the very obvious and simple solution came to me.

A quick recap of the original obstacle

Version 1: dataURI images in main stylesheet

When you replace the background image references in your stylesheet with data URIs, the size of your stylesheet increases significantly as the image bits are moved from image files into the stylesheet. (After gzipping, the increase in stylesheet size equals the original size of the images.) The page weight is the same but the difference is that stylesheets block rendering and downloading of images referenced in stylesheets. This means the more data URI images you have in your stylesheet, the bigger your stylesheet, the longer it takes before the page is rendered, and the longer it takes before other non-data URI CSS images can be downloaded. For an example, see how page components 4 and 5 are blocked in the above image.

You might be wondering why we would have both data URI CSS images and regular CSS images. The reason is that IE8 only supports data URIs smaller than 32KB. So if you have an image 32KB+ you’ll need to serve it normally if you want your site to get along with IE8.

My previous hack/solution

Version 2: dataURI images in separate stylesheet in body
One way I found to get around the problem was to move the data URI images into their own stylesheet (yes, adding an additional HTTP request) and force the browser to load the stylesheet asynchronously by placing the data URI stylesheet link in the body, after an external script reference. As you can see in the waterfall, the data URI images and the regular images are now downloaded in parallel.

A better way

dataURI waterfall using scripted link element
Of course there’s a better way to achieve the same end.  All we need to do to get the parallel downloading we want is make the dataURI stylesheet load asynchronously, something we can easily do with Javascript.  Obviously the dataURI images will now be dependent on Javascript being enabled, so you’ll have to take that into consideration.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Title</title>
    <link href="style.css" rel="stylesheet" media="all" />
    <script>
        var datuURIs = document.createElement("link");
        document.head = document.head || document.getElementsByTagName('head')[0];
	datuURIs.href = "duri-images.css";
	datuURIs.rel = "stylesheet";
	document.head.appendChild(datuURIs);
    </script>
</head>

Whether the dynamically inserted stylesheet occurs before or after the main stylesheet does not seem to matter in most browsers, but it does in IE8. In IE8 the dynamic stylesheet will block if it comes before the regular stylesheet. So if you’re using this technique you’ll want to order the elements as I have above.

On the general subject of using embedded data URIs for images, is it worth fussing with all this stuff?  In most cases I think the answer is probably not (yet, at least), in part because you can achieve a similar performance result with an aggressive use of CSS sprites.  Although CSS sprites have their own overheard and drawbacks, overall I think they’re easier to work with, especially when you start having to worry about data URI workarounds for IE6 and IE7.

But there are certainly situations where data URIs might be a good fit.  Mobile applications and “HTML5 apps” aimed at non-IE browsers come to mind.  And if nothing else, they’re fun to play with.

Both comments and pings are currently closed.

Discussion

is thought that DATAURL much slower background-image over time rendering page

@banzalik
I think the stylesheet *parsing* takes slightly longer, because of the base64 encoding, but the actual *rendering*, from what I can tell, happens more quickly. See the following two examples from Chrome’s timeline tool. In the data URI example, the image rendering begins later but finishes very quickly.

Regular images:
https://cl.ly/e994e8eb969ff74166b8

Data URI images:
https://cl.ly/66cfb28f414c43868bdf

Very intresting article.