Home / Using CSS sprites for image navigation

Using CSS sprites for image navigation

I normally stay away from using images for navigation but when I do it’s useful to use CSS image sprites so a single image can be downloaded for the navigation. This saves time and bandwidth and means there’s no chance of lag of the mouseover image between mousing over and the image being grabbed from the server, or having to bother about pre-loading images.

What’s a CSS sprite?

The easiest way to explain is with an image. The image below is part of the navigation from my running blog which will be going live in the next couple of weeks.

Instead of having 10 images (5 off and 5 on) we can use a single image and use the CSS background-position property in combination with setting the widths and heights so make the image appear in the correct position for each navigation item.

It’s then also possible to still have text in the anchor tag which doesn’t appear on the page, but adds to usability if the CSS doesn’t load for some reason.

The navigation in action

Here’s a working version of the above navigation. Move your mouse over the buttons and you’ll see how they change from a lighter green background to a darker one, and then back again when you mouse out.

Note: if you are reading this in a feed reader it may not work as expected. If it’s not working then please click through to read the article in a web browser and it will work.

This has been tested and works in IE6 to IE8 beta; Firefox 1, 1.5, 2, 3; Opera 9.0; Safari 3.2; Chrome 1.0. Windows versions only.

How it works

The HTML looks like this:

<ul id="example-nav">
    <li><a id="example-nav-home" href="#">Home</a></li>
    <li><a id="example-nav-events" href="#">Events</a></li>
    <li><a id="example-nav-upcoming" href="#">Upcoming Events</a></li>
    <li><a id="example-nav-training" href="#">Running Log</a></li>
    <li><a id="example-nav-photo" href="#">Photo Gallery</a></li>
    <li><a id="example-nav-equipment" href="#">Equipment</a></li>
    <li><a id="example-nav-personal" href="#">Personal Best</a></li>
    <li><a id="example-nav-misc" href="#">Misc</a></li>
</ul>

The width and height of the <ul> need to be set to the width and height of the image, the padding and margin needs to be reset to 0, there should be no bullet dots and overflow needs to be hidden so there are no rendering issues. Therefore, the CSS for #example-nav looks like this:

#example-nav {
    padding: 0;
    margin: 0;
    list-style: none;
    width: 398px;
    height: 26px;
    overflow: hidden;
}

The <li> elements need to be floating otherwise they’ll still appear as a vertical list:

#example-nav li {
    float: left;
}

Next, set the defaults for the <a> tags inside the navigation. They need to be blocks, have the sprite as the background image and the top padding needs to be set to the same height as the image so the anchor text doesn’t appear at all. Here’s the CSS:

#example-nav a {
    display: block;
    background-image: url(/images/css-sprite-example.png);
    padding-top: 26px; /* same as height of #example-nav */
    text-decoration: none; /* needed for IE8 beta, otherwise it still shows the underlines */
}

And finally the settings for each <a> need to be set to specify the width and the background position. The first element is the easiest, as all we need to set is the width and the vertical offset like so:

#example-nav-home {
    width: 42px;
}
#example-nav-home:hover {
    background-position: 0px -26px;
}

The above CSS says that #example-nav-home is 42px wide, and when the mouse goes over it we move the background image 26px up. This shows the bottom section of the sprite image.

The background position must be set for both off and on states for the rest of the <a> links. The horizontal position is always the negative width of the previous elements combined, and the vertical position is 0px when the mouse is out and -26px (in this example) when then mouse is over.

The definitions for the remaning <a> tags is as follows:

#example-nav-events {
    width: 53px;
    background-position: -42px 0;
}
#example-nav-events:hover {
    background-position: -42px -26px;
}
#example-nav-upcoming {
    width: 116px;
    background-position: -95px 0;
}
#example-nav-upcoming:hover {
    background-position: -95px -26px;
}
#example-nav-training {
    width: 87px;
    background-position: -211px 0;
}
#example-nav-training:hover {
    background-position: -211px -26px;
}
#example-nav-photo {
    width: 100px;
    background-position: -298px 0;
}
#example-nav-photo:hover {
    background-position: -298px -26px;
}

Making one of the buttons active

In response to an email and some comments from a couple of my visitors I have added a post titled "CSS Sprites – making one of the buttons active" which shows how to make one of the buttons active/selected.

Conclusion

Using CSS sprites for navigation is relatively easy and it means there’s less to download from the server when the page is loaded which means faster loading overall. In the above example we only have to download a single image instead of 10. If your navigation has 10 elements then you’d only need to download a single image instead of 20, and so on.