Data URIs make CSS sprites obsolete

I was sitting in a talk given by Facebook’s Jason Sobel at Velocity this year, when I was a bit surprised by an impassioned plea that he made at the tail end of the talk. To paraphrase, Jason said that CSS sprites require too much work for average web developers and that we should be pressuring the browser vendors to make this process easier. I was perplexed for a moment. First, I don’t think CSS sprites are all that complicated anymore, especially with tools like the online CSS Sprite Generator readily available. Second, CSS sprites only really have to be used for older browsers (looking at you, IE6 and IE7), as this problem is easily solved in other browsers by using data URIs. Jason’s epilogue made it even clearer to me that people still don’t understand the true power of data URIs and how they’ll transform web development going forward.

The purpose of CSS sprites

Before getting into how data URIs make CSS sprites obsolete, it helps to examine the problem that CSS sprites solved. The problem is that HTTP requests are a major performance bottleneck for web pages. The more requests you have, the longer it takes your page to load and the slower it is, so every little image you load onto a page fights against you in your quest for page speed.

CSS sprites solved this problem by combining multiple images into a single file, thus collapsing all of those extra HTTP requests into a single request and vastly speeding up the page. The downside is the overhead of planning for and using CSS sprite images, as the images need to be arranged in a certain order, perhaps with some extra blank space in between. That typically meant that someone had to write down the location of each individual image within the larger sprite image so that CSS could be used to position the image in the correct spot to show the correct image. For more information see Dave Shea’s article, CSS Sprites: Image Slicing’s Kiss of Death.

Basic CSS sprite usage

The pattern I use the most for CSS sprites is relatively straightforward and has the goal of ensuring CSS maintainability. There is a single class that contains a reference to the CSS sprite image and several other classes that simply move the background into different positions. For example:

.mysprite {
    background: url(mysprite.png) no-repeat;
}

.icon1 {
    background-position: 16px 16px;
}

.icon2 {
    background-position: 32px 16px;
}

Suppose you were making a progressively enhanced toolbar with this CSS, so there’s an unordered list with each item representing a button. Imagine that these are styled such that the text is hidden and each list item link simply becomes an image to click on. The HTML for such an example would look like this:

<ul class="toolbar">
    <li class="mysprite icon1"><a href="/save">Save</a></li>
    <li class="mysprite icon2"><a href="/open">Open</a></li>
</ul>

For any element that wants to use the master sprite image, the class of mysprite is applied. Then, a second class is applied to move the sprite into position. Note that there are alternate techniques that have the same result; the reason I like this one is because the URL is only ever referenced once (good for maintainability) and it’s able to be used anywhere on the page.

In terms of performance, the benefit to this technique grows as the number of images in the same file increases. You can end up with one very large image file, but that is still better than making multiple requests for a bunch of small images. You make a single request for the sprite image and after that point it’s cached by the browser, so you no longer have to worry about making a request. Note also that if the CSS is in an external file, it too will be cached.

Using data URIs instead

A little while back, I wrote about what data URIs are and how to use them. In short, data URIs allow you to embed images (and other files) directly into HTML and CSS. Since all of the data is represented locally, there is no extra HTTP request required to access the information.

Remember that the original problem that CSS sprites solved was having too many HTTP requests for images. Data URIs also solve that problem, and solve it in a much more manageable way. Instead of using a single extra request to get the large sprite image, you use zero extra requests to get the images to use. What’s more, there’s no need to combine all of the images – you can keep the images separate and use them as normal background images. The CSS doesn’t really change all that much (full data URIs omitted for space):

.mysprite {
    /* no longer needed */
}

.icon1 {
    background: url(data:image/png;base64,<data>) no-repeat;
}

.icon2 {
    background: url(data:image/png;base64,<data>) no-repeat;
}

Here, the mysprite class actually becomes unnecessary as the image data now resides in each icon class. The HTML doesn’t need to change (though you can remove mysprite if you so desire) in order to create the same effect.

