Ali Jafarian

The Web Project

I'm building a new online platform for learning web design and development. Check out the KickStarter to get early access and heavily discounted rates!

View the KickStarter


CSS sprites have been around for a while, and for good reason. They minimize server requests (which allows web pages to load faster), and they keep CSS organized. They are, however, a bit tricky to understand at first.

For those of you who aren’t familiar with CSS sprites, the basic concept behind them is to create one image file made up of multiple images for your web page’s background images (instead of separate background images). But that sounds crazy! Yes, at first it does. But once you realize the benefits of CSS sprites you will try to user them for everything possible! In fact, most large enterprise level websites do use one image sprite for most of the graphics on their site.

Today I’m going to show you how to design your image sprites and CSS to be more flexible in your website or application.

Design

We’re going to design a 80×20 pixel sprite that contains four 20×20 pixel icons. The point here is to avoid any un-needed space and make our sprite as compact and pixel perfect as possible. I’ve referenced some examples below:

Good Sprite

Bad Sprite

The HTML

Our HTML will consist of a parent <div> that contains a standard <ul>. Inside of the <li>’s we have anchor links with their own unique class (or id, if you prefer). Then, inside the <a>’s we place a <span> with a consistent class (in this example I used “icon”).

<div id="icon-nav">
  <ul>
    <li><a href="#" class="profile"><span class="icon"></span>Profile</a></li>
    <li><a href="#" class="inbox"><span class="icon"></span>Inbox</a></li>
    <li><a href="#" class="calendar"><span class="icon"></span>Calendar</a></li>
    <li><a href="#" class="settings"><span class="icon"></span>Settings</a></li>
  </ul>
</div>

The CSS

Our CSS is pretty standard, but the key to realize is the positioning of the <span>’s. They are positioned absolutely inside of the relative positioned <li>’s. This allows the icon to be part of the clickable <a> without being a background image. It also give us complete control over where the icon is positioned in relation to your link. So if the styling of your links changes you don’t have to re-size the sprite image, you simply change the CSS background-position property to reflect the new positioning.

#icon-nav {
  float: left;
  width: 600px;
}
#icon-nav ul {
  font-family: 'Play', sans-serif;
  font-size: .9em;
  list-style: none;
}
#icon-nav ul li {
  border-left: 1px solid #ea7f15;
  float: left;
  position: relative;
}
#icon-nav ul li a {
  background: #ea7f15;
  background: -moz-linear-gradient(top, #ea7f15 0%, #db4602 100%);
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ea7f15), color-stop(100%,#db4602));
  background: -webkit-linear-gradient(top, #ea7f15 0%,#db4602 100%);
  background: -o-linear-gradient(top, #ea7f15 0%,#db4602 100%);
  background: -ms-linear-gradient(top, #ea7f15 0%,#db4602 100%);
  background: linear-gradient(top, #ea7f15 0%,#db4602 100%);
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ea7f15', endColorstr='#db4602',GradientType=0 );
  color: #fff;
  display: block;
  padding: 20px;
  text-decoration: none;
  width: 109px
}
#icon-nav ul li a:hover {
  background: #ea7f15;
}
#icon-nav ul li a span.icon {
  background: url(images/icons_sprite.png) no-repeat;
  height: 20px;
  position: absolute;
  right: 20px;
  top: 18px;
  width: 20px;
}
#icon-nav ul li a.profile span.icon {
  background-position: 0 0;
}
#icon-nav ul li a.inbox span.icon {
  background-position: -20px 0;
}
#icon-nav ul li a.calendar span.icon {
  background-position: -40px 0;
}
#icon-nav ul li a.settings span.icon {
  background-position: -60px 0;
}

Summary

And there you have it! A simple, yet flexible, CSS icon sprite. Keep in mind that there are many ways to design and code CSS sprites. Many designers/developers will use the sprite as a background image for the <a> links themselves, as opposed to creating extra spans. That’s a fine approach, but over the years I’ve found this approach to be more efficient in terms of time and ability to update. Hope it helps!