blue       earthtones
CSS Image Sprites

Image Sprites are 'way cool. But more importantly they offer the web developer boundless opportunities to improve the performance of web pages.

Most of us think of 'sprites' as the animated images in video games, independently moved over a background by video register hardware. But in more recent years the term has, for web developers, equally come to connote image fragments selected from an image palette via css to dramatically improve page speed.

This technique is used liberally by Apple, Amazon, CNN, Google, Yahoo, You Tube, and countless others to improve page load speed (read: performance). And I've been creating and using them for some time for exactly the same reasons.

The reason to use sprites is simply that it significantly improves performance by reducing the number of HTTP requests needed to retrieve the images needed to render a given page. Since the number of parallel HTTP requests between a browser and server are typically limited to four (4) concurrent channels, the balance of image requests will be serialized in groups of four until all of the images have been retrieved.

Conversely, assembling the images required to build a page into one larger image and using css to specify the pixels in which the target image lies allows the browser to render the page much more quickly, increasing perceived responsiveness and the visitor experience. Beyond this, the aggregate size of a palette image is typically much smaller than the sum of the individual images, further improving response time.

— The use of sprites may be the single most expedient way to improve page response time, particularly for image-heavy pages —

Compiling Image Sprites

Compiling Sprite images is an art in itself. Some of the considerations include the required image quality, image transparency, and file size. I typically find myself building at least two sprites for any given site which take these factors into consideration. The steps that I typically undertake include:

  1. Organize the image collection into those which will require transparency and those which will not;
  2. Establish the client goals regarding image quality vs file size (i.e. page load performance) tradeoffs
  3. Determine the optimal image format (e.g. png 8/24, jpeg, or gif) for a given sprite depending on its content;

It likely comes as no surprise that I use Photoshop to build sprites. This page is not intended to be a tutorial on the process, so I'll just say that adding each image to a new .psd as a separate layer, organizing them on a compact and uniform grid using View → Guides, and then using "File → Save for Web and Devices" in the appropriate format for the sprite provides the most straightforward solution.

Application to Navigation Bars / Buttons

a navigation bar image palette

One of the many useful applications of sprites is to optimize navigation buttons which employ different images for :hover, :active, and :visited states. An example of this (from www.theGeoZone.com) can be seen at right and below. Rather than load the nine images separately, this example loads a palette of nine buttons/states within a single image (and consequently a single HTTP request) coupled with css positioning to render the appropriate image for each css pseudo-class.

The composite image is at right. The examples are below. Click-and-hold to see the a:active state. Although I use an unordered list in this example, you could just as easily use floated DIVs or other elements -- see using sprites with the HTML5 <nav> tag below.

The css code for the navigation bar is:


  #topnavDemo ul {list-style-type:none;}
  #topnavDemo li {display:inline}
  #topnavDemo li a {background-image:url('../images/proj/buttons.gif');
                    display:inline-block;height:31px;}
  #topnavDemo li a.btn1 {background-position:0px 0px;width:150px;}
  #topnavDemo li a:hover.btn1 {background-position:0px -32px;}
  #topnavDemo li a:active.btn1 {background-position:0px -64px;}
  #topnavDemo li a.btn2 {background-position:0px -96px;width:125px;}
  #topnavDemo li a:hover.btn2 {background-position:0px -128px;}
  #topnavDemo li a:active.btn2 {background-position:0px -160px;}
  #topnavDemo li a.btn3 {background-position:0px -192px;width:121px;}
  #topnavDemo li a:hover.btn3 {background-position:0px -224px;}
  #topnavDemo li a:active.btn3 {background-position:0px -256px;}
The salient portion of the html code is then, simply:

    <ul id="topnavDemo">
        <li class="btn1"><a href="#"></a></li>
        <li class="btn2"><a href="#"></a></li>
        <li class="btn3"><a href="#"></a></li>
    </ul>
	

