Some notes on duplicate data-uris in CSS

If you are considering using data-uris instead of CSS sprites for your background images, you are probably doing this (at least partly) for performance reasons. Each image you can stuff into a data-uri saves you an HTTP call, after all.

But if you are thinking about performance, you will also be paying attention to the size of your CSS, and you might be concerned about the use of the same background image multiple times, but in different contexts. With image files, referencing the same background image multiple times is lightweight, but with data-uris, the base-64 encoded data takes up a lot more space:

.monkey {
	background-image:url(http://sunpig.com/martin/code/2011/gzipcss/erlenmeyer.png);
}
.fez {
	background-image:url(http://sunpig.com/martin/code/2011/gzipcss/erlenmeyer.png);
}

vs.

.monkey {
background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAlotsmoredata...");
}
.fez {
background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAlotsmoredata...");
}

There are, of course, other ways of assigning the same background image to different elements (you can group your selectors, or create a mixin classname for use in your HTML). But if, for whatever reason, you do end up embedding the same base-64-encoded resource multiple times in the same file, provided you are serving your CSS gzipped, you don’t need to worry too much about the extra file size.

The reason for this is that the DEFLATE algorithm (which powers gzip compression) is all about eliminating duplicate strings. When the algorithm finds the second instance of a long base-64-encoded string, it can just replace it with a reference to the first instance. And because the reference is much shorter than the base-64 block itself, the size increase of the gzipped file is negligible.

Here’s a short table showing some actual figures. The files 1.css, 2.css, and 3.css contain 1, 2, and 3 copies of the same base-64-encoded image respectively. I used nginx (0.7.67) on my laptop to check the gzipped file sizes.

File Uncompressed size (bytes) Gzipped size (bytes)
1.css 1437 1139
2.css 2871 1135
3.css 4311 1156

Note that the file with the data embedded twice comes out even smaller than the version with only one copy. gzip can be a bit strange that way, which is why you should always check the gzipped version of any CSS or JS files you’re fine-tuning for size. Minor optimizations don’t always work out the way you might expect.

Just for clarity: embedding the same resource multiple times is not always a great strategy for re-usable CSS. But when you do it, at least you don’t have to worry about file size bloat.

Further reading