CSS Sprites: Image Slicing’s Kiss of Death

Back when video games were still fun (we’re talking about the 8-bit glory days here),
graphics were a much simpler matter by necessity. Bitmapped 2-dimensional character data
and background scenery was individually drawn, much like today’s resurgent pixel art.
Hundreds and later thousands of small graphics called sprites were the building blocks
for all things visual in a game.

Article Continues Below

As game complexity increased, techniques developed to manage the multitude of sprites
while keeping game play flowing. One variation saw sprites being plugged into a master
grid, then later pulled out as needed by code that mapped positions of each individual
graphic, and selectively painted them on the screen.

example sprites

And what does this have to do with the web?#section1

Everything old is new again, and though the rise of 3D games has made sprite maps
obsolete, the concurrent rise of mobile devices with 2D gaming capabilities
have brought them back into vogue. And now, with a bit of math and a lot of CSS,
we’re going to take the basic concept and apply it to the world of web design.

Specifically, we’re going to replace old-school image slicing and dicing (and the
necessary JavaScript) with a CSS solution. And because of the way CSS works, we’re
going to take it further: by building a grid of images and devising a way to get each
individual cell out of the grid, we can store all buttons/navigation items/whatever we wish
in a single master image file, along with the associated “before” and “after” link states.

How do CSS Sprites work?#section2

As it turns out, the basic tools to do this are built into CSS, given a bit of creative

Let’s start with the master image itself. Dividing a rectangle into four items, you’ll
observe in this master image that our intended “before” link
images are on the top row, with “after” :hover states immediately below. There’s
no clear division between the four links at the moment, so imagine that each piece of text is
a link for now. (For the sake of simplicity, we’ll continue to refer to link images as
“before” images and the :hover state as “after” for the rest of this article.
It’s possible to extend this method to :active, :focus, and
:visited links states as well, but we won’t go into that here.)

Those familiar with Petr Stanicek’s (Pixy)
Fast Rollovers may
already see where we’re going with this. This article owes a debt of gratitude to Pixy’s
example for the basic function we’ll be relying on. But let’s not get ahead of ourselves.

On to the HTML. Every good CSS trick strives to add a layer of visuals on top of a clean
block of code, and this technique is no exception:

<ul id="skyline">
    <li id="panel1b"><a href="#1"></a></li>
    <li id="panel2b"><a href="#2"></a></li>
    <li id="panel3b"><a href="#3"></a></li>
    <li id="panel4b"><a href="#4"></a></li>

This code will serve as a base for our example. Light-weight, simple markup that degrades
well in older and CSS-disabled browsers is all the rage, and it’s a trend that’s good for the
industry. It’s a great ideal to shoot for. (We’ll ignore any text inside the links for the
time being. Apply your favorite
image replacement
later to hide the text you’ll end up adding.)

Applying the CSS#section3

With those basic building blocks, it’s time to build the CSS. A quick note before we
start — because of an IE glitch, we’ll be tiling the after image on top of the before image when we need it, instead of replacing one with the other. The result makes
no real visual difference if we line them up precisely, but this method avoids what
otherwise would be an obvious “flicker” effect that we don’t want.

#skyline {
    width: 400px; height: 200px;
    background: url(test-3.jpg);
    margin: 10px auto; padding: 0;
    position: relative;}
  #skyline li {
    margin: 0; padding: 0; list-style: none;
    position: absolute; top: 0;}
  #skyline li, #skyline a {
    height: 200px; display: block;}

Counter-intuitively, we’re not assigning the before image to the links at all, it’s applied
to the <ul> instead. You’ll see why in a moment.

The rest of the CSS in the above example sets things like the dimensions of the #skyline
block and the list items, starting positions for the list items, and it turns off the
unwanted list bullets.

We’ll be leaving the links themselves as empty, transparent blocks (though with specific
dimensions) to trigger the link activity, and position them using the containing
<li>s. If we were to position the links themselves and effectively ignore
the <li>s, we’d start seeing errors in older browsers, so let’s avoid

Positioning the links#section4

The <li>s are absolutely positioned, so why aren’t they at the top of the browser
window? A quirky but useful property of positioned elements is that all descendent elements contained within them base their absolute position not off the corners of the browser window, but off the corners of the nearest positioned ancestor element.The upshot of this is that since we applied
position: relative; to #skyline, we’re able to absolutely position the
<li>s from the top left corner of #skyline itself.

#panel1b {left: 0; width: 95px;}
  #panel2b {left: 96px; width: 75px;}
  #panel3b {left: 172px; width: 110px;}
  #panel4b {left: 283px; width: 117px;}

So #panel1 isn’t horizontally positioned at all, #panel2b is positioned 96px to the left of
#skyline’s left edge, and so on. We assigned the links a display: block; value
and the same height as the <li>s in the past listing, so they’ll end up
filling their containing <li>s, which is exactly what we want.

At this point we have a basic image map with links, but no :hover states.
See the example. It’s probably easier to see what’s happening
with borders turned on.


In the past we would have applied some JavaScript to swap in a new image for the after
state. Instead our after states are in one image, so all we need is a way
to selectively pull each state out for the appropriate link.

If we apply the master image to the :hover state without additional values,
we make only the top left corner visible — not what we want, though clipped by the link
area, which is what we want. We need to move the position of the image somehow.

We’re dealing with known pixel values; a little bit of math should enable us to offset
that background image enough both vertically and horizontally so that only the piece
containing the after state shows.

That’s exactly what we’ll do:

#panel1b a:hover {
    background: transparent url(test-3.jpg)
    0 -200px no-repeat;}
  #panel2b a:hover {
    background: transparent url(test-3.jpg)
    -96px -200px no-repeat;}
  #panel3b a:hover {
    background: transparent url(test-3.jpg)
    -172px -200px no-repeat;}
  #panel4b a:hover {
    background: transparent url(test-3.jpg)
    -283px -200px no-repeat;}

Where did we get those pixel values? Let’s break it down: the first value is of course
the horizontal offset (from the left edge), and the second is the vertical.

Each vertical value is equal; since the master image is 400 pixels high and the after
states sit in the bottom half, we’ve simply divided the height. Shifting the whole background
image up by 200px requires us to apply the value as a negative number. Think of the top
edge of the link as the starting point, or 0. To position the background image 200 pixels
above this point, it makes sense to move the starting point -200px.

Likewise, if the left edge of each link is effectively 0, we’ll need to offset the
background image horizontally by the width of all <li>s prior to the one
we’re working with. So the first link doesn’t require an offset, since there are no pixels
before its horizontal starting point. The second link requires an offset the width of the
first, the third link requires an offset of the combined width of the first two links, and
the last requires an offset of the combined width of all three previous links.

It’s a bit cumbersome to explain the process, but playing around with the values will
quickly show you how the offsets work, and once you’re familiar it’s not all that hard to

So there you have it. Single-image CSS rollovers, degradable
to a simple unordered list.


There’s no reason why we have to leave the links touching each other, side-by-side as they
were in the previous example. Image maps may be convenient in some spots, but what about
separating each link into its own stand-alone button? That way we can add borders and
margins, let the underlying background show through, and generally treat them as separately
as we need to.

