Shared publicly  - 
I was asked about base64 vs a sprite image in CSS...

Both techniques are better than multiple images as they reduce the number of http requests. A sprite image requires 1 additional request, base64 doesn't.

Some point out that base64 increases the file size of the image by 25% (slightly more if padding is needed). Base64 represents 6 bits of data as a character. Characters in utf8/ASCII are 8 bits, so that's where 25% comes from. However, gzip recovers a lot of that. I took a 411 byte image which base64'd to 548 bytes, but gzipped back to 469 bytes. In this case the increase is more like 10%, which is nothing to worry about at these sizes. Also, since gzip is BLACK MAGIC the increase may be less when it's in a css file.

With base64 the image data is in the css file, meaning it gets downloaded even if it isn't needed. Eg, if you're using media queries to optimise image usage for mobile, base64 doesn't help.

The browser has to download the full CSS file before it can render anything, having imagery in a separate request gets you progressive rendering, whereas with base64 the CSS and image data has to download before anything is displayed to the user.

WIth base64 you'll need to provide a url fallback for IE6/7 as they don't support base64 url, so experience there is particularly bad as they have to download all the image data twice & get hit by the separate http requests.

Aside from the delivery method, using base64 is the same as using separate image files. This means you can tile the image, which you can't do with a sprite yet. In the future we'll be able to use something like or (I much prefer the mozilla idea).

A sprite image is smaller than the sum of its parts as compression works across all the components of the sprite and you only have 1 set of PNG headers. A sprite image will be smaller than a set of base64 urls.

I'm an advocate of building sprite images manually, automated tools tend to create more images than needed and don't get the most out of compression. A major drawback of this is when working with others & version control. If 2 people are on feature branches and each add to the sprite, it won't merge. You don't get this problem with base64.

Personally, I use a sprite image except for images that need to tile. For tiling backgrounds that are only a few bytes I use base64 with a fallback url for IE6/7.

I strongly recommend running sprite images though then to get the most out of compression. And of course, use to get the positions and dimensions of the sprite components :)
vento chen's profile photoRafa Yepes's profile photoDingzhou Li's profile photoSebastian Cubillos's profile photo
Good point. However I'd think twice about using base64 for images over a few k
To be more specific, I rarely use base64 for anything over 1k
It sounds like that's only an issue in IE8, which supports base64 anyway. However, it means you'd need to serve your CSS with a different mime type for browsers that look like IE6/7. Guess the best way to do it would be to have 2 css files & use conditional comments to serve the one with mhtml bits to IE6/7. Bit messy though.
If you're targeting webkit mobile devices specifically, you can achieve some really interesting performance levels if you use a web service to return a base64 map of your images (via JSONP).

What I found was that if you have base64 in images inlined (when the page gets rendered), the devices end up chugging ultimately delaying your DOMContentLoaded -- if your JavaScript application bootstraps when DOMContentLoaded gets invoked (say for example, if you're using Backbone), you could end up with a site without any behaviours for a while! This is evident on sites with lots of images like eCommerce sites (when you want to provide your users with the capability to buy your items through their mobile devices). It requires a bit of horsepower from the mobile device to decode base64 encoded strings.

To get around pushing/delaying DOMContentLoaded, we blank out img src's and retrieve it through an async call then slot the strings in after the application bootstraps. So essentially you could have an Amazon type of store user interface with loading placeholders, then when the cross-domain-friendly (JSONP) async call comes back it'll slot in the images as base64. The overall effect is that the more images your mobile storefront has, the more performance gains you have.

A neat little hack project I wrote called Cid does this: One can argue that this approach is far too fragile as it passes image src's, but you gain statelessness (you don't have be logged into the online store to encode what images the user sees), reduce all image http requests to 1, and you can certainly leverage "cache" by utilizing local storage.

Yikes! That was a mouthful (that's what she said).
Jamie: I've been looking into that approach. There are some drawbacks, but the overall idea seems like the best of both worlds: a single, non-blocking request for every single image needed for the page, but without the hassle of updating or adding extra CSS work to position parts of sprites. More work needs to be done for ease of use (making it easier to exempt large images from the mix, so the core bits load faster instead of waiting for a bunch of huge images) but this really seems like the most efficient direction: well worth the extra file size in most cases.
Agreed -- there's a bit too much machinery that's going on and it needs a simple way (or a ton of documentation) of integrating it into existing sites.

In regards to the size of images for mobile devices, one could possibly try writing something like this: but for NodeJS, which would resize the images, create a hash map of base64 encoded strings of those images, and ship it to the device.

+ Reduced size of images without having to have different versions of it for different viewing experiences (mobile vs tablet vs desktop)
+ Reduced http requests due to JSONP and base64 encoded images

- Too much magic :/

Upcoming hack project? ;o)
Really good article Jake.
About "I'm an advocate of building sprite images manually" please try this [1] and share your thoughts, please :D

Add a comment...