At first glance, this may seem strange to you. The first question that people tend to ask when I describe this approach is that I’m dramatically increasing the size of the CSS by embedding the image data, doesn’t that hurt performance? The answer is no, so long as the CSS lives in an external file and is gzipped and cacheable by the browser. Base64 encoding, which is how the image data is represented, compresses remarkably well when gzipped, ultimately resulting in roughly the same amount of bytes being transferred over the write as compared to downloading the original image file. The added benefit is that you’re making zero extra calls for all of the images. And since these are in your external CSS files, they are also cached, so the next time the user comes to the page the CSS file is pulled from cache with the images already inside.

Automatic transformation

Because I believe in this technique so much, I wrote a tool called CSSEmbed (read the announcement) that makes it trivial to update your image-based CSS into data URI-based CSS. This frees you up to write CSS code like this:

.icon1 {
    background: url(icon1.png) no-repeat;
}

.icon2 {
    background: url(icon2.png) no-repeat;
}

So you write CSS in the old-fashioned, non-performant way with individual images, run it through the tool, and you automatically get a CSS file with data URIs embedded. That’s it, no more arranging images into a single file or keeping track of coordinates.

Note: CSSEmbed also supports an MHTML mode to make IE6 and IE7 compatible stylesheets that use internal images similar to data URIs.

Conclusion

CSS sprites were a solution to the problem of multiple HTTP requests to download multiple images. Data URIs allow you to embed images directly into your CSS files, solving the same problem in a much more elegant and maintainable way. Although we still need CSS sprites for older versions of Internet Explorer, that shouldn’t prevent you from investigating the use of data URIs as a better alternative to CSS sprites. Once IE6 and IE7 go away for good (some day), there really shouldn’t be the need to use CSS sprites so heavily if at all.

