Base64 vs. CSS Sprites: battle for performance

2012-07-15 17:17:17

Tones of developers fighting with unneeded kilobytes of data on their web projects to increase their performance. Minimization of pages weight, reducing the number of requests, place of including scripts and many other things affect the speed of loading and displaying the pages. Developers using CSS sprites to reduce the number of queries when page loads. Base64 image encoding also using in this context and in some way it is more convenient.

CSS sprites

The main idea of CSS sprites is combining multiply images to one. For showing different parts of it on the page use background-position in combine with width and height.

EXAMPLE: CSS Sprite from Google:

CSS Sprite from Google

EXAMPLE: CSS Sprite from Apple:

CSS Sprite from Apple

Benefits:

  • combining multiple image loading requests into one request

Drawbacks:

  • hard to maintain and update without some tool to help, manually editing and putting together image sprites is quite a chore
  • increased memory consumption (possibly very dramatic): this is often overlooked. The time to deliver the images is decreased at the expense of a bigger memory and CPU footprint, especially for large sprites and sprites with a lot of whitespace;
  • bleedthrough for sprites that don’t have much whitespace to separate images, there’s an increased chance of nearby images visibly bleeding through other elements.

Base64

Base64 works with Data URI.

  • data:[<mime type>][;charset=<charset>][;base64],<encoded data>

In CSS it looks like this:

  • selector {
  • background: url(data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7)
  • no-repeat left center;
  • }

In plain HTML it looks like this:

  • <img
  • width="16"
  • height="16"
  • alt="star"
  • src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7"
  • />

So, the goal of using base64 can be reached if we encode all small images and put them in one CSS file. After that we will replace multiply HTTP requests with one - css file request.

Benefits:

  • combining multiple image loading requests into one request of CSS file;
  • easy updates of generated file.

Drawbacks:

  • base64 encoding makes file sizes roughly 25% larger than their original binary representations, which means more data down the wire (this might be exceptionally painful on mobile networks); with gzipping our base64 CSS file will be about only 10% larger.
  • data URIs aren’t supported on IE6 or IE7

What to chose:

Several months ago my answer would be "Base64 if we need to update our file often, and CSS Sprites if not". But now there is one more thing which gives the advantage to the side of CSS Sprites - Retina devices.

Retina prepared graphics are 2x larger than common one. So if we create 2 CSS Sprites (for retina and common) browser will download those one that it will use. In Base64 way we will have to encode all graphics and there will be 2 files that will upload automatically in both ways - while using retina device or common.

If we want to work with it in CSS style only I'll chose CSS Sprites.

This is the detection of Retina displays in CSS Media Queries way:

  • selector {
  • background-image: url(our_bg_image.png); /* will be downloaded on common displays */
  • }
  • /* Stylesheet for Retina */
  • @media screen and (-webkit-min-device-pixel-ratio: 1.5),
  • screen and (min-device-pixel-ratio: 1.5) {
  • selector {
  • background-image: url(our_bg_image@2x.png); /* will be downloaded on retina displays */
  • }
  • }

If we don't need to support IE<9 we can use Base64 way with retina script detection:

  • <script>
  • var retina = window.devicePixelRatio > 1 ? true : false;
  • if (retina) {
  • // the user has a retina display
  • } else {
  • // the user has a non-retina display
  • }
  • </script>

As for me - I'm choosing CSS Sprites and CSS3 Media Queries Retina detection because of:

  • one technology using to detect retina display and using sprites - CSS3;
  • IE<9 support (I don't need to support them, but as a web developer - I'll sleep much better if I have nice-looking website in all browsers)