In fact, the building blocks are already in place. We really don’t need to
modify our code too radically; the main change is in creating a new background image that
doesn’t continue from link to link like the last example did. Since we can’t rely on the
<ul> for placing the original background image, we’ll end up
applying it to all <li>s instead and offsetting each the same way we
offset the after states in the prior example.

With an appropriate image and a bit of spacing between each
<li>, we’ve got buttons.

Note that in this example we’ve added 1px borders which, of course, count toward the final
width of the links. This affects our offset values; we’ve compensated by adding 2px to the
offsets where appropriate.

Irregular shapes#section7

Up till now we’ve focused only on rectangular, non-overlapping shapes. What about the more
complex image maps that image slicers like Fireworks and ImageReady export so easily? Relax,
we’ve got you covered there too.

We’ll start the same way as the first example, by applying the background image to the
<ul> and turning off list item bullets and setting widths and so forth.
The big difference is where we position the <li>s; the goal is to
surround each graphical element with a box that tightly hugs the

Again, because of the ability to use absolute positioning relative to the top left corner
of the <ul>, we’re able to precisely place our links exactly where we want them. Now
all that’s left is to set up the hover states.

Worth noting is that in this case, a single set of before and after images wasn’t enough.
Because of the overlapping objects, relying on only one after state would show pieces of
surrounding objects’ after states. In fact, it would show precisely the pieces that fall
within the link’s borders. (Easiest to just see it in action.)

How to avoid this? By adding a second after state, and carefully selecting which objects go
where. The master image in this case has split the purple and blue
objects into the first after state, and the green, orange and yellow objects into the second.
This order allows boxes to be drawn around each object’s after state without including
pieces of the surrounding objects. And the illusion is complete.

Benefits and pitfalls#section8

A couple of final thoughts. Our new CSS Sprite method tests well in most modern browsers.
The notable exception is Opera 6, which doesn’t apply a background image on link hover states.
Why, we’re not sure, but it means that our hovers don’t work. The links still do, and if
they’ve been labeled properly, the net result will be a static, but usable image map in
Opera 6. We’re willing to live with that, especially now that Opera 7 has been around for a

The other concern is familiar to anyone who has spent time with
FIR. In the rare cases in which users
have turned off images in their browsers but retained CSS, a big empty hole will appear
in the page where we expect our images to be placed. The links are still there and clickable,
but nothing visually appears. At press time, there was no known way around this.

Then there’s file size. The natural tendency is to assume that a full double-sized image must be heavier than a
similar set of sliced images, since the overall image area will usually be larger. All image
formats have a certain amount of overhead though (which is why a 1px by 1px white GIF
saves to around 50 bytes), and the more slices you have, the more quickly that overhead adds up.
Plus, one master image requires only a single color table when using a GIF, but each slice
would need its own. Preliminary tests suggest that all this indicates smaller total file
sizes for CSS Sprites, or at the very least not appreciably larger sizes.

And lastly, let’s not forget that our markup is nice and clean, with all the advantages that go
along with that. HTML lists degrade wonderfully, and a proper image replacement technique
will leave the text links accessible to screenreaders. Replacing the sprite imagery is dead
simple, since all of our dimensions and offsets are controlled in a single CSS file, and all
of our imagery sits in a single image.