but the reality is that the html above will leave about a 4-pixel horizontal space between the buttons. There are 3 or 4 (somewhat odd-looking) variations of the HTML source that will eliminate this. For the example above, I'm actually using:


    <ul id="topnavDemo"
        ><li class="btn1"><a href="#"></a></li
        ><li class="btn2"><a href="#"></a></li
        ><li class="btn3"><a href="#"></a></li>
    </ul>
	

HTML5

Navigation Sprites work equally well in conjunction with the HTML5 <nav> tag; and they use similar css code:

The css code for the HTML5 <nav> bar is:


  nav a {background-image:url('../images/proj/buttons.gif');display:inline-block;height:31px;}
  nav a.btn1 {background-position:0px 0px;width:150px;}
  nav a:hover.btn1 {background-position:0px -32px;}
  nav a:active.btn1 {background-position:0px -64px;}
  nav a.btn2 {background-position:0px -96px;width:125px;}
  nav a:hover.btn2 {background-position:0px -128px;}
  nav a:active.btn2 {background-position:0px -160px;}
  nav a.btn3 {background-position:0px -192px;width:121px;}
  nav a:hover.btn3 {background-position:0px -224px;}
  nav a:active.btn3 {background-position:0px -256px;}
and the html5 code is then, simply:

  <nav>
    <ul
      ><li><a href="#" class="btn1"></a></li
      ><li><a href="#" class="btn2"></a></li
      ><li><a href="#" class="btn3"></a></li>
    </ul>
  </nav>

Note that both the X and Y axis positions for css sprites must be specified as negative numbers. This is because positioning is from the image's perspective; for example, in order to render the portion of the image which lies 224px down from the top (0,0) origin, the image position must be shifted "up" by -224px.

Application to Photo Galleries

An example of image-heavy pages that can benefit significantly from sprites may be observed in photo galleries. The following thumbnails are loaded as a single palette, reducing 8 HTTP requests to just one, then enlarged using the pirobox jQuery plugin. The total size of the eight individual, web-optimized thumbnails was 106Kb, the size of the palette image is is 67.7Kb - a net reduction of 36% in size and 7 HTTP requests. In view of that, consider a gallery which might contain 50 thumbnails and multiply the net gain in performance...

Gold & Petzite [2002-496-06]
Gold [2008-117-10]
Gold [2006-404-04]
Gold [2007-006-05]
Gold [2007-025-02]
Gold [2007-060-04]
Gold [2008-117-22]
Gold [2005-294-04]

Gold photographs reproduced with permission, courtesy of and © Scovil Photography

You might question why not just <img> the entire thumbnail palette and place a client-side image map over it. This would meet one of the goals above, that is, reduce the number of http requests, but in order to use the jQuery pirobox plugin to expand the thumbnails and implement a slide show, it's necessary to insert an anchor tag into the div with class=" pirobox". Try clicking on one of the thumbnails above to see this feature.

Other Applications of Sprites

Another useful application of sprites is to retrieve all images needed to set the visual metaphor for a site in a single HTTP request. For example, this (W3C validated) HTML5 page you're reading obtains its masthead, footers, and corners from a single palette image and renders 'way more quickly as a result.

(Parenthetical to the discussion of sprites, this page also implements a quick-change of the visual metaphor from blues to earthtones by varying the style sheet and sprites that are loaded. Try clicking on the color theme choices at topmost right to see this.)

The application of sprites as a performance improvement measure is only limited by the developer's imagination and knowledge of css; and well worth the investment of time to familiarize yourself with the technique!

Further Reading:
  1. Try a web search for "css sprite tutorial" for dozens of examples. A good introduction is here.
  2. With regard to compiling the palette image (my term), my personal preference is to use Photoshop in order to create precisely the composite image I want. However, there are a number of websites that will do this for you. Try a web search for "css sprite generator".
  3. A useful tool for analyzing page load speed (and other page performance metrics) is the Page Speed plugin to Firebug.