Dynamic Labels with CSS



This is a CSS tutorial on how I created the icon bank used to filter the news on Shacknews. For the redesign, we needed group of icons that had the following qualities:

  1. The group of icons should have a default label so the user can tell what they are.
  2. Each icon should have its own individual label so the user can tell what it does.
  3. Each icon should have a clear hover state.
  4. The whole thing must fit in a space about 250 pixels wide by 21 pixels tall.

The solution you see uses nothing but CSS and images. No Javascript.

This tutorial assumes a working knowledge of CSS techniques such as image replacement and sprites. Now let's get to work.


div.filter contains an h3 and an unordered list. The list items are each given a class so we can reference them individually later. Each list item contains a link. Since we will be doing image replacement, each link has a title attribute for usability. div.headerbar is only present because it is referenced in the original CSS, so you can ignore it.

The links below were changed to point to # for readability. Originally they pointed to other sections of the website.

<div class="headerbar">
  <div class="filter">
    <h3>Filter News</h3>
      <li class="fall">
        <a href="#" title="All News">All News</a>
      <li class="fconsole">
        <a href="#" title="Console Games">Console Games</a>
      <li class="fpc">
        <a href="#" title="PC Games">PC Games</a>
      <li class="fsubscribe">
        <a href="#" title="Subscribe">Subscribe</a>

The Sprite

The following sprite is used for everything. Anytime I talk about a background image, this is it. If you need more information about using sprites in CSS, ALA has a great article on the subject.

Each row of the sprite corresponds with a single state of the icon bank. The top row is the default state, and each row after that is the state when hovering over a specific icon.

These icons are by Mike Kane, but all the other iconography on Shacknews is by Gray Smith.


The Basic CSS

div.filter is given a width of 270px, a height of 21px, and is given the sprite as a background image. The background position of left top means the "Filter News" label and the icons along that row are visible.

The h3 is hidden. The bullets, margin, and padding are removed from the unordered list, and it is absolutely positioned to account for a bug in IE.

The links are set to block and assigned dimensions of 22px by 21px. Their z-index is set to 2. The text inside the links is hidden by a negative indent. Finally, each link is given a specific absolute position corresponding with the icons in the sprite.

As you can see, the links themselves are transparent by default. You can only tell where they are by div.filter's background image.

div.headerbar div.filter {
  position: absolute;
  top: 10px;
  left: 0;
  width: 270px;
  height: 21px;
  background-image: url(sprite-filter.gif);
  background-repeat: no-repeat;
  background-position: left top;

div.headerbar div.filter h3 { display: none; }

div.headerbar div.filter ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  position: absolute;
  top: 0;
  right: 0;

div.headerbar div.filter li a {
  display: block;
  position: absolute;
  top: 0;
  height: 21px;
  width: 22px;
  overflow: hidden;
  text-indent: -5000px;
  background: none;
  z-index: 2;

div.headerbar div.filter li.fall a { right: 69px; }
div.headerbar div.filter li.fconsole a { right: 46px; }
div.headerbar div.filter li.fpc a { right: 23px; }
div.headerbar div.filter li.fsubscribe a { right: 0; }

Hover CSS

When you hover over an icon, the link position is moved all the way to the right, and its width is set to 270px, the width of div.filter. The link's z-index is also set to 1, which drops it underneath the other icons. By doing this, you can still hover over the other icons even though the current link is taking up the entire width of div.filter.

The sprite is set as the link's background-image, and its background-position is set to specific coordinates depending on which icon is being hovered. For example, if you hover over the "PC News" icon, the link's background-position is set to left -63px, making the "PC News" label and the fourth row of icons visible. The third icon stands out and the rest appear subdued.

When you stop hovering over an icon, it reverts back to its default state. Its z-index is set back to 2, its width is set back to 22px, its right property is set back to the default, and it becomes transparent again.

div.headerbar div.filter li a:hover {
  width: 270px;
  z-index: 1;
  background-image: url(sprite-filter.gif);
  background-repeat: no-repeat;
  right: 0;

div.headerbar div.filter li.fall a:hover {
  background-position: left -21px;

div.headerbar div.filter li.fconsole a:hover {
  background-position: left -42px;

div.headerbar div.filter li.fpc a:hover {
  background-position: left -63px;

div.headerbar div.filter li.fsubscribe a:hover {
  background-position: left -84px;

Final Notes

That's all there is. All the magic takes place in the hovers. By changing the dimensions and background image of the link, its easy to simulate a dynamic label for a group of icons.

As far as I know, this technique works in Firefox, IE 6 and 7, Opera, and Safari.

I used an image for the labels to match the style of the site. With a few minor modifications, you could easily use text for the labels (or even the icons). I made a totally impractical proof-of-concept to demonstrate how crazy you can get using this concept.

If you have any questions or comments, send me a note.

Pup, Inc.

Last updated July 26, 2007

Back to Pup, Inc.