184 Reader Comments

  1. I’m constantly surprised at the ways in which CSS can be manipulated to great visual effect. It takes people like Dave, Doug, Søren, et al, to keep that CSS cutting edge as sharp as it is. Excellent work.

  2. Genius!

    (The final green shape needs a tweak though. When hovering in Mozilla 1.5 on XP, the neighbouring grey shape edges out a touch.)

    The introduction to this article reminded me of Boulderdash on the Commodore 64. That early games computer had several character grids you could hold in memory. Boulderdash cleverly switched between these several times every second to give the effect of animation. I once looked into the code and saw an earlier abandoned character set, with much cruder designs. Why is this important? Er, it’s not, but I thought I’d mention it.

    Also the Commodore had built-in hardware sprites, which floated over the main character data used to make a screen. If only we had those in CSS…

  3. The 2 separate active maps for the overlapping shapes is one of those now obvious, simple ideas I wouldn’t have thought of. Thanks for saving the headache.

    As Chris Hester above said, the left green crescent is a bit off (tested in both Firefox and IE6). Not sure at first glance whether it’s a positioning or a graphics problem.

    Also, to nitpick, a slight advantage to saving individual rollovers for graphics (at least in GIF form) is the ability for each image to have it’s own set of 256 colors. It’s not unlikely, given sufficiently colorful images, that the 256 color limitation involved in placing all active and non-active states for multiple buttons in one GIF could visually degrade the overall effect.

  4. I think the best part about this is the ability to degrade on non-CSS browsers, as the images themselves are merely list items.

    Aaah, behold the power of unordered lists!

  5. Ofcourse, using one image cuts down the number of http requests to the server, for each image.

    In some cases i would expect that this would make up for an increase in file size.

    I can think of several places i have used 10+ gif icons, which would probably have been faster as one image positoned using css

  6. Nice write up with some good examples. Thanks Dave.

    This basic idea had occurred to me a while ago for just the reason that Dave Marks mentions in his comment above. I was going to demonstrate it by doing Amazon’s nav bar in CSS with one master image. Needless to say, I didn’t get round to it. Such a simple nav bar lends itself perfectly to this technique.

    I have seen this technique (or a variation of it) in use already:


    However, it breaks if you resize the text – so you need to stick to images.

  7. Good, well written, expansion on a well known technique, and as already pointed out, your demonstration shows good examples.

    In regard to single image vs lots of images…
    1) As already mentioned there will be some memory saved by combining images that share the same pallet.
    2) In particular, GIF images can store long solid-colour horizontal lines in very small memory space.
    3) Splitting in to many images allows most peoples web browsers to download them faster because they can be downloaded simultanseously (only helps of fast connections).
    4) I may have missed it in the article, but I don’t think you mentioned the main reason for having a single image, is if you had a different ‘after’ image, it would not start downloading intil you hover over it, (So putting the before and after images in a single file removes the need for a JavaScript ‘pre-loader’).

    Here’s another example of this technique in use: http://www.alpha-matrix-design.co.uk
    I’d welcome comments and constructive criticism, but direct it to me not to this discussion board.

  8. Yet again, I am blown away by the amazing power of CSS. Thank you for illuminating this technique. I am sure there are many who will find amazing ways to use this.

  9. I checked out the example with the skyline and nothing happened. Maybe a settings issue?

  10. Thanks all for the feedback so far!

    To those experiencing browser discrepencies — it’s possibly related to cache. If you’ve configured your browser to ‘Check for new page every time’ or similar, it may be trying to re-download the image for every hover. Leave your mouse over the link a bit longer, give it a chance to show up, and it should.

    Also keep in mind that this is mostly a developer setting. End users won’t usually have this selected, so you needn’t worry about it too much.

  11. A number of folks mention that this technique degrades nicely. When people say as such, are they including browsers like Netscape 4.x?

    I am just curious because this technique doesn’t degrade well at all with Netscape 4.79.

    I’m still learning and justed wanted some clarification in this regard. Thanks.

  12. Great work Dave. Well-written, great examples, everything in there was extremely well done.

    I’ll definitely be saving this article for future use. The irregular shapes will come in handy some day – not sure when, but it’s only a matter of time. 🙂

  13. I’ve seen Pixy’s hover technique, and I’ve built a couple sprite engines in my lifetime. I don’t know why this didn’t occur to me. Very cool.

    I can imagine several uses for this other than hover effects… I’ll try a few things and see what I come up with.

  14. Along with Doug Bowman’s sliding doors article, easily the best thing I’ve read on here since the relaunch. I look forwards to your next article.

    I definately plan to use this on the new lastfield site to replace the highlighting UK map we use on our contact page.

  15. For Jason. M…

    Perhaps they don’t appear to be degrading well as Dave hasn’t put the list text in any of his examples? If the text was there, then you would see a fine unordered list, or at least you should be able to.

    Perhaps Dave would consider adding list text to his final examples to demonstrate how it degrades?

  16. [quote]The big difference is where we position the

  17. s; the goal is to surround each graphical element with a box that tightly hugs the edges.[/quote]

    I’m surprised that things don’t fall apart when you mouse over a place where two boxes overlap!

    Any idea why this works? Could it be that if it’s not clear which box you want, the browser simply does nothing?

    Very nice!

  18. Here’s a test case with actual text in each link for the benefit of testing in NN4.x. Note that I’ve used Phark image replacement here, which doesn’t work in IE5.

    “I’m surprised that things don’t fall apart when you mouse over a place where two boxes overlap!”

    Whichever link has a higher z-index gets priority — so in a corner where two boxes overlap, in this case the one that appears later in the source code is the one that gets triggered, and the other is ignored. You can pick and choose which links get priority by explicitly setting a z-index value, but I decided to just let them fight it out in my examples.

  19. Damn, doesn’t seem to work fully in Mozilla 1.6 on XP. (I used 1.5 before.) The two examples, one with “borders turned on”, do nothing. Yet the final “So there you have it” version does work!

    Same result in Firefox 0.8.

  20. I’ve done something alike with javascript mouse-overs and not slicing the images up, but I never seen it done with CSS before.

    Eric Meyer’s famous spiralling shelve demo springs to mind, but this one actually works in IE!

    One mayor plus using larger images is that once the two images are loaded, the caching of the images make the rollovers fast, while pages with a lot of sliced up images tend to have a small delay.

  21. Chris — the examples you cited weren’t meant to work at that point in the narrative; only the final examples in each section are fully functioning with mouseovers.

    Martijn — funny you should mention the Complex Spiral, I considered rebuilding it with background-image positioning for this article, but decided that was too much of a tangent. I think it can be done, it just wouldn’t end up fixed-position.

  22. I’ll just add to the compliments, I really like your code, its very clean and elegant and it degrades nicely.


  23. Great article, it lacks a bit in code originality, since it uses lot of the latest articles’ code (Image maps, rollovers, FIR, etc), but it certainly gives users a lot of ideas and code examples. It’s what everyone who reads ALA has been thinking of doing once, but never came round to. A really useful reference, definately a keeper.

    “I think it can be done, it just wouldn’t end up fixed-position.”

    Wouldn’t you just use the combination of these two rules:

    background-attachment: fixed;
    background-position: -10px -20px; (example values)

  24. I see no obvious reason why buttons like in the icon example couldn’t be spread across the content. Not that doing such is a good idea from a usability standpoint, but you could make even 2 different sets of buttons and still use the one master image idea, right? You’d just have to reposition accordingly.

    Gifs were used in the example but as long as the individual images were kept small is there any particular reason to avoid jpgs? My thinking here is I’m currently building a site that will have several photo galleries of about 12 thumbnails each. If I want to go with a rollover effect for each thumbnail (say a sepia toned image and a full color image), would the bandwidth benifits of this technique still apply to the use of jpgs? Again, I don’t see any obvious reason that it wouldn’t, but I’ve learned not to assume too much.

  25. Anyways, blobs! Awesome article, it’s always the simplest things we stumble across which end up being the most useful.

  26. really, this article just amazes me how with some little ideas you can make them more applicable in various ways.

  27. I have been using this method for my nav links for a while and it works wonderfully.

    I never thought of using it for irregular shapes in that manner.

    Great work!

    I always love to have a great place to point questions on this subject too.

  28. as each image must be verified before download. Could save quite a bit of time for many icons or images.

  29. Why does everyone use LIs when they are not neccessary? It’s extra markup for no reason!

    Because, if we’re talking about navigational links, they *are* a list…A list of links. A list is a list is a list, whether it’s a grocery list, top ten list, or list of links.

    Not to mention, by marking up your links as a list, it gives *incredible* flexibility if/when you wish to change the layout of your site. Want your nav running vertical down the side? No problem…just change the CSS. Want the nav to display horizontally across the top? Cool…change the CSS.

    If you’re so worried about an extra LI around each link, I think you need a new hobby.

    (Not sure why I’m taking the bait…)

    Anyway, great *useful* article Dave. Most of us appreciate it.

  30. You have a way of thinking out of the box (no pun intended) that is very refreshing.

    Yesterday, in your mezzoblue post, you showed us that by leaving out the left and top properties in a positioned element you can effectively place an absolutely positioned block in the normal flow of the document. This article illustrates how it can be used to great effect when your child elements can be positioned inside their parent element – a positioned parent element that is still inside the normal flow of the document.

    I always thought that you either use float positioning or absolute, and that mixing the two were impossible. With this technique you have demonstrated whole other worlds of possibilities. I think this is the real innovation of the article. Your rollover examples are only one application of many to come.

  31. Dave: the NN4 version you linked in the comments leaves blue lines stretched across the page from the left margin in Firefox 0.8 under Win98. Not seeing any of the problems other people encountered.

  32. To Dave:

    Wonderful technique. I had come up with a layout that was going to need something like this just a couple of days ago – Perfect timing!

    To Dante-Cubed:
    If you’re so concerned with the “serious questions”, and you can’t keep from reading ALA, why don’t YOU write an article about what you think is important?

    Complaining does nothing more than irritate the rest of us. As a previous commenter said – “If you don’t like it, why are you here?”

    Rather than complain, contribute.

  33. …but since no-one has suggested it, what the hell. Could one large image file be used to replace all the seperate images for a page and lead to quicker loading?

  34. David Shea, you’ve done a heck of a lot to legitimize CSS for graphic designers and given me a ton of inspiration. You are just plain awesome. I can’t wait to test out this method.

  35. Yeah. They’re there for a reason: I wanted the square bullets. I was talking about using lists for no reason at all. I have a reason.

    “you need a new hobby”

    What is that supposed to mean? I have far too many: Musician, writer, historian, web developer.

    I tried contributing. Didn’t work. ALA would never publish me. That’s why I stick to what I’m good at: San Francisco History.

  36. Derek — definitely. You could build thirty different sets of buttons on one page and have them all draw from the same master image (though if you’re trying to construct thirty sets of buttons you might wish to re-evaluate your strategy). No reason to avoid JPG or PNG, any image format should work fine. Actually, Skyline (the first example in the article) makes use of JPG. Your particular example would be an interesting case study; JPG compression works a little differently, but you might still see enough savings in overhead to justify it.

    GIF does run into limitations when you try to cram a whole bunch of differently-coloured images into the same master image; you can tell on the blob example, even though it’s 256 colours. Just something to keep in mind; JPG might be preferable sometimes. This is one area where old-school slicing and dicing has a leg up, at the expense of the multiple colour tables.

    Terry — the positioning trick is just a feature of CSS, has been for ages. Though I have to admit, I’ve known about it for a while but never actually used it to my advantage until recently; it was a quirk more than a feature until I really understood it.

    Subrisi — I thought about that for a bit. As long as you’re trying to fit your sprite inside very specifically-dimensioned containers, then yep, you should be able to do it. But in practice you’ll probably find it doesn’t make much sense; a larger container will cause the other bits and pieces of the master image surrounding your sprite to poke through. Might be an interesting experiment though…

    rgw — What can I say? Thank you! (and thank you everyone else providing useful feedback.)

  37. Image maps are really neat. Maybe I’m just a newbie to CSS, but why is the background set to transparent? Thanks!

  38. Dante-Cubed wrote:
    They’re there for a reason: I wanted the square bullets. I was talking about using lists for no reason at all. I have a reason.
    < << I hope you're joking. But in case not: You don't use lists simply because you want square bullets. You use lists when what you're dealing with actually IS a list. A list of links is, by definition, a list. Sure, using

  39. :s because you want the square bullets is a reason, but it’s not a good reason. You might as well say “I’m using them because the pope has 215 purplegreen anecdotes stuffed in his seventh kneecap on damp and lonely thursdays”. 😉

  40. I have to say this is absolutlely brilliant. Thanks Dave, you have once again proven your abillity to craft new ways to use old ideas… This will no doubt become common practice among CSS developers for years to come.

  41. Jemal:
    “Dave: the NN4 version you linked in the comments leaves blue lines stretched across the page from the left margin in Firefox 0.8 under Win98. Not seeing any of the problems other people encountered.”

    a {
    text-decoration: none;

    should fix that.

  42. Dave, you just plain rock.

    There are so many CSS-relatd sites I wish I had time to read… Still, ALA and Mezzo do sit on top of the list, and this kind of article makes the “why” of that obvious.


  43. I actually ran across this technique while reading a Danny Goodman DHTML article in 2000, though he used JavaScript rather than CSS. After Zeldman implemented the Fahrner Image Replacement on the Daily Report, I got to messing about with combining the techniques as Mr. Shea has done.

    While I never actually finished my explorations (testing/hacking in Opera and IE/Win and a multitude of small variations on the basic principal created a black hole), some of the ideas that came out of the experiments included:

    — using an animated GIF for the :hover state

    — adding additional :visited and :active states for the buttons

    — including a ‘current page’ state to show the user where they were in the site

    — using one image per link (rather than one image per state) to increase positioning flexibility

    — using an acutal image within the and positioning that (rather than a background image) within a block-level element with overflow: hidden, so that visitors with images disabled but CSS enabled would have alt text available

    — using a single-pixel transparent GIF (horror!) sized with CSS to get the alt text if images were off but CSS was on, and a span with a display of none to provide text if images were on and CSS off/unsupported; the obvious drawback is that screen readers will read the link text twice, which is unseemly but perhaps preferable to having the links entirely hidden to users with images off but CSS on

  44. I know. I would have used display: list-item, but IE 5x doesn’t support it, and it was just as complicated. I decided not to bother, and used lists.

  45. Thanks for posting that article! It’s pure genius!

    For a while I wanted to have an image map where the images were separate from each other, but until now I had no idea how to do it.

    I’ve changed the navigation on my website so it uses this sprite system, but I’ve made a few changes. In case you were wondering, I got the hover images to work in Opera using a bit of JavaScript. It’s a little bit bigger, but it works for me!

    If you want to see it, please check out my homepage: http://www.boxofjunk.net/

    Again, this article is excellent!

  46. <script type="text/javascript">
    //Powered by DCScript
    function zebra() {
    var node = document.getElementById("zebra");
    var tds = node.firstChild.firstChild.childNodes;
    for (var i=0;i

    Change the ID and the colors (or the onload bit). Correct me if this script is wrong. This was my initial thought has to how to create Zebra Tables. The firstChild.firstChild bit is for the TBODY tag (which is automatically generated by IE6).

  47. Ahh CSS you solve all of my woes. If it hasn’t been said before, I’ll say it again (and again and again): excellent article. Really ingenious utilization of CSS here — I immediately ran to my computer to make my own!
    I think trying it with animations would prove interesting…

    On an aside(sorry), I am wondering if anyone knows the url to a website that illustrates designing css layouts using colored in borders. I want to pass that along to a friend who could really use it. I think the site in question had a rose as an example graphic?

    In any case, everyone at ALA is doing a great job — thanks for feeding my brain with wonderful things :).

  48. Why don’t you just marry CSS, Dave Shea or A List Apart?

    Just kidding. Dave has done a lot of stuff with CSS. He’s done as much with CSS as PPK has with Javascript and the DOM.

  49. I love this technique, nicely mixing some others to create an easy to reuse one.

    There is a lot of power in the background positioning technique. Right now I am using it on my new portfolio site, and I use it for a rollover and highlight state of an icon rather than the nav itself.
    check the work in progress, I will write an explanation document for an internal DOM training.

  50. I really like the clean usefulness of this idea but I as well as several other designers use repeating backgrounds will this work with images that require patterning?

  51. I must say i’m super impressed by this technique.
    I’m learning css right now and designing a few webs sites. so i was wondering how i should slice my layout and implement nested div all over the place to make it work.

    But simplicity is always mother of reason.

    I tried to adapt this technique to my navigation bar, adding as well a piece of css to show the current page status ( like in the i3forum page ).Then i removed all the script for the slicing script in an external css. but now it’s not showing anymore.
    is there an issue if this technique is externalized ?

  52. I have tried something like this a while ago when i saw the fast image replacement but I tried using animated gifs which would work in everything but opera. for some reason it didn’t like using animated gifs as backgrounds.

  53. Ive used a similar was of doing this for a long time, to make my links Very SE friendly and to also reduce the amount of JavaScript used on a site…

    Well done dave on getting this method out into the open 🙂 summat i kept saying i would do but just never got round to doing so…

    If you would like to view my little way goto http://www.phunky.co.uk/2004/

  54. I’m using this teqnuiqe, plus some other stuff i figured out myself (positioning a little box somwhere else on the page on :hover), only using CSS, now it looks like the CSS is going to be very big for a very small page!

    What’s best to use? CSS or Javascript?

  55. Wasn’t finished writing, dumdumb me 😛

    The CSS is starting to grow well over 150 lines, only for this page: http://www.urbanturban.no/index.html (The new page is not uploaded yet).

    Is it better now, to do as it is done on the old page, use JS to show the “info images” on hover, or go with css?

  56. I have been playing around with this idea today but with no success. Is it possible to use this method to replace the image used to submit a form?

  57. And I’m the one being called immature.

    I agree with a lot of what PPK says. He’s seems to think (in some ways) like me. I don’t love him. I don’t agree with everything he says.

  58. Wonderful concept! It solves and simplifies a lot of issues I (and most likely many others) have had problems with.

    Dave, your example at http://www.mezzoblue.com/tests/sprites/blobs.html causes my Win/IE6 to have a delay of 2 to 3 seconds before showing the hover states. Mozilla’s doing it right though. And the skyline example in this article works fine in IE6. What could be the cause of this discrepancy?

    Dante-Cubed, please correspond directly with people with whom you want to quarrel on a more personal level. I’d encourage others to not respond to your baiting any more.

  59. i’ve slightly changed dave’s code to work with text within each of the sprite boxes. it works in ie6, ie5.5, moz on pc and safari and ie on osX. i’ve had to use the box model hack, which is kinda ugly… so if anyone has a better way of doing this, please let me know.


  60. Thank you Dave! I have been thinking about my nav for awile and was using separate images for each menu item. I’ve immediately implemented it on my subpages, and it works great. This thing really saves time when making alternative style sheets.

    Hypothetically, one could put almost all of the images used on a page into one jpeg, and then when it comes time to redesign / create new style, all that would be needed to be edited would be the master image (then a find/replace on the css).

    Keep writing this stuff; this is why I read ALA

  61. Avoiding a hack in that particular example would be easy, just add span tags around the links then replace the 20px padding-right in #sidemenu a with #sidemenu span a 20px margin instead. Fair enough, some designers would rather use a hack than ‘code-bloat’ but that’s down to personal preference.

  62. Well… thats about it really – Superb!

    I love this CSS stuff. Everytime I use it I’m filled with on overwhelming feeling of “doing it elegantly” instead of kludging it horribly. And this is one of the most elegant uses I’ve seen yet.

    First time I’ve found this website… brilliant… I shall definitely be exploring it further.

  63. In case of “CSS on and Images off” a good solution is Gilder/Levin Method mentioned here:http://www.mezzoblue.com/tests/revised-image-replacement/
    (yes with extra spans and no transparent images but i think it’s worth).

    Image flickering:
    When you use that technique the flickering is very annoying because the text become visible on every mouse over. So I have created a behavior to solve this issue. (The behavior is really simple, adds a new image between the text and the span (based on the CSS background-image absolute URL))

    (The page is in Hungarian but i hope you can understand the source code 🙂

    There is a another silly thing in IE. The mouseout doesnt chenges back the hover state of the span inside the link. We should add an extra a:hover {} rule beside the a:hover span{} and then everything works.

  64. In addition to the potential overall savings on filesize due to reduced overhead, there is also a performance benefit: only one trip to the server is required to fetch the images. This, in my opinion, is the more important gain (outside of cleaner and simpler html and css).

  65. First off, I think this article is world-class. Dave took a good technique (Pixy’s rollovers), and improved upon it.

    My question is really more around image replacement, so if this isn’t the forum for it, please let me know (politely!).

    In an attempt to add text to the links in the Buttons section (#iconmenu), I’ve tried to repurpose the Shea Enhancement (Gilder/Levin IR w/ title) summarized on mezzoblue to work with links, instead of an h6 and nested span. I can’t seem to get the to /not/ obscure the . In other words, the image replacement works, but the 100% span covers up the , and I lose the rollover and the cursor change.

    I’m elected not to use the text-indent: -1000em method of IR, so without gettting into an argument about which method is better, can someone point out the approach to use to incorporate Dave’s “Shea Enhanced” IR tech with the #iconmenu example?

  66. Very interesting article. But why, in the “Irregular shapes” section, is a second “after state” image required? Could you not spread out the pieces in the after state so that they do not overlap? This might make the math for positioning the after state pieces a bit more complicated, but it’s something you’d only have to do once, and your after state image would be smaller and non-redundant.

  67. Janos, I believe there is something wrong with your settings, I viewed both your link and Dave’s, and neither of them had any delay in IE 6.

  68. Will whoever is trolling my SF History board please stop. I know this is off topic but they are people from this ALA forum with the I.P. Addresses: (someone named Mikey)
    I’m assuming the latter is the one who posted the “I love PPK” trash. Please stop. I will stop trolling here if you stop on my site.
    Ray, Spook and Mickey please stop. If you want to deal with me email me, don’t post rubbish on my SF History site. Just because I might troll here is no excuse for you to do the same.

    Thank you.

  69. I’m not sure that this technique is the end-all be-all solution that others are making it out to be. There’s a sweet spot in a page’s design where multiple connections to a webserver will almost certainly result in a faster display of images than this will.

    Consider this: you have an extremely image-heavy page, with a few nav items that each have a largish filesize. By concatenating all of these nav items together, you need to wait until the entire file downloads before displaying _any_ of the images. On the other hand, with multiple connections to a webserver, your nav items will be guaranteed to show up as soon as they are downloaded. If your nav item is over 2k, for instance, the image header filesize overhead is negligible.

    This is the age-old serial vs. parallel debate, just in graphic format. If establishing parallel connections requires just a bit more overhead, and bandwidth is constant, what’s the point at which a serial connection is a better idea? For smaller pages, sure, knock yourself out, but for any decently-sized page (say 40k or larger) I just don’t see this method as speeding up rendering times at all.

  70. Loved the article, only problem now is I have to go and RE-DESIGN my image maps! But probably a good idea to do so anyway. I was also intrigued by the other recent article on image maps (see: http://www.alistapart.com/articles/imagemap/)

    One question though.

    In the blob example by using appropriate title tags one can get the name of the link to pop up but I wanted to employ the effect used by eric meyers (old but tested method) of pop up text (see:
    http://www.meyerweb.com/eric/css/edge/popups/demo.html) so that the link name would appear somewhere else on the page, BUT I can’t seem to get it to work in using this method? Is it because it is within a list? Should I give up? is there another more ingenius way?

    I’m NO expert with css but I love trying out the new methods people keep coming up with on alistapart, GREAT site.

  71. Marko:
    My behavior (.htc) doesnt solve the delay but the flicker. The delay is beacuse IE downloads every time the image again and again.
    1. Mouseover/mouseout
    2. IE:Turns of the image
    3. IE downloading the image (the delay)
    4. download complete IE show up the image

    Sam Ingle:
    If you set the cache properties in IE to “every visit” (or something like that) you should see the effect. (image flicker or text shows up)

    More about flicker in IE:

  72. This one is an excellent idea for my site, which can be used to select Eastern, Central, Mountain and Pacific zones in the United States before selecting specific States. I would appreciate to know the quick summary of Pro/Con of that design for all browsers wherever possible? I aim to satisfy my audience to the best possible, even for text-based lynx users.

  73. Sorry to wander off-topic again, but remember this is supposed to be a discussion. Everyone doesn’t have to like what has been presented. If Dante doesn’t feel that this is a worthwhile use of ALA’s bandwidth, then so be it. He’s entitled to his opinion, even if you don’t agree with it.
    I know I don’t. This is an interesting visual design element. And let’s face it, Lynx compatibility and standards compliance aside, visuals are what draw in your guests, almost as much as your content. And that’s my opinion.

  74. “I will stop trolling here if you stop on my site… Just because I might troll here is no excuse for you to do the same”

    So you admit to trolling. Sigh…

    If people are trolling your site, they’ve as much right as you have to troll here. But remember the ALA text at the top of this page: “We reserve the right to delete flames, trolls, and wood nymphs.”


  75. I just tried out this technique on a site that has buttons which require a number of states: normal, hover, selected, and disabled. What I found most useful was the ability to add and modify the button states just by swapping out one image. That way, I know that I’ve updated all the states of all the buttons and won’t be surprised by a rollover state on a selected button that has the old font, for example.

  76. Nice Work Dave!!

    And the CSS has given me a completely new set of ideas to play around with.

    Thanks and lot fo sharing it.

  77. The problem I have is that markup that consist of a list of empty links is rather useless when I am using a screen reader or have CSS turned off. Furthermore, a sliced image would give me alternative texts for every image.
    Now, to change this all we need to do is to add a text in the “slices” and hide this text with another FIR technique, for example
    http://www.kryogenix.org/code/browser/lir/ .
    Wouldn’t that be a better solution, as it does fall back to a fully accessible list of links no matter what I do?

  78. I never said I didn’t like the technique. It’s a bit too complicated for me, but still I like it. I don’t think I’ll ever need to use it in practice, though. But ya never know.
    I was thinking of bringing Javascript into the mix, not for the rollovers but maybe for clipping. Not at all sure how I’d do this.

  79. Jamie, that’s a very interesting experiment. Although you might be accused of “dumbing down” text for readers. (“Why can’t they just learn to read the original script!”)

    This is the kind of dynamic effect that can only occur on the web, not in print. I’m all for it. But is there a way to make the rollovers bring up standard text, not images? (Perhaps using generated content.)

  80. Won’t this bloat the data? Instead of having lots of small files to be loaded, a big one has to be loaded hundreds of times.

  81. Chris, thanks for your comments.
    It ain’t so much about dumbing down as about making it readable for those who can’t see so good.

    I like the idea of doing it with real text in theory, but can’t really see a way of doing this and staying with pure css and static html – especially given the way different browsers display fonts etc.

    I’ve just modified it slightly so there is a no-style version now – this divides the text into a bulleted list which is a bit odd, but much better than nothing. Would be interested to here other’s suggestions for how to do this better:

  82. Very nice effect! but has anyone successfully tweaked it so that images can be printed out?

  83. Well, the thing that bugs me is that we add links that lead nowhere for a visual effect. In your case, it is not wise to make the flowing text a list, but if you use this technique to spice up a navigation, then we would need it.

    It once again boils down to hover effects on elements that are not clickable being misleading. If every browser supported hover on every element, that’ll make it easier.

  84. It’s funny how Web Standards promoters contradict themselves. WaSP and PTG says that Web Standards will lead to simpler, cleaner, and leaner documents. However they encourage as to use uls for every sort of list, adding a lot of extraneous markup. Funny.

    That aside, the desicion on wether to use lists for this or not could go either way. I would just use a DIV with maybe some spans. Maybe lists would be better, since they have shorter names (UL and LI as opposed to DIV and SPAN).

    Just thought I’d wrap up this argument.

    I even thought or using an IE behaviour htc to do this, but that would be too browser-specific.

  85. Until navigation list (NL) is added to all browsers, then I don’t think designers have a better choice than unordered list. Semantically speaking, a list of links would be the best scenario for establishing a navigation set in terms of raw HTML [for non-visual users].
    Dante-Cubed, this code is far, far, far cleaner then any image map method of old or relatively new. Though personally I’d like to see a way to keep the text in the anchor, it is still technically correct code.

  86. Though personally I’d like to see a way to keep the text in the anchor, it is still technically correct code.
    edit: Without having to embed a span inside the anchor.

  87. Dante wrote:
    It’s funny how Web Standards promoters contradict themselves. WaSP and PTG says that Web Standards will lead to simpler, cleaner, and leaner documents. However they encourage as to use uls for every sort of list, adding a lot of extraneous markup.
    <<< Of course people use simplifications. It's not technically true that web standards automatically lead to cleaner documents; e.g. of course if you have a valid document and remove the doctype (thereby making it non-standard), it's going to be smaller in filesize. But in making the case for web standards, it would be too time-consuming to include all such little gotchas. The listener would lose interest before the speaker had a chance to get to the good parts. It's also an unfortunate fact that the term "web standards" is widely used as if it meant "purely semantic XHTML code coupled with CSS". Font tags might be looked down upon even among the most passionate CSS haters, but they're still part of a so called web standard (they're officially called "recommendations" by their creators). So, web standards can actually lead to terribly bloated code if you use the "wrong" standards (or even the "right" standards) the "wrong" way. Anyway: Using ul:s for every sort of list is NOT "adding a lot of extraneous markup" (though it could be "adding wrong or vague markup" if there's a better list type than ul available). For the last time: A list is a list and should be marked up as a list, just as a paragraph should be marked up as a paragraph. (It could be argued that the written content of a page is technically a list of paragraphs, but that, IMHO, is not the semantic definition of a list in HTML. The items in a list should have something relevant in common other than all being parts of the content.) So, no, "Web Standards promoters" do not contradict themselves in this case.

  88. Well conceived and beautifully written Dave! Here’s a short FIR-based modification for Opera 6.

    Change the background position for the ul element to reveal the hover image instead:

    #skyline {
    	       width: 400px; 
    	       height: 200px;
    	       background: url(test-3.jpg) 0 -200px no-repeat;
          	 margin: 10px auto; 
    	       padding: 0;
    	       position: relative;

    Adjust the widths of the list elements to add up to the full 400px width of the ul element:

    #panel1b {
           	left: 0; 
           	width: 96px;
    #panel2b {
    	       left: 96px; 
           	width: 76px;/*formerly 75px*/
    #panel3b {
           	left: 172px; 
           	width: 111px;/*formerly 110px*/
    #panel4b {
           	left: 283px; 
    	       width: 117px;

    Finally, add these background postions for each list id tag‘s a element:

    #panel1b a {
    	       background: transparent url(test-3.jpg) 0 0 no-repeat;	
    #panel2b a {
    	      background: transparent url(test-3.jpg) -96px 0px no-repeat;	
    #panel3b a {
    	       background: transparent url(test-3.jpg) -172px 0px no-repeat;	
    #panel4b a {
           	background: transparent url(test-3.jpg) -283px 0 no-repeat;	

    That‘s it. Hope somebody finds this helpful.

  89. >Anyway: Using ul:s for every sort of list is NOT “adding a lot of extraneous markup” (though it could be “adding wrong or vague markup” if there’s a better list type than ul available).< Oh, there is: The Menu tag. It's just like UL but has no bullets. Since most people "tame" the lists by removing bullets it doesn't seem to be a problem. Of course if you DID want bullets you could always do: menu { display: list-item; }

    First Item

    You make the call.

  90. …Menu is deprecated but still works. Just because something is “deprecated” doesn’t mean you shouldn’t use it. It should make a comeback.

  91. There’s a reason why things become deprecated. Usually it’s because something better has come along. With the menu element and the ul it’s kinda like leaded and unleaded gas. Most sensible people understand (well…those with half a brain anyway) the drawbacks of using leaded gasoline. Sure…leaded gas is still available here and there. That’s called backward compatibility. However, just because it’s still available does not mean you should still use it given the choice.

    Could you imagine the crap that would be in the air if we all still used leaded gasoline. Think how bad it would be in a large city of several hundred thousand. Say a city like San Francisco. It wouldn’t be as beautiful as it is today with all kinds of cars running around using leaded gasoline. Leaded gasoline is still available “here and there” as a transition. The only people using leaded gasoline are those with antique automobiles, those that can not afford to buy a new auto and those that don’t give a shit about community. Either you understand that or you don’t.

  92. “Though personally I’d like to see a way to keep the text in the anchor, it is still technically correct code.
    edit: Without having to embed a span inside the anchor.”

    As posted here earlier for review:
    has exactly that.

    We should stop wasting time on useless discussions if lists or menus are correct and stick to the topic at hand.

    /me puts the lid on the box with trollnip

  93. Although

    may be used, despite being deprecated, I try to follow the advice of the W3C myself. At the base of the page I linked to earlier, they say:

    “We strongly recommend using UL instead of these elements.”

  94. hi there again, a few days ago i posted here about this technique.
    if i put the code in a linked css it’s not showing anymore the picture.
    i could not find out why.

    now i’m almost finish with my first complete css designed web site, but a lot of adjustment for browsers compatibility.

    and just about ths technique, it’s working well almost everywhere but bug comletely on opera mac ( the latest version )
    is ther a work around ?

    could somebody tell me as well if they are good places where show your web sites to get some help debugging. i start going crazy…

  95. Dante wrote
    Menu is deprecated but still works. Just because something is “deprecated” doesn’t mean you shouldn’t use it.
    <<< As has been pointed out, that's EXACTLY what it means. At any rate, we're talking about saving a few bytes per page. You might as well start removing all the line breaks from the source. Contrast that to the tens of kilobytes (per page) of unnecessary tables and font tags that "web standards promoters" (WSP) are usually talking about when they mention bloated code. You see what you're doing here, Dante? First you say (or at least imply) that WSP are over-zealous. Then you imply that they're not zealous enough.

  96. What I meant to say was that even though MENU is deprecated, it is still supported by browsers to provide backwards compatibility. I think even though some tags like XMP have been deprecated for years, they’ll be supported by IE for many years to come for backwards compatability. You can still use MENU. Besides, if it’s deprecated it won’t do anything. You can have semantics (UL becomes the much more semantic MENU) and use CSS to control what it does.
    If you’re crazy enough you could do this:

    Blah blah

    Menu here

    Anything you want

  97. For those of us not skilled at visualizing code and too lazy to type it in, a link to an example would be helpful.


  98. If you want an example of how one of the points mentioned in this article is wrong, view the examples with Netscape 4. They do not degrade gracefully. In NN4 all you see is part of the image and nothing else. No plain ULs. No behaviour. A better way would be to import the styles so Netscape 4 can access plain content instead of almost nothing.

  99. You rant about alistapart on evolt and you rant about evolt here. Both refused to publish articles by you. You whiningly announced you will retire from writing online articles, if that is all you can contribute here, then please retire from posting.

  100. I didn’t mean my above post in a bad way. What I meant was that Evolt always has stuff that you won’t find anywhere else, or stuff that might not make much sense. I *do* have a right to criticize.

    I contribute a lot. If you look at the Zebra Tables comments you’ll see just that.
    Whining? I have a few responses to that but that belongs in email, as I said earlier.

  101. On page 11 of these comments, Jamie Mackay posted a great link to an experiment using rollovers to allow people to decipher a piece of script text, by hovering over the lines. I’ve just come across another great example like this. (I would have emailed this to Jamie, but don’t know his email address.)


  102. For the stuff I do, I’d name this one of the top 3 articles on A List Apart *easily*. Not only is this innovative and clean, it’s better than Javascript and saves n00b schmucks like me from having to learn it! Ha ha 🙂

  103. I agree this was a better solution tha javascript–kinda.
    It’s a lot more complex; you must know the correct coordinates for the position.
    Javascript is meant for adding usability anyway. Just don’t get too carried away with ditching Javascript: you’ll need it eventually.

  104. So, has anyone found a nice way to not only fix the flicker, but get past IE having to download the image every time?

    I was really hot about this idea until I noticed that IE 6 completely ruins it. It makes fast hovers impossible, yet again.

    I’ve heard the discussion about using fir, but I have yet to see an example targetted at rollovers using this method.

    Anyone figured it out yet?


  105. Excellent work, Mr. Shea, and thanks for sharing.

    With this tutorial in mind, I retired to my CSS laboratory and started experimenting; I took a couple of accessbility aspects from Prof. Bowman’s “Sliding Doors” technique and cross-bred them with “CSS Sprites”. Then I started testing the thing in the various major browsers – here’s a code overview;

    My Website Name

    A brief welcome message.


    OK, I _think_ that’s pretty self-explanatory; if you have CSS on, you get a very nice graphical top bar. If you switch CSS off, you get neatly structured text. Trouble is, it’s working fine (on Windows) in Firefox 0.8, IE5.5 and IE6.0. Where the wheels seem to fall off is when you view the thing in IE5.01…although the initial (i.e. “off” state) display is perfect, the rollover image only appears on click, and then stays highlighted until anther link is clicked.

    It’s puzzling, because Dave’s final (map) example works perfectly in IE5.01 on my machine, so it’s not a settings issue. I’ve tried removing everything from each list item except for the link itself – replicating Dave’s final example almost to the letter – and still it (mis)behaves the same way. What might I be missing or doing wrong, any thoughts?

  106. Ever trying to maximise CSS, this article was just what I was looking for. Simple but really effective.

    I went and changed a rollover navbar immediately and was very pleased with the results.


  107. project lead: ‘What’s that ya have?’
    developer: ‘CSS.’
    pl: ‘CSS. BRILLIANT!’
    pl: ‘What do ya do with it?’
    developer: ‘Well, I have found a way to make rollovers using only one image.’
    pl: ‘And you make rollovers work in many browsers using only one image no matter where you are?’
    developer: ‘Yes.’
    pl: ‘Make CSS rollovers using one image…BRILLIANT!’

  108. Firstly, excellent article – I hadn’t thought of doing things this way.

    Here’s my attempt, which uses the initial idea along with a number of bits of advice which have been mentioned in this discussion.


    The graphic used is

    Browsers tested on
    PC – IE6, Firefox
    Mac – IE5, Safari 1.2, Firefox .08

    Lessons I’ve learnt in this are:-

    1- Because this map is a lot more complicated than the Blobs example, I needed to create 4 versions of the graphic rather than 3, as Inverness-shire was surrounded by so many other counties. The image is now a whopping 60k. However, I could go through it chopping out lots of areas in the 3 rollover maps and turning them white which would reduce the filesize. As Scott suggested earlier in this thread, I could go through the image deleting everything from the rollover state versions except the yellow bits, and then move them all up nearer the normal map and redo all the arithmetic. I’d guess the image size could be as little as 20k.

    2- I’ve seen mention of using z-index to bring some of the smaller areas to the fore. I don’t think it’s needed – what I’ve done here is shuffled the

  109. s around – the later ones seem to have the equivalent of the highest z-index.

    3- I’ve added title=”Shetland” etc to the s for alt tags

    4- I’ve used the a {text-indent: -100em;} hack as suggested by Dante-Cubed (there was something useful amongst all the vehemence) so that I can add text links in the tags. Hopefully this would give a navigable list if the styles are not used.

    The only annoyance for me is that the arithmetic is a pain in the arse. What I want now is someone to design some software to make it easy, in the same way as something like Globalscape’s Cutemap does for normal image maps.



  110. Comment from the sliding doors article:-

    “Switching IE to not check the page for newer content every time removed the image flicker problem.”

    Should apply here too I would think.

  111. The best reason to use, say, a 500×50 image instead of 10 50×50 images is because for every image, the server sends a bunch of headers to the client before sending the image, and the client pauses to see if the image has been cached or modified since it was last cached, and then it signals the server to continue downloading if it needs the new version.

    This is very slow when there are a lot of images. The menu on my website uses 58 images just for the buttons (there are 23 buttons, if I remember right). It takes forever to load the damn thing… but a single image would load much quicker.

    Also, everyone knows the problem of image rollovers — you need to pre-cache the rollover image in JavaScript or it won’t be loaded until you move the mouse over it. A sprite map fixes that problem.

    Otherwise it was a really great article… it occured to me that something like this would be great but I didn’t think it could be done with CSS.

  112. Hi there,
    I’ve found that Safari on OS 10.2.8 has problems with returning to the normal state after the hover. This has something to do with position:relative of the

      but I can’t figure out a way to circumvent that.

      Does someone maybe have a fix for?

      Anyway, the article is great.

  113. Chris Fam’s comment from March 12th,

    “has anyone successfully tweaked it so that images can be printed out?”

    is a major issue that, amazingly, no one has addressed. Without a work-around for this I wouldn’t recommend using this method.

    Is there a solution to this problem?

  114. Do the browsers load the background-images when they find them in the css-code? Otherwise it would cause the rollover to lag.

  115. I’ll say from the outset that I’m not especially good with CSS. 😉

    I can’t work out how to translate this to a vertical list of links, like thus:

    link 1
    link 2
    link 3

    …instead of the horizontal way this example is set out. I’ve tried changing the “left: x; width: x” to “top: x; height: x”, and the different offsets, but Safari doesn’t even register there being links there. Doing it horizontally, as demonstrated here, works fine. Thanks in advance!

  116. Yo. Anyway know the css code, for changing the state of an image defined by a CSS class, to have a border shown when the user places the mouse over the image?

  117. Yo. Anyway know the css code, for changing the state of an image defined by a CSS class, to have a border shown when the user places the mouse over the image?

  118. This article is amazing, the writing of the tutorial is also outstanding. I had it working in a complex layout in no time. The code is rock solid, very stable.

    Thanks Dave for taking the time to document this incredible technique!

  119. Fantastic!

    I’ve only been doing full CSS-based design for a few weeks, but I’m loving it!

    There’s a submission for CSSZenGarden from me in Dave’s inbox (we can but try!) and my menus are going to look fantastic now that we’ve been let in on that little gem!

    PLEASE keep up the hard work everyone- it’s our future!

    (and Dave, accept my submission… I’m sure I can find out where you live…) lol

    (I’m REALLY just kidding. really.)



  120. Hey VW, not managed to get this fully underway myself, but did gather that you can put the image anywhere you like- left, right, top bottom…. it’s all a maths game.

    As long as the position attributes for the images in both states correspond with what you want to see in said states, your laughing.

    As for the vertical lists, I’m still trying to crack that myself, but I did see one used on http://www.CSSZenGarden.com
    Have a little browse through to see if you can spot it (I’ll have another look myself)
    (could it be ‘display: inline;’?)

    All the best 😉

  121. And what do you know,,, it was on this site! (well durr!)

    http://www.alistapart.com/articles/practicalcss/ when it loads run your search function (usually ‘ctrl’+’f’ [find]) to locate the words ‘Checking it Twice…’

    It’s right there.

    (Normally, a nice touch with css is that if an element has an ‘id’ attribute, you can use it as an anchor to that direct part of the page. That page just didn’t seem to have any!)

    Further reading on that point… http://www.w3.org/TR/REC-html40/struct/links.html#h-12.2.3
    ‘…because the W3C aren’t f***ing about…’ (quote:Me, just now.)

    I’m off to bed, but no doubt CSS won’t let me sleep AGAIN.



  122. >Hey VW, not managed to get this fully underway myself,
    >but did gather that you can put the image anywhere you
    >like- left, right, top bottom…. it’s all a maths game.

    Aye, that’s what I figured, but I can’t work it out. Instead of having “left” and “width”, you’d think you’d have “top” and “height”, but it doesn’t work. I end up with the entire navigation image being linked as the bottom (contact) link, and the whole lot mouseovers at once…

    And setting it to inline instead of block doesn’t work either. 🙁

  123. Great article am experimenting with this right now but am having problems centering the list. I have gone to many resources and use the text-align:center trick for IE and the margin:0px auto for all others. In all other browsers except IE the list is centered.
    But in IE it is always about 30 picels off to the right forcing the user to scroll in 800×600 resolutions

    Anyone have any good links or solutions to centering this list?

  124. I am trying to learn as much as possible about CSS. I have been using Dreamweaver & Fireworks for about 5 years. I am currebnlty converting our website to all CSS. However, althoguh I keep hearing about “sprites” I have no idea what they are. It appears to be some kind of image. Could you please clarify so I can understand what you are doing. I find that those who are familier with a technology often forget that those who are still learning may not yet know all the jargon, much of which is not in the reference books.

  125. Sie sind auf der Such nach einer Kreditkarte oder suchen ein geeignetes Zahlungsmittel für den Urlaub. Mit einer Kreditkarte (englisch: credit cart) haben sie genau das richtige gefunden. Wir bieten ihnen eine Barclaycard an, diese kombiniert Mastercard und Visa in einer Karte. Wollen sie hingegen Urlaub machen und abnehmen ist Fastenwandern genau das richtige für sie. Fasten und wandern sie, Fastenwandern in den Vogesen ist gesund und macht spass. Bücher, DVDs, kann man online einkaufen, dort gibts alles günstig auch Software ohne Versandkosten. Besuchen sie Bücher, DVDs günstig kaufsonline machts möglich.

  126. I really like this idea…however I wanted to see if it really degraded to an unordered list in Netscape 4.7 (mac). It doesn’t.

    Now, I don’t intend on caring too much about this browser, but I’ve been reading Zeldman’s book and this website and have loved them both simply because they present new techniques that can transcend all the difficulties I’ve been experiencing.

    How come the sprite technique doesn’t just show up as an unordered list for me in NS4.7 Mac?

  127. Always looking for new ways in which to implement CSS and this certainly is a good one. I’ve already played about with it and found it quite easy and it seems to be an extremely good way to present things.
    Wonderful tutorial, many thanks.

  128. Hello, studying your great tutorial and trying to get to the same results I have some big problems with this button-thing. Even with a exactly same picture and your css-code (!) I don’t get to the same result… How do you count the values for the image itself and the borders and how do you get this image in the middle of the page without coding it???
    I’m willing to learn but now I need a litte or more help. Thanks a lot!

  129. Hello, in the meantime paul o’brien from sitepoint helped me with my centering-problem. Shorthand-coding is not my speciality… (margin top and bottom with px and right/left with “auto”).
    The rest of the story I solved with a little help from my partner who askes the right questions. But I still don’t understand why you used the dummy-background-image for the ul – that makes no sense to me. Also the 1px add to the width of the picture/ul I see but don’t understand.
    So if you, dave, or somebody else could explain me, I would appriciate!

  130. Once again you guys really make me feel like an amateur.

    Just when i thought i had a handle on it….

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

Nothing Fails Like Success

Our own @zeldman paints the complicated catch-22 that our free, democratized web has with our money-making capitalist roots. As creators, how do we untangle this web? #LetsFixThis