Nov
20
CSS Image Sprites Tutorial - Create Multiple Buttons With Rollovers
One of the good things about CSS is that there are always different ways to complete a certain task. Wether it be getting your background to display correctly with a pattern or getting nice rollovers on your buttons. We will talk about the latter today, or whatever day you read this counts too. We are going to follow this step by step tutorial (which hopefully makes sense to more than just me) to recreate the list of social media buttons in the footer of our site.
Creating the Image Rollover
Here is the image before we create the rollover.
And here is the after, same image re-sliced but with the colors darkened on the buttons.
Now we take the two images in Photoshop and have to combine them to make our image for the sprite. Keep the original on the left side and the rollover on the right. Make sure the image is exactly twice the width of the original. The easiest way to do this is take the original image in Photoshop, go to Image > Canvas Size… We want to anchor the resizing to the left side of the image and set it to 200%.
Our image is now looking like this, the original image on the left and the right 50% is blank.
Now turn the Snap setting on and drag the rollover image onto the blank half of the new image. Make sure it aligns correctly or you will have weird measurements. Our image is now looking like this, original on the left and the rollover on the right side.
Now save it out for the web, you can choose png or jpg, its up to you. I chose jpg because I’m nostalgic. Don’t hate the pixelation. Pretend it’s nintendo.
Image Sprites - The HTML
Now that we have our sweet image it’s time to break out some good ol’ CSS. First thing we need to do is set up the unordered list in the HTML with each of the items we want to link to. If I had a lot of links I would go with a naming convention like: social-01, social-02, social-03 etc. But since I only have 5 I will give each list item it’s own id based on the name of the link.
Ok, so what we have above is an unordered list that has an id of social with five list items in it. Each list item has a unique id so I will be able to control that specific li when I am laying out my links. Inside the li’s contains a link going to wherever I want to send it. Each link has a nofollow tag inside because these are sites that I choose not to send any link love to. I will explain why there is a span tag later. On the inside of the span tag put the text that is on the button, make sure it matches the text because if we hide it and Google finds out you are being sneaky sneaky you could get penalized. Or punched in the face.
Image Sprites - The CSS
Without any CSS, our list is starting to look like this:
That list is ugly. Don’t lie. Now it’s time to beautify it by adding a little bit of Cascading Style Sheet razzle dazzle.
Why does he keep saying razzle dazzle?
I don’t know. But read on, we are starting to get somewhere.
Styling the Unordered List
Like any other project, I believe that it is best to work from the largest parts of the document to the inside smaller ones. So we start by styling the ul first. Lets take the image we made earlier with the normal and hover states combined and turn it into the background image of the ul.
#social {
background:url("img/social_btns.jpg") 0 0 no-repeat;
width:113px;
height:202px;
margin:0;
padding:0;
}
With that piece of code my ul now has the background image of the non-hover state (the left side) of the image we created earlier. We set the width and height of the ul to the width/height of the SINGLE image we created, before the rollover was added to create the sprite. It looks like this:
Styling the List Items and Links
Now that we have a background for the ul it’s time we styled the list items and links. Each link and list item is the same size (because the buttons are all the same size,) and have equal spacing in between them. In Photoshop I have used my ruler to see that each button is 34px high, 113px wide, and all except the bottom link have 8px of space on the bottom.
This is also the time when the span tag comes in, I will set anything that is in the list between a span tag to display: none so it disappears and we still have the link that we created. Here is the CSS we are adding.
#social li span { display: none; }
#social li { float:left; list-style:none; position:relative; }
#social li, #social a {
height:34px; /* Each button must have the same height, define it here */
display:block;
margin:0;
padding:0;
}
li#linked-in, li#twitter, li#facebook, li#digg, li#stumble { margin-bottom:8px; width:113px; }
li#stumble { margin:0; }
With that our list is looking good finally, but it still doesn’t have hover states. You can see the current demo of it here. If you hover over the images you can see that there are no hover states, but in the bottom corner of the browser the correct link hrefs are showing up. This is good. We are almost ready to step into actually creating the sprite. Never mind we are ready, what an early Christmas present this is.
Creating the Image Sprite Hover States with CSS
Now that we have our list laid out with images showing, its time to give each of the links a hover state. The way the sprite will work is that we will tell that specific link to have a hover state, the hover state will be using the SAME image as the UL that we created earlier, but we will use CSS to make the correct part of the image show on the hover.
When a background image is displayed it always starts from the coordinates 0,0; or the top left corner. So what we have to do is tell the link to display the background image, but then use CSS to shift the coordinates so it displays the rollover part of the image. So we will have the statement of the background, then tell it to position it however many pixels it is so the background is in the right spot. Since it is 113px wide we will take it -113px horizontally, and depending on where the button is subtract how far we want it to go down.
Here is the CSS for the hover states which we add right below the previous block.
#linked-in a:hover { background:url("img/social_btns.jpg") -113px -0px no-repeat; }
#twitter a:hover { background:url("img/social_btns.jpg") -113px -42px no-repeat; }
#facebook a:hover { background:url("img/social_btns.jpg") -113px -84px no-repeat; }
#digg a:hover { background:url("img/social_btns.jpg") -113px -126px no-repeat; }
#stumble a:hover { background:url("img/social_btns.jpg") -113px -168px no-repeat; }
I measured the numbers like this:
Each arrow represents a measurement that I made to see where I should set the background position. After that we’re finished! The final version can be seen in the footer or here.
Questions or comments can be posted below and I will try to answer them as quickly as possible.








