Dave Woods - Freelance Web Design Warwickshire

CSS Hover Icon Menu Using CSS Sprites

Swapping icons on hover is traditionally done using JavaScript but this method requires a lot of unnecessary code and a number of different icons in order to achieve what should be really simple.

However, there is a solution and this tutorial will explain how to apply different hover over icons to an unordered list using CSS Sprites.

First up, here’s an example of what this tutorial can be used for creating:

You may be surprised to learn that only a single image is used within the example page above. This is achieved using a technique known as CSS Sprites and simply adjusts the background position within the CSS to display the part of the image that’s required.

Here’s the image that is used:

Now that you’ve seen a demo and the image that’s used, lets move onto some code.

HTML

The HTML is really simple an is just an unordered list with an ID applied to each list item and an empty span which we’ll be replacing with an image.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Icons Demo</title>
</head>
<body>
<ul id="navigation">
<li id="digg"><a href="#"><span></span>Digg</a></li>
<li id="reddit"><a href="#"><span></span>Reddit</a></li>
<li id="delicious"><a href="#"><span></span>Del.icio.us</a></li>
<li id="facebook"><a href="#"><span></span>Facebook</a></li>
<li id="technorati"><a href="#"><span></span>Technorati</a></li>
</ul>
</body>
</html>

CSS

Within the CSS, we’ll start off with some generic styling.

* {
padding: 0; margin: 0;
}
body {
font: 85%/1.5 verdana, arial, helvetica, sans-serif;
padding: 10px;
}
#navigation {
list-style: none;
}
#navigation a {
color: #CCC;
text-decoration: none;
}
#navigation a:hover {
color: #666;
}

Next, we can start dealing with the icons themselves and can simply apply the set of icons to the span using the following CSS.

#navigation span {
background: url(icons.gif);
float: left;
width: 16px;
height: 16px;
margin: 3px 5px 0 0;
}

You’ll notice at this stage that all this does is apply the icon in the top left of the image to all the list items. So, in order to change this, we need to move the background image accordingly to display the relevant image within the 16×16 box.

We can do this by using the following CSS to positioning the image accordingly.

#reddit span {
background-position: -16px 0;
}
#delicious span {
background-position: -32px 0;
}
#facebook span {
background-position: -48px 0;
}
#technorati span {
background-position: -64px 0;
}

And finally, we can create the hover effect by moving each icon in turn up by 16px on hover by simply adjusting the background position.

#digg a:hover span {
background-position: 0px -16px;
}
#reddit a:hover span {
background-position: -16px -16px;
}
#delicious a:hover span {
background-position: -32px -16px;
}
#facebook a:hover span {
background-position: -48px -16px;
}
#technorati a:hover span {
background-position: -64px -16px;
}

And that’s it. It does require an extra span in the markup which I’m sure a few minimalistic designers will be against but I do prefer it to the alternative JavaScript methods.

I’m sure there are other CSS methods available so feel free to post in the comments below, any other methods you may have come across in the past (or in the future).

15 comments on “CSS Hover Icon Menu Using CSS Sprites

  1. James Hopkins

    Dave,

    You’ve chosen to float the span to change it from it being inherently inline to display as a block box- however you’ve failed to clear the float container

  2. Dave Post author

    @James – You shouldn’t need to clear the float in this situation as the float is just being used so that width and height can be applied to the span.

    There may be occasions when you’ll have to use a clearing method but this shouldn’t need it as it is.

    @Anjanesh – You could do but to get it working cross browser, you’d need to use filter:alpha(opacity=100);-moz-opacity:1.0;opacity:1.0;

    It also won’t validate.

    The purpose of this tutorial was more to show how you could swap icons on hover as you may have an interface where you want to change the icon completely and this would be a useful method to use.

    Hope that makes sense?

  3. James Hopkins

    @Dave- Whilst I understand your method of floating the span, effectively transforming it to behave like a block box, why do you feel that a clearing method isn’t needed in this instance? One of the child elements is floated, so the float container needs to be cleared.

  4. Dave Post author

    @James – The float is only on the span and therefore as the text next to it isn’t floated the container quite happily surrounds it’s children without the need for a clear.

    I understand your concern and if the icon was larger than the text then it would need clearing otherwise there could be problems with overflow so in practice I probably would use a Clearing Method.

  5. James Hopkins

    @Dave, the point I’m trying to put across is that not clearing a float container isn’t good practice. If someone who is new to CSS comes across your post and uses a larger icon, they may get confused as to why their border/background around their anchor doesn’t encapsulate the span; same problem if they try to add vertical margin/padding without clearing the float container first.

    Nice looking site BTW – check your inbox 🙂

  6. James Hopkins

    That won’t work. I’m guessing you were thinking along the lines of floating and clearing the anchor element, thus taking it out of the flow which will clear it of any child element floats. However you would be going round in circles a bit as you would then need to clear the anchors parent element, using clearfix or similar.

    I would personally just use clearfix on the anchors in the first place.

  7. Dave Post author

    It will work as it will force the list item to clear underneath the previous floated element.

    You could also use the overflow method on the list item as this would have the same effect.

    Maybe we’re thinking of different things so it might be useful if you put an example online somewhere of a problem as there’s usually a better solution than applying the clearfix method (I don’t like adding extra code unless I have too ;))

  8. James Hopkins

    It would be cool if you could update your example with your proposed solution, as I’m sure you’re correct in that we’re thinking about slightly different things!

  9. Jermayn Parker

    I like this!
    Previously I would have used separate images to create the roll over image effect but this is nicer as it only uses extra css code instead of extra images.

  10. Peter

    I have this code, it works in firefox but in IE6 and IE7 the buttons are displayed BELOW eachother instead of NEXT TO eachother…how can I fix this?

    #messagesender {
    clear:both;
    list-style:none;
    list-style-type:none;
    }

    #messagesender a {
    color: #CCC;
    text-decoration: none;
    }
    #messagesender a:hover {
    color: #666;
    }

    #messagesender span {
    background: url(/images/buttons.gif);
    float: left;
    width: 16px;
    height: 16px;
    margin: 3px 5px 0 0;
    }

    #messagesender-button-bold span {
    background-position: 0px 0px;
    }
    #messagesender-button-bold a:hover span {
    background-position: 0px -16px;
    cursor:pointer;
    }

    #messagesender-button-italic span {
    background-position: -16px 0px;
    }
    #messagesender-button-italic a:hover span {
    background-position: -16px -16px;
    cursor:pointer;
    }

    Thanks!
    Peter