In the olden days, video games relied heavily upon sprites given the rather severe limitations of computing hardware at the time.
You can use this “old” technique to reduce the bandwidth load on your server.
Most major web sites use them, but you may never have even heard of a sprite.
But what exactly is an image sprite, and why does it save bandwidth?
To understand what a sprite is, consider a web site that has 3 images on it. Each image is a button, labeled A, B, or C. When you hover your mouse pointer over each of the 3 images, they glow. That means you actually need 6 images in total: 3 for the normal A, B, and C buttons, and 3 images for the glowy A, B, and C buttons.
Now, normally, you’d just use a bit of javascript or CSS to make the mouseover/hover effect, and you’d call it a day. But there is a problem: When a new user visits your web site, their browser must download 6 different images just to display 3 little buttons. Worse yet, even frequent visitors’ browsers may re-request the 6 images from time to time. Your browser’s cache is only so large, and if you do a lot of surfing, those images might get pushed out of the cache.
To make matters worse, it’s not just the size of the images that counts. Let’s say each of your 6 button images is 1kB. Well, who cares about 6kB, right?? Thing is, there is also additional bandwidth overhead every time your browser requests new data from the server. It works something like this:
- REQUEST: Get HTML page
- REQUEST: Get stylesheet
- REQUEST: Get image #1
- REQUEST: Get image #2
- REQUEST: Get image #3
- REQUEST: Get image #4
- REQUEST: Get image #5
- REQUEST: Get image #6
That’s a lot of extra requests for those 3 buttons! The more complex your web site is, the more images you may have, and the more requests that have to be made to the server. More images = more requests = more bandwidth.
So what would happen if you could combine those 6 images into only 1 image? The combined image might only be 4.5kB, which already saves you 25% on bandwidth for the images themselves. Not only that, but the list of requests made by your web browser now looks something like this:
- REQUEST: Get HTML page
- REQUEST: Get stylesheet
- REQUEST: Get image #1
You’ve also managed to knock off 5 requests back to the server, which also saves that additional request overhead. You use less bandwidth, your page loads faster for the end user, and everyone goes home happy.
A combined image in our example above is known as an image sprite. The simple explanation is that you use 1 image, and then use a bit of fancy CSS that will only display part of that combined image in certain places on the web page. When the user hovers over the A button in our example above, the CSS actually displays a different part of the same image. It looks like this:
There are 6 images, each 50px x 50px, combined into one larger image.
The HTML in our example looks like so:
<a id="a-button" class="s-buttons" href="#" title="A"></a> <a id="b-button" class="s-buttons" href="#" title="B"></a> <a id="c-button" class="s-buttons" href="#" title="C"></a>
And the CSS looks like this:
.s-buttons { background: url("buttons.gif") no-repeat; height: 50px; width: 50px; display: block; } #a-button { background-position: 0 0; } #a-button:hover { background-position: 0 -50px; } #b-button { background-position: -50px 0; } #b-button:hover { background-position: -50px -50px; } #c-button { background-position: -100px 0; } #c-button:hover { background-position: -100px -50px; }
As you can see, it’s pretty simple. The background-position property shifts the “porthole” to a different segment of the total image.
The two parameters are the X and Y offsets. You start at the upper lefthand corner of the image. An offset of 0 0
is the normal A. An offset of 0 -50px
shifts us down to the glowing A. An offset of -100px -50px
shifts us over and down to the glowing C.
All the images that comprise the sprite don’t have to be the same size. You can go crazy if you’d like. Also, keep in mind that when using the JPG or PNG image formats, it’s often useful to experiment with which images you’re combining. Sometimes you can achieve huge reductions in image sizes by grouping images into sprites that are mostly the same color, for example. PNG is an especially interesting format for making sprites due to the way it compresses image data. Best to play around and see what happens!
You can also use a site like PunyPNG.com to losslessly compress images of all types. That alone could save you a LOT of bandwidth.
Finally, keep in mind that my example above is one way to use image sprites. There are quite a few different sprite techniques out there, but the basic premise is the same.
And that’s all there is to it!
[ad name=”banner”]
This information is now partially obsolete if you have a modern server with HTTP/2.
Because HTTP/2 and its predecessor SPDY support multiplexed connections, the overhead of requesting several small images at once has been significantly reduced.
Instead of making many discrete requests, HTTP/2 compatible browsers can request a large number of resources all at once and receive them all in one round trip.
True, but now the danger is that everyone will totally abandon sprites since, “it doesn’t matter anymore”. And the reality (still) is that often times, you can combine, say, 9 1kB button images into 1 spritey image, optimize it, and you end up with a single 3kB file to download (concurrently with other files over HTTP/2). So, even with HTTP/2, I still use sprites even though I’m a little less insane about it.
Everyone usually chuckles when I tell them I just saved 6kB per fresh page load in image size, but do that kind of thing 100 times, and you save 600kB per empty-cache page load. Do everything that way (including JS, CSS, and optimized HTML content), and you end up with a much faster-loading page.
But, as I say, everyone seems to think I’m totally nuts on that count. Like, “Optimize?! Why??? Everyone has 1Gbit fiber these days!” Well, actually, no… 🙂