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.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




58 Comments
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?
Arnout on July 6th, 2010 at 9:36 am
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.
Yoav Weiss on July 6th, 2010 at 9:38 am
[...] post: Data URIs make CSS sprites obsolete | NCZOnline This entry was posted on Tuesday, July 6th, 2010 at 1:00 pm and is filed under Uncategorized. [...]
Data URIs make CSS sprites obsolete | NCZOnline | My Blog on July 6th, 2010 at 10:35 am
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).
Kamil Trebunia on July 6th, 2010 at 11:37 am
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
CarlB on July 6th, 2010 at 11:37 am
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..
pragmar on July 6th, 2010 at 12:03 pm
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.
Andrew Ingram on July 6th, 2010 at 12:08 pm
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
Matt C. on July 6th, 2010 at 12:27 pm
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.
John Wister on July 6th, 2010 at 12:49 pm
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).
Aeron on July 6th, 2010 at 12:57 pm
bug = big
Aeron on July 6th, 2010 at 12:57 pm
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.
Andris Reinman on July 6th, 2010 at 12:59 pm
Also image sizes are 150% once encoded as base64 vs an optimized binary such as png8.
Aeron on July 6th, 2010 at 1:04 pm
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.
Ryan Grove on July 6th, 2010 at 1:44 pm
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
Marcel Duran on July 6th, 2010 at 2:38 pm
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.
Joseph Scott on July 6th, 2010 at 2:46 pm
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.
Thierry Koblentz on July 6th, 2010 at 3:22 pm
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.
Nicholas C. Zakas on July 6th, 2010 at 3:23 pm
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
)
Alex on July 6th, 2010 at 5:17 pm
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.
WeaselSpleen on July 6th, 2010 at 6:38 pm
What about domain sharding? Is there a point where static assets/domain sharding become more efficient?
cancel bubble on July 6th, 2010 at 6:49 pm
And what about legibility?
Not being able to rely on file names may create problems when it comes to differentiate assets, versions, etc..
Thierry Koblentz on July 6th, 2010 at 7:07 pm
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.
Riyad on July 6th, 2010 at 8:16 pm
@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.
Nicholas C. Zakas on July 6th, 2010 at 11:53 pm
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/juicer/
If you’re on Rails, Jammit looks very interesting: http://documentcloud.github.com/jammit/
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.
Morgan Roderick on July 7th, 2010 at 5:24 am
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/wro4j/
Currently it does support a base64 image encoding in css (not by default). More details can be found here: http://code.google.com/p/wro4j/wiki/Base64DataUriSupport
Unfortunately, data uri adoption have to suffer as long as IE6 & IE7 have a big market share.
Alex
Alex on July 7th, 2010 at 10:14 am
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?
mario on July 7th, 2010 at 12:31 pm
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.
Steve Souders on July 7th, 2010 at 12:46 pm
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.
Leto on July 7th, 2010 at 7:44 pm
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.
tofui on July 8th, 2010 at 1:11 am
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?
Dmitri F. on July 8th, 2010 at 11:22 am
Interesting idea. I use to use Data URIs for my Mail signatures in Apple Mail:
http://blog.tice.de/beitrag.php?file=2007_11_17_1127 (german)
Sample: http://blog.tice.de/a_dateien/mail_signatur2.html
Tice on July 8th, 2010 at 4:02 pm
[...] always prolific Nicholas Zakas has a great post up on his blog titled Data URIs make CSS sprites obsolete. The main argument he makes goes like this: We want to reduce the number of HTTP requests we make, [...]
JavaScript Magazine Blog for JSMag » Blog Archive » News Roundup: Data URIs, Knockout, on July 8th, 2010 at 5:16 pm
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.
Thany on July 9th, 2010 at 4:20 am
Also, the user cannot choose NOT to download images, which is useful on a UMTS connection, for example.
Thany on July 9th, 2010 at 4:22 am
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.
NICCAI on July 9th, 2010 at 5:35 am
@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.
Kevin on July 9th, 2010 at 8:28 am
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
JT on July 9th, 2010 at 1:17 pm
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.
Dave Gregory on July 9th, 2010 at 9:10 pm
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 }
Andrew Maier on July 10th, 2010 at 12:47 am
Next level sh*t [here].
Roll on SVG I say.
Good detective work Nicholas.
ldexterldesign on July 10th, 2010 at 1:48 am
[...] the original post:Â Data URIs make CSS sprites obsolete | NCZOnline Posted in web designs. Tags: a-bit-surprised, css, end-of-, jason, jason-sobel, made-at-the, [...]
Data URIs make CSS sprites obsolete | NCZOnline | top10webdesigncompany on July 10th, 2010 at 2:35 am
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.
Alexander Moya on July 10th, 2010 at 11:51 am
[...] Data URIs: Instead of image sprites you can take a look at Data URIs. It can make you get rid off of big, non-mantainable images files. Just take into account that IE6 [...]
Website optimization checklist | JMPerez Blog on July 10th, 2010 at 3:12 pm
Obviously if you want to use an image that is over 32kb (to support IE8) then you’re screwed
Mark McDonnell on July 11th, 2010 at 6:09 pm
@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/wro4j/wiki/Base64DataUriSupport) . 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
.. First of all it started with 30%, then it reached 50%. Spectacular grow!!! 
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)
Alex on July 12th, 2010 at 3:56 am
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
Andy Davies on July 12th, 2010 at 9:17 am
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.
Constantine on July 15th, 2010 at 10:32 am
[...] fine evening, an article popped up on HackerNews — Data URIs make CSS sprites obsolete. Then, I knew this is something I can pursue to accomplish what we [...]
Dynamic CSS and DataURI to the rescue - Brajeshwar on July 27th, 2010 at 4:37 am
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.
Khang Tran on July 30th, 2010 at 11:48 am
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
Johan on August 2nd, 2010 at 8:04 pm
Doh – answer to my own question – the images would not be cached since the data would obviously be different if the image was changed.
Johan on August 2nd, 2010 at 8:19 pm
“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?
Alex on August 9th, 2010 at 6:04 pm
[...] in en eller kanske ett par förfrågningar men får istället en uppsjö negativa konsekvenser. Data URIs make CSS sprites obsolete tar upp fördelarna med base64 lösningen men ett antal nackdelar diskuteras även i kommentarerna. [...]
Optimering av laddningstiden för broken8.se - Broken8 on August 27th, 2010 at 6:37 pm
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.
Matt on September 10th, 2010 at 10:45 am
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
Hiren Khambhayta on September 22nd, 2010 at 6:00 am
[...] Every image that we include in our design makes a request to the server to be loaded into the page. If we use sprites, would reduce considerably the amount of requests. Also there is another alternative for this issue posted by Nicholas Zakas in his blog named “Data URIs make CSS sprites obsolete“. [...]
Tips to Code Better CSS for in your Projects | Admix Web on November 9th, 2010 at 12:37 pm
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.
Diego on November 22nd, 2010 at 12:16 am
Comments are automatically closed after 14 days.