Comments

  1. Arnout

    But when you add more bytes to the size of your CSS it will take longer for the browser to start displaying content. So if you increase the size of your CSS allot the perceived performance would suffer from it and not benefit from it?

  2. Yoav Weiss

    While the upsides of your solution are obvious (much more manageable then sprites, each image can be compressed on it's own format and in an optimized manner), the major downside of embedding images into the CSS is that CSS blocks rendering. That means that your site (at least the first time it is loaded, and on most browsers) sits blank while the images are downloaded. An AJAX based approach, that downloads a single JSON/XML file that contains all the images and adds the images as the site renders, is much better in that aspect, and enjoys most of the benefits of your approach.

  3. Kamil Trebunia

    Another great possible use case for constant values in CSS, unfortunately CSS WG still doesn't think they would be valuable enough... It would be much more convenient to define const with image ("const ICON_RED_ARROW = url(data:...") data and then use it however we want instead of writing convoluted CSS or bloated HTML (classitis).

  4. CarlB

    Using Data URIs only solves one of the two main facets of Web performance optimization, reducing the number of objects needed to present a page successfully. Encoding images into Base64 will however make one problem even worse, you will need to send more data for the first download.

    Without tools, looking at the web designer types and mentioning DataURIs or Base64, I expect nothing but blank stares just like when CSS Sprites became a trend to solve an issue. Command line tools like what you built are great for those really into this kind of stuff, but the big vendors need to bake in support for these efforts before adoption can be more widespread.

    Testing of a couple examples I tried, resulted in an increase of greater than 35% in data size over the individual files. The saving grace, which would need further testing is that the Base64 is all text which lends itself to compression algorithms a little better. An unscientific test of zipping the b64 version of the file got the zipped file to be only 1k larger than the original image.

    Nicholas, Thanks for making the tool and bringing this option to the table. Having more ways to solve the challenges we face is always better.

    CarlB

  5. pragmar

    While such a system would not affect overall performance, it might affect the perceived performance of the first site page loaded since the css is typically place in the html head. Not such a problem for repeat users, with the css in cache - but first impressions and all. I think it would probably be wise to separate the image data into a second css stylesheet and add it to the tail end of the document in order to defer the load until after the html document is in the browser. But yes, a far superior solution than css sprites..

  6. Andrew Ingram

    Surely you'd need to make sure any data urls come at the end of your css file, otherwise you'll end up with the page being unable to render whilst the data-url part of the CSS is downloading.

  7. Matt C.

    Hey Nicholas, great article. I had two questions:

    #1: By base 64 encoding the images you embed in the CSS, don't we increase the total image data being pushed down the pipe by a third? (assuming we were gzipping them already)

    #2: The extra work of base 64 decoding the images to display means the browser is doing extra work for every image in your CSS. Does the browser do this work every time the page is displayed, or does it do this only once when it's populating it's CSS cache? Do you what kind of a performance hit this might be?

    -Matt

  8. John Wister

    Embedded images can make sense for some things, but are not a general solution. CSS will typically be shared among many pages on a site. The bigger it is, the longer it takes that first page to show up. Having images for a page be in their own file at least means you can compartmentalize them.

  9. Aeron

    Data URI's a great, but I think the bug problem is change a single line in your CSS and the user has to re-download all images (unless I'm mistaken).

  10. Aeron

    bug = big

  11. Andris Reinman

    To be correct - you need to use negative values for the sprite positions. eg: "background-position: -16px -16px;" not "16px 16px;" - this value indicates the shift of the left-top corner of the sprite image.

  12. Aeron

    Also image sizes are 150% once encoded as base64 vs an optimized binary such as png8.

  13. Ryan Grove

    I agree that data URIs make sprites almost obsolete, but I strongly disagree with your assertion that sprites are no longer complicated.

    While putting together a simple sprite for a simple website is quick and painless thanks to tools like the CSS Sprite Generator, the difficulty increases significantly when you start needing more complex sprites (e.g., sprites that contain tiled background elements) or when you need to manage multiple localized variants (e.g., one sprite with a US logo, one with a UK logo, one with a TW logo, etc.).

    When I was at Yahoo! Search, part of my job was managing our sprites (mostly because nobody else wanted to). The main US sprite served as the global master, but we had 40+ international regions that each had their own logo treatments and various other minor differences. Additionally, many of these international regions had alternate skins, so they required two or more sprite variants. As a result, any sprite change to the global master also had to trickle down to all the other localized sprites, and each sprite had to be re-exported to PNG, optimized, and pushed to the CDN.

    I managed this by organizing all the sprites into a single Photoshop file with a layer for each sprite element and a layer comp for each international region or skin variant. Common CSS was shared between all regions, with minor overrides applied by each region as necessary. Even so, there was a fair amount of overhead involved in any sprite change simply due to the sheer number of sprites that had to be updated, exported, optimized, and pushed. I also manually optimized the color palette for each generated sprite to ensure the lowest possible file size. Technically, much of this process could have been automated, but keeping it manual allowed us to squeeze out every last unnecessary byte and ensure that we weren't compromising on image quality while doing so.

    We eventually did reduce a lot of the pain by moving some of our more complex and frequently-skinned sprite elements (mostly tiled gradients) into either data URIs or pure CSS, but it was still pretty complicated.

  14. Marcel Duran

    Hi Nicholas,

    What about having both sprite + data uri combined? AFAIK several images are bigger than a single one combining all these files (sprite) because of the image headers, etc.

    Regarding GZip compression, once I analyzed 2768 optimized png favicons and in average files were:
    497bytes (png file)
    686bytes (base64) +38% bigger
    588bytes (gzipped w/ -9 compression [apache default DeflateMemLevel]) +18% bigger

  15. Joseph Scott

    While correct that the amount of data going over the wire (compressed) is likely comparable, base64 increases size of the data roughly 1.37 times. From what I've read, browsers cache the uncompressed versions of CSS, resulting in increased memory usage. This is an area that could use more research.

    I like the data URI concept and expect that browser vendors will continue to improve support and performance for them.

  16. Thierry Koblentz

    Hi Nicholas,

    The problem I see with this approach is that browsers end up getting all the images they find in the styles sheet instead of fetching only the ones needed to style elements for a given document.

    Sprites in rules like these:


    .icon1 {background: url(icon1.png) no-repeat;}
    .icon2 {background: url(icon2.png) no-repeat;}
    .icon3 {background: url(icon3.png) no-repeat;}
    .icon4 {background: url(icon4.png) no-repeat;}

    are ignored as long as no element in the page matches these classes, but with the data uri approach things are very different, the browser gets all the assets as soon as it downloads the styles sheet - even if the document as no use for these images.

  17. Nicholas C. Zakas

    A few people mentioned this, so let me try to clarify: When you convert an image to a data URI, you increase the size of the data by around 33%. When gzipped, that actual difference in wire weight in negligible. This is because base64 encoding uses a limited number of characters and is therefore easier for gzip to compress. So the wire weight shouldn't be a big concern.

    You also shouldn't be concerned about cachability if these are in your external style sheets. The style sheets will be cached and then so will the images in data URI format.

    The size of the mobile cache is a concern, of course, since these tend to be quite small and since they cache the uncompressed version of the files, you are increasing file size.

    @Marcel - That's interesting, when I had done tests before the difference wasn't that large. I'll have to go back and do some more. I wonder if the size of the image has something to do with it as well, since you always need at least 22 bytes for the data URI prefix.

    @Matt - I think I already answered your first question above. For the second question, I'm not sure. Base64 decoding is a pretty fast process, so I wouldn't worry too much about its performance overhead.

    @Arnout - Anytime you increase the size of a resource, you run the risk of slowing things down. What you're saving in this case is the extra HTTP request(s) that would also slow down page rendering. It's a tradeoff.

  18. Alex

    This is really interesting. We just paste the base 64 text in place of the tag instead of having an external jpg/png file? That's really neat!

    My own concern with this is that it adversely affects the edit-ability of the image. You'd best be sure that's the icon you want right?

    What would be *really* fantastic would be a server side include that output the PNG saved icon as base64. (if that made any sense at all :))

  19. WeaselSpleen

    There's another approach to this problem: don't use images.

    Does this image absolutely need to be here for viewers to understand my content? If not, then leave it out.

  20. cancel bubble

    What about domain sharding? Is there a point where static assets/domain sharding become more efficient?

  21. Thierry Koblentz

    And what about legibility?
    Not being able to rely on file names may create problems when it comes to differentiate assets, versions, etc..

  22. Riyad

    Any idea if any of the browsers cache any of the decoded base64 image data or is it re-decoding that data on every page reload?

    Seems like 6 of 1, half-dozen of the other.... I'm imagining a graphics-heavy page on a mobile device pegging the CPU for twice as long to reflow the page as well as base64 decode all the graphical assets now instead of parallelizing some of that stuff.

    But I'm not a browser expert, just not seeing an "Absolute clear" win here... it's definitely cool though.

  23. Nicholas C. Zakas

    @WeaselSpleen - A very good point! And a point made even more compelling with the use of CSS gradients (a very common design element).

    @Thierry - Yes, the browser is always getting the data instead of waiting to see what's necessary, that may be a downside depending on how your CSS is organized. Perhaps doing it this way would end up changing your normal patterns? As for the second point about legibility, that's exactly why I created CSSEmbed. I think that these types of CSS files should be created at build time, so you just edit the CSS in a way that makes sense to you.

    @Alex - See the second point of my response to Thierry above, you're better off automatically creating the data URIs at build time than you are trying to manipulate them by hand.

    @cancel_bubble - you still pay the price of an HTTP request (or two or three).

    @Riyad - I'd suspect that the images are re-decoded with each page load. But as I said in another response, base64 decoding is a fairly inexpensive operation, especially when compared to decoding image formats in general.

  24. Morgan Roderick

    With regards to image file sizes, please bear in mind that different compression methods doesn't really matter much in the runtime environment of the browser, it will only reduce the bandwidth and storage consumption. A 200 pixel png will take up the same amount of memory in the browser, no matter how it's compressed (or even if it is blank). If you want to see for yourself, just create a 100MP blank png and load it up in a browser ... you should see memory consumption shoot up, even though the file compresses REALLY well :-)

    There are certainly limitations and pitfalls to be aware of when embedding images in stylesheets, but it can reduce the amount of requests sent to the server, which improves perceived performance, especially on slower / lossy networks. Your tool of choice should help you avoid some of the pitfalls, like embedding the same image more than once, etc.

    For those worried about caching, don't be ... if you know how to control resource caching and have a good cache invalidation scheme, you won't run into problems. If you don't, then you should really be fixing that first... really, go fix that now.

    There are several good resources out there that allows you to embed images into your stylesheets, I've contributed to one of them: http://github.com/cjohansen...

    If you're on Rails, Jammit looks very interesting: http://documentcloud.github...

    With regards to MHTML for IE7--, please be aware that for it to work, the protocol, hostname and port needs to be in the stylesheet for it to work ... which sets some serious limitations for it's usage ... but you can always do fallback to non-embedded resources for those browsers :-)

    @CarlB: Big tool vendors are rarely at the forefront of innovation on the web, they cater to a different audience, who are happy with "well enough". Companies that are really pushing the envelope for performance on the web, relies on experienced and curious PEOPLE to come up with ways to improve their services, and don't rely on non-cli tools to squeeze every bit of performance out of their systems.

  25. Alex

    Nice article, Nicholas!

    "What would be *really* fantastic would be a server side include that output the PNG saved icon as base64. (if that made any sense at all :))"

    There is a tool, which reuse the CssEmbed code created by Nicholas and can be easily integrated in any java web application with a simple filter: http://code.google.com/p/wr...

    Currently it does support a base64 image encoding in css (not by default). More details can be found here: http://code.google.com/p/wr...

    Unfortunately, data uri adoption have to suffer as long as IE6 & IE7 have a big market share.

    Alex

  26. mario

    I've only ever used data URLs for very simple webpages, where I just embedded the single logo into the sole html file. But this approach is rather ingenious. Only I'd split up my CSS into a regular stylesheet and a secondary with embedded images.

    Base64 expands 3 bytes into exactly 4, and the deflate algorithm eats that almost completely away again. However, didn't IE6 have some bug where it sometimes wouldn't read text/css with content-encoding?

  27. Steve Souders

    This problem is certainly not "easily solved" by using data: URIs and MHTML. I think you're working at a different level than most other web devs. ;-)

  28. Leto

    I think data URIs are quite exciting and certainly have a place.

    Another point worth considering in this approach, which I haven't seen mentioned yet, is that of user-agents with images disabled. Generally this is done on slow connections so the client is fetching only the content and the styling. By combining the style and images you are taking away some of the user's control.

  29. tofui

    IE7 only supports 256 chars in the base 64. IE6 has no support. I wanted to use it in my framework, but it just wasnt practical at the end of the day. It mucks up the DOM and caused chromium to lock up randomly.

    I spent weeks in research and I think it's gonna be a little while before this is practical.

  30. Dmitri F.

    Here's an idea. Why not have one global stylesheet for all styling info, and then have another 'preloader' css file that contains the data URI's?

  31. Tice

    Interesting idea. I use to use Data URIs for my Mail signatures in Apple Mail:
    http://blog.tice.de/beitrag... (german)

    Sample: http://blog.tice.de/a_datei...

  32. Thany

    You're making a big mistake by obsoleting sprites in favour of data URI's.

    First of all, data-URI's make the downloaded data bigger by about 30%, due to base64 encoding.
    Secondly, You're going back to putting each icon in its own "file", while putting all of them in one file produces a smaller file.
    Third, the CSS becomes a bigger download, which delays the first rule being applied by the time it takes to download all that extra data.

    Basically what you're doing is removing one extra HTTP roundtrip, while having the visitor download 30% more data. Not a great idea, iyam.

  33. Thany

    Also, the user cannot choose NOT to download images, which is useful on a UMTS connection, for example.

  34. NICCAI

    Until data URIs are incorporated into IDEs, a common compressor, or a pre-processor like Less CSS, I'm not sure they're really practical. Once you throw in the fact that first load performance will be hit, and mobile caching will rear its ugly head, I don't think you come out on the positive. Realistically, I don't see real incorporation happening fast enough. It's more likely to be trumped by CSS gradients, canvas, and overall improved browser support/standards.

    One thing that I think pushes sprites way out ahead is the inherent object orientation that comes from setting them up. Naturally, their use tends to create a reusable class structure. This concept alone benefits the new developer more than anything. That said, combining sprites and data URIs could ultimately be interesting.

    Lastly, I always wondered what was possible with Data URIs and client-side storage. Haven't quite wrapped my head around the idea, but food for thought.

  35. Kevin

    @Alex: if you are developing with a scripting language (PHP, JSP, &c.), you can actually build your CSS with scripts in it. Along the lines of:

    .icon1 {
    background: url(data:image/png;base64,<?php include('scriptobase64encodefile.php?icon1.png'); ?>) no-repeat;
    }

    Or, since the CSS file would be a script, just put the function in the file and have an echo instead of an include.

  36. JT

    What kind of crazy connection must your average user have that the extra connection overhead incurred by including one CSS sprite is greater than the extra 50% you're adding on to your data size by using data URIs? Especially of course if you want to make any tiny modification to the CSS file - the browser can't cache any of the image data.
    Really this isn't a terribly worthwhile solution unless you have only a few, very small images on your site. CSS files block page loading, Images don't. It's really not worth the bother except possibly in a few very small cases

  37. Dave Gregory

    We started using URI-zing our CSS about a year and 1/2 ago. I was quite happy since I didn't have to maintain sprites.

    I got a scare lately when I looked on Pingom Tools and looked at the size of these files. They were massive! Then I sparked up the Net tool and Yslow to double check and found that the files were slightly larger size than if they were un-URIzed and un-minified.

    That means minifying and g-zipping URI'zed stylehsheets were only about 10 percent more than the minified version. So yes, Data URI is very g-zip friendly. Yay!

    Now, I must confess.. our main css file is 100k (raw). And there are alot of image references. (no sprites at all). But after URI-zing, it's a whopping 246 kb! gzip that: 129.6 kb. Now knowing that, I'll spend my time reducing the overall filesize of my CSS in general, and not worry about sprite-ing my images.

    Thanks for the nice writeup NZ.

  38. Andrew Maier

    To those that are complaining about the perils of embedding base64 icons into stylesheets, I would say that instead of linking out to one sprite file, we should instead link out to an individual stylesheet that contains all of our sprite rules.

    IE:

    style.css:
    h1 {..}
    h2 {..}
    icon 1 {dimensions, file1}
    icon 2 {dimensions, file 2}

    becomes:

    style.css:
    h1{..}
    h2{..}
    icon 1, icon 2 {dimensions}

    faux-sprite.css:
    icon 1{ base64 }
    icon 2 { base64 }

  39. ldexterldesign

    Next level sh*t [here].

    Roll on SVG I say.

    Good detective work Nicholas.

  40. Alexander Moya

    I like the suggestion of @Marcel_ Duran, how about combining both approaches, using css sprites and embedding the sprite in the CSS, only one image to encode, gzip and download, and you still have 0 http requests.

    However it does sound like overkill for most web developer's necessities and more work than just optimizing and offloading images, I'll have to test all these options to see witch one suits me best with both time & performance.

  41. Mark McDonnell

    Obviously if you want to use an image that is over 32kb (to support IE8) then you're screwed :-)

  42. Alex

    @Mark McDonnell "Obviously if you want to use an image that is over 32kb (to support IE8) then you’re screwed "

    This is not a problem, because you can check the size of the image on the server-side before transforming the image url into the Data URI. This is exactly how wro4j works (http://code.google.com/p/wr... . But, as I mentioned already... if you want to support IE6 & IE7, you better forget about Data URI support.

    @JT "What kind of crazy connection must your average user have that the extra connection overhead incurred by including one CSS sprite is greater than the extra 50% you’re adding on to your data size by using data URIs?"

    That is funny, how people who do not like the Data URI approach, jungles with the numbers :D.. First of all it started with 30%, then it reached 50%. Spectacular grow!!! :D
    Actually, it is less than 30% (size of the image, not of the entire css). Also, do not forget that the css can be served gzipped, thus reducing the overhead down to 10%. The other thing to consider, is that once css is cached .. no extra request is required.

    I'm not in favor using blindly data URI for everything. Actually, I do believe that combining Data URI with sprites is a best approach. But we have to wait until IE 6 & IE7 will die (at least 2 years)

  43. Andy Davies

    It's a trade off in which you're swapping the overhead of the http request for the sprite image for a large css file.

    Generally we want the css to be downloaded as soon as possible so the browser can start to render the page, the images can be downloaded and inserted later and to a certain extent data URIs work against this.

    Different devices have different caching rules and the likelihood is that as files get larger they are less likely to get cached.

    That said there are some good use cases for data URIs but right now it's about careful choices not broad brush recommendations

  44. Constantine

    Article sounds sweet and convicing, but is it realy so ?

    You fail to show how base64 data url in css would remove the need for sprites. It looks like for most tasks that we use sprites for - you will either still need sprites in the future, or will not need images at all.

    Task #1 - decorated box, sliding doors
    Solution: css3 border-image - border image is a single sprite, rather than a collection of images.

    Task #2 - rounded corners, gradients, text/box shadows
    Solution: no need to apply images anymore. use css3 properties.

    Task #3 - FIR, or other image replacement
    Solution: use web-fonts

    Task #4 - rich buttons and icons (hover/active/focus/click)
    Solution: use sprite, because you can hold consistent graphics in one file.

    Task #5 - png sprite-based animation
    Solution: try to guess ;)

    Task #6 - list markers and anchor icons
    Solution: individual images would be more intuitive and usable, say a[href*="facebook.com"] { bg-img: url("facebook.png"); }

    Task #7 - reduce total requests
    Solution_1: one mega sprite, youtube style
    .icon1 { background-position: ); } // output: -32px -128px
    Solution_2: one mega css with server-side encoded images.
    .icon1 { background: url(data:image/png;base64,) no-repeat; } // output: base64-encoded image
    Solution_3: compile css using some tool (one mega css with encoded images, just like in step 2)
    .icon1 { background: url('icon1.png'); ?>) no-repeat; } // output: base64-encoded image

    So i dont see any practical benefits, except for the two last ones. And only if they are complied.

    ps: Real problem with sprites is a lack of proper tools. Look at 3D texturing. Nobody writes coordinates for UV / UVW mapping by hand. Look at desktop publishing. Nobody makes layouts by hand.

  45. Khang Tran

    first of all, thanks for the fascinating article. i love it when people come up with creative new solutions!

    generally, i think this is a neat idea. but what about when you have multiple CSS files and they refer to some of the same images? seems like you'd be suffering redundant data transfer then. of course, life is all good if you only have one CSS file. unfortunately, our site is too large/complex to go that route.

  46. Johan

    Is it possible to load images using data URIs and NOT have them cached?

    For example an image editing application that loads a lot thumbnails. The thumbnails change as edits are made and thus i need to ensure the browser does not cache them. With the image src attribute it is easy to jsut append a random numeric query string src="image.png?123" but that does not appear possible with the data URI.

    Thanks

  47. Johan

    Doh - answer to my own question - the images would not be cached since the data would obviously be different if the image was changed.

  48. Alex

    "but what about when you have multiple CSS files and they refer to some of the same images? seems like you’d be suffering redundant data transfer then."

    Wrong! The approach is wrong. Since you have the same image, why would you have different classes referencing the same resource? This is the most common mistake unexperienced designers would do. CSS can be written keeping in mind the DRY (Don't Repeat Yourself) principle.

    "life is all good if you only have one CSS file. unfortunately, our site is too large/complex to go that route."

    Khang, what stops you to merge all css into a single file?

  49. Matt

    I have not done significant testing however I have found this works in IE7, IE8 and Firefox:

    background-image : url("data:image/png;base64,") !important;
    background-image : url("images/some_image.png");

    IE7 falls back to the less important rule with a valid url. Other browsers including IE8 will use the data uri and will not make any other http requests.

  50. Hiren Khambhayta

    Nice article, I have used the same technique of css sprites and boosted my website speed by about 200%. Before it was loading in 7 seconds but now it loads in just 3 seconds

  51. Diego

    So, does this have any issues with cacheing images? Seems like if it is all embedded wouldn't that mean downloading the same images over and over? Did I miss something? I found a cool tool in php for generating css sprites automatically (www.spritemeister.com), because I want to load my source graphics once all at the front of the experience.

Understanding JavaScript Promises E-book Cover

Demystify JavaScript promises with the e-book that explains not just concepts, but also real-world uses of promises.

Download the Free E-book!

The community edition of Understanding JavaScript Promises is a free download that arrives in minutes.