The Why
Around this time last year, Google officially announced that page load time is a new factor that can have an effect on our SERP. This means that Google's page rank algorithm may reward certain websites with a better SERP simply because they load faster. Even though Google claims that this new factor accounts for less than 1% of search queries, any website that values a high organic page ranking should take the change seriously.
Having a faster website not only has the potential to boost (or maintain) SERP, it also has a positive effect on the user's experience. Akamai Technologies, innovators of one of the world's leading CDN, sponsored a research study on the retail website performance and concluded that "the consequences for an online retailer whose site underperforms include diminished goodwill, negative brand perception, and, most important, significant loss in overall sales."
Methods like compression, minifying CSS and JavaScript, and caching are all common suggestions for improving a website's page load time. However, there remains a less suggested method that involves reducing the number of HTTP requests to the server by combining all of the commonly used images into one image file.
With the tools provided by webpagetest.org, we can examine the performance of any website during page load. I've created a sample webpage that is comprised of a simple HTML layout, one external CSS document, and 15 different images (27 including mouse-over images) that make up the user interface. The page load test results (the median of 10 tests) state that it takes 1.644 seconds for the page to load, which is a very respectable load time. However, if we take a look at the nifty graph that webpagetest.org provides us with, we will notice the inefficient way in which we load our images.

For every image used on the page, a separate HTTP request is made. The time spent waiting for the first byte (known as TTFB or Time to First Byte, shown as green in the waterfall graph) for each separate HTTP request is minuscule (about 100 milliseconds) and the majority of the time is spent actually downloading the image (represented by the blue). That being said, a meager 100 milliseconds multiplied by a large quantity of images can add up quickly.
 |
The majority of HTTP requests being made are for images. |
 |
The majority of bytes being downloaded are from the images used on the site. |
To combat this inefficiency, we can simply reduce the number of requests being made to the server by combining all of the images used to create the site's user interface into one large image. The amount of data being downloaded will be equivalent, but there will only be one HTTP request made to get that data. Therefore, with this change, less time will be wasted during the loading of the page.
*Note that the time saved using a CSS sprite is not necessarily equal to the number of requests made for images multiplied by 100 milliseconds, as most modern browsers can make two to four requests simultaneously.
The How
I used Microsoft Paint to create and combine all of the images used in the sample web page to keep things simple:
Click here to view the version of the Sample Site that does not use a CSS sprite.
Click here to view the version of the Sample Site that does use a CSS sprite.
Both versions of the sample site have almost identical markup. The main differences lie in the cascading style sheet. If we take a look at the CSS rules created for the anchor element used as a register button, we can see how the image is placed without the use of a sprite:
CSS not using sprite image:
a.headerNav
{
float: left;
width: 162px;
height: 43px;
margin: 10px 0px 10px 16px;
}
a.register {background-image:url('images/register.gif');}
a.register:hover {background-image:url('images/register_over.gif');}
Markup of the register link:
<a href="#" class="headerNav register"></a>
We simply set the size of our element and its background to our register image (images/register.gif). The mouse-over effect is created by using the "hover" pseudo-class to change the background to a different image (images/register_over.gif). That's about it--we have our image button.
Now to get the same results using a sprite image. Here's that same register element's style and markup:
CSS using a sprite image:
.sprite {background-image:url('Sprite.gif');}
a.headerNav
{
float: left;
width: 162px;
height: 43px;
margin: 10px 0px 10px 16px;
}
a.register {background-position:-165px -260px;}
a.register:hover {background-position:-165px -310px;}
Markup of the register link:
<a href="#" class="headerNav register sprite"></a>
Notice that we're now using another class I chose to call sprite. The only property set in this class is the background-image property and it's pointing at the sprite I created with Paint:

I chose to place this property in a new class called sprite because I knew many other elements on my page would use the same image as their background. Instead of setting the property for each element separately, I chose to place each element using my sprite image into the sprite class.
The rest of the styles are almost exactly the same. The only difference is that we no longer set the background-image property for our register class. Instead, we specify where to take a virtual slice of our giant sprite image by setting the background-position property. This property accepts two values delimited by a space. The first value represents horizontal positioning and the second represents vertical (x-axis and y-axis). The size of your element, determined by the height and width properties, determines the size of the slice you take out of the sprite image. Imagine that the background-position property designates where that rectangle (determined by your height and width properties) is positioned on your sprite.
For instance, if we set the height as 43 pixels and the width as 162 pixels, we have a virtual rectangle that looks like this (without the borders):

The background-position property positions the top-left corner of this rectangle in our sprite, selecting a particular piece of our sprite to display. Here's an illustration of the background-position when set to 0px 0px:

Notice that the top-left corner of our virtual rectangle is located at the top-left of our sprite, as our background-position coordinates were specified to be 0px from the left and 0px from the top. Currently, this displays a portion of our header logo, which is not what we were going for. If we change the background-position property to be -165px -260px, the rectangle would select the register button portion of the sprite image:

Notice that the virtual rectangle is now displaying our register button. That button is exactly what will display as the background of our element. If we replicate this technique for every image used on the site, we'll only have made a request for this one sprite image instead of separately requesting each individual image.
The Real Results
Let's take a look at the (much smaller) page load waterfall graph for the sample webpage that uses an image sprite:

Observe that the overall time spent on the TTFB (green) is way lower, as we only have to make three requests instead of 17.
 |
The number of HTTP requests for images has been severely reduced. |
 |
The amount of data downloaded has stayed the same. |
With the same layout and design, by utilizing the CSS background-position property to virtually slice a single image sprite instead of separately requesting individual images, we've managed to go from 1.644 seconds down to 1.172 seconds taken to load the sample page. That's a 472 millisecond (29%) improvement! Not too bad considering all we had to do is toss all of our images into one image file and change the way we work with images in CSS.
Feel free to download the source of the sample pages for your own use:
Sample Page Source
Here are the links again to both pages:
Sample Page that does not use a CSS sprite.
Sample Page that does use a CSS sprite.
If you're interested in web development, I suggest browsing Intertech's website for available training courses.
1640aae5-5233-4527-9b50-d1fc569c40d0|4|4.8