Previously, I discussed how the #1 problem with slow-loading websites is often the number of separate HTTP requests.  Now lets talk about images.

Images and icons are the the building blocks of website design and as such, there are often many images required for each page.  It is not uncommon for a complex web application to load tens if not hundreds of images.  Each image means network latency and render time as the image is requested, downloaded, cached, and rendered.  Even once it’s cached, it still takes network overhead to check and see if the image has changed.

To improve load times, one thing we can do is reduce the number of separate images.  This can be done by simply designing sites that require fewer images, but often that’s not possible. The technique I’ll discuss today is to use sprites.

The basic concept with sprites is that you put all your images tiled into a single image file. Each image in the sprite has its own offset that you need to remember or calculate.  Using CSS, we can do a nifty trick with DIV tags to create a small viewport and display only a certain portion of the sprite image, making just one icon visible.  The end result is that only one image file is downloaded instead of hundreds.

This trick is accomplished by replacing each IMG tag with a DIV tag with a unique CSS class. This DIV has a fixed height and width set the same as the icon.  Each DIV shares the same background-image property pointing to the sprite image, and the background-position is set to the offset for the individual icons.

Here is an example of the changing viewport.  You can see the underlying image is the larger composite sprite image, but we only want the Terminal icon with is at the offset {x:40, y:40}. So we set the CSS width and height to 20px, and set the background-position to -40 -40. The offset is expressed in negative numbers because the image is moving to the left x,y pixels to position the correct icon under the 20x20 viewport.

performance sprite viewport

/* CSS - Example #1 */
.icon1 {
    background-image: url(/sprite.png);
    background-position: -40px -40px;
    width: 20px;
    height: 20px;
    float: left;
}

<!-- HTML - Example #1 -->
<div class="icon1"></div>

Lets look at the performance of a real example.

Example #2 includes 100 free icons individually.  Notice how painfully slow it loads.  In my analysis using Firebug, it took 3.61 seconds to display.  Ouch!

(click for a larger image)

Now take a look at the Example #3 which uses a single sprite image.  This only took 633ms and the end result is identical.

(click for a larger image)

Example #2 wraps each IMG tag with an anchor that links to the icon file. This same thing can be accomplished two ways with the sprite technique.  The simplest way is to wrap the DIV in an anchor tag, just like the IMG tag was wrapped.   The other way is to add an onClick event to the DIV element. However, this imposes undue requirements on your users and adds a dependency on JavaScript.

Unfortunately I have yet to find a way to use a sprite when tiling background images.  Has anyone come across a cross-browser technique to solve that problem?