matthew booth Says:
Nov 20
8:45 pm
Instead of using span {display:none;} you can just use text-indent:-9999em; that way the text is still accessible.
That’s the way I do it, not sure if it matters or if it is better… slightly less markup that way too.
Lightpost Creative Says:
Nov 20
2:41 am
@Matt
I have used that method but it doesn’t work when people use images off, CSS on. Which is more common than screen readers as far as I’ve read, so the accessibility is essentially the same.
Kim Says:
Nov 20
9:13 pm
heh, display:none won’t work with CSS on/images off either
Good intro tutorial on sprites btw - not only worth doing for rollovers, but great for reducing total number of http requests as well.
digg.com use a huge sprite containing a bunch of images: 200×1600 pixels and only 5KB:
http://digg.com/img/menu-current.gif
Another idea, rather than setting this everywhere:
#linked-in a:hover { background:url(”img/social_btns.jpg”) -113px -0px no-repeat; }
try:
#social a {background:url(”img/social_btns.jpg”) no-repeat 0 0}
#linked-in a {background-position:0 0}
#linked-in a:hover {background-position:-113px 0}
#twitter a {background-position:0 -42px}
#twitter a:hover {background-position:-113px -42px}
i.e. generically apply the same BG image to all ‘ a’ elements in the list, and just change the BG position using the specific ids - makes it easier to update the filename if it’s only referenced in one place.
Hopefully makes sense! (had a beer or two:)
zigi Says:
Nov 20
1:07 am
Hi,
Is there a way to apply a:active on sprites? I don’t get it to work
Thx
Lightpost Creative Says:
Nov 20
1:35 am
@zigi
Unfortunately, a:active does not work with this method. If you are looking to create a navigation with this method and you want the current page highlighted, you can go about it by using a < body> ID and doing something like this:
body#about-us li#about a {background-position:0 -42px}
and so on with your other pages.
David Hucklesby Says:
Nov 20
9:17 am
@Lightpost Creative -
If zigi means what he says - an active state that shows a third image while the mouse button is down - then this method works brilliantly. Just provide another column of images for the active state and give a rule for :active that shifts the first (x) position further left.
I suggest adding the :focus selector to the :hover selector for that rule, so that keyboard users get the change of state too. Viz: #stumble a:hover, #stumble a:focus { … }
On the other hand, if you want a “you are here” indication and have access to the markup, you could replace the A tag with STRONG and style it the way you suggest.
Lightpost Creative Says:
Nov 20
11:46 am
@David Hucklesby -
I stand corrected! When I wrote that, I had even forgotten the fact that I’ve done exactly what you described once before. You are indeed right, it works beautifully when you add a third column of states for the sprite.
zigi Says:
Nov 20
6:22 am
People !
Thx for your advise, I will try the third column way
Hope it works, as I need it also for Buttons
Cheers,
Ziv
Shoghon Says:
Nov 20
8:57 am
FYI- It is advised by Google to just eliminate the text altogether in Image links. Simple use the alt tag in the image to describe the link.
Lightpost Creative Says:
Nov 20
12:49 pm
@Shoghon - Do you know where Google said that? That doesn’t exactly work for Image Sprites though since it is just a background image, not an img tag in the link.
Raymond Selda Says:
Nov 20
9:40 am
Really nice CSS tutorial using sprites. Thank you.
Franky Says:
Nov 20
8:16 am
This is a great tutorial but why can’t anyone ever write one for horizontal images?
Gaillen Says:
Nov 20
8:46 pm
Franky you could try this tutorial
http://www.oscaralexander.com/tutorials/how-to-make-sexy-buttons-with-css.html
Lightpost Creative Says:
Nov 20
8:51 pm
@Franky
The same method applies. Instead of stacking images next to each other, stack images on top of one another. Then when you do the rollovers, all you have to do is change the Y position, instead of the X position.
migaber Says:
Nov 20
10:29 am
nice tutorial I do it ,it is very useful thanks alot
Steve Yakoban Says:
Nov 20
8:49 am
This is a clean and simple method in a clear tutorial. Thank you for it!
One issue I wish you would address: how to make it work using different width buttons. The trend to more organic designs is causing some nav buttons to vary in look, size, and width. If this method is used, dead space around shorter buttons becomes clickable and that’s not cool. How can this be changed for short and long buttons with no clickable dead space?
tai Says:
Nov 20
11:27 am
yea, what steve said. different width buttons.
David | WebModia Says:
Nov 20
3:31 am
Stumbled here, just thought I’d chime in on the earlier comments regarding making this more accessible.
Definitely DO NOT use display:none - that is 100% non-accessible.
The offset text approach does indeed have the other disadvantage of leaving the text off screen if the viewer has CSS on but images off (a fringe case scenario but certainly possible).
So, the most robust CSS sprite / image replacement method is what is commonly called Gilder/Levin - Not sure if html will work in your comments so I’ll try to describe it:
1. Rather than wrap the link text in a span, put an empty element *after* the link text but still within the anchor element. I use an ‘em’ or even an ‘i’ tag b/c they are smallest (every byte counts). There’s no semantic meaning but it is a minor tradeoff.
2. Apply ‘position:relative’ to anchors, and ‘position:absolute’ to the empty ‘i’ element.
3. Basically, the idea is to position the ‘i’ over the anchor - applying appropriate positioning values, width, height, display:block… essentially, cover the anchor with the ‘i’.
4. Apply the sprite image to the ‘i’ element as bg image, with appropriate background positions for the individual links and their respective link states. You’ll need to give each link a unique ID to target them.
This method is demo’ed (a variation but basic idea) over on mezzoblue.com - google search his site for “Revised Image Replacement” if the direct link doesn’t come through here: http://www.mezzoblue.com/tests/revised-image-replacement/
I use this method for just about every link and header that requires image replacement. The only shortcoming other than the semantically meaningless ‘i’ (or ‘em’ or ’span’ - whatever you like) is that bg image needs to have no transparency - if that’s a problem, then fallback to Phark.
Josh Bock Says:
Nov 20
6:22 am
I am having some issues creating my own version of this using my own graphics. I have followed every step word for word but I can not get my images to act like buttons. I am at the step right before you add the hover the state. My image is a gif, and I have also tried a png image. I am at a lost at the moment on how to fix this. Any help will be greatly appreciated.
Debbie Says:
Nov 20
11:26 am
Thanks for this tutorial! This was something new, so I was looking for a tutorial that it explained all of the CSS. I had tried out another tutorial that left me confused and with a mess. Your version actually taught me what I was trying to do so that I was able to make a modification to work with what I was trying to do. So much easier when someone explains it well and you actually learn instead of just copying. Thanks again!
John Says:
Nov 20
6:52 pm
Thanks for this tutorial!!!! Best one I’ve found. Had to make a few adjustments seeing my sprite was for a horizontal row of images. None the less, your tutorial gave it the backbone it needed.
five stars!!
Jamal Says:
Nov 20
1:56 pm
I just can’t get it to work for some reason. Here is a link to it, http://www.5alarmint.com/tsa. Can someone tell me what I did wrong?