I want to share a CSS technique I’ve used alot. I’m sure that you have seen CSS sprite techniques that utilize changing background position on hover to change a link’s state. Also, they have the added benefit of keeping from loading images on hover, limiting lag. This technique is very similar, but works like a charm for IE6 and PNG images. I know this may be a moo point at this stage, because IE6 is on the outs, but still works beautifully as a technique.

Let’s jump right in, as I don’t have a lot of my Labor day to give.

First, as always, I want to preview this thing and see what it does. Here’s your preview:

Buy me a coffee
You get the picture. Hover it, click it, etc…the button has different states.

Aight, the meat and potatoes: the XHTML

So, the markup is pretty simple. It’s basically a link with a span in it. Check it:

<a href="..." id="buyme_coffee">
<span>Buy me a coffee</span>
</a>

How it works

Before looking at the CSS, it helps to know how it works. Think of it as a window to a larger canvas behind it. It’s easy to think of it in terms of the two elements:

  • The window: The A tag
  • The canvas: The SPAN tag

The window only shows a portion (a view) of the canvas. The canvas can be any size. By changing the position of the canvas, you can pan a different portion of it into the window. The window is fixed width, fixed height, and any overflowing content is hidden. This way, only the portion of the canvas in the window view is visible.

The CSS

#buyme_coffee,
#buyme_coffee span{
display:block;
width:160px;
height:40px;
position:relative;
overflow: hidden;
}
#buyme_coffee span{
height:120px;
background: url(coffee_button.png) 0 0 no-repeat;
text-indent:-9000px;
}
#buyme_coffee:hover span{
top:-40px;
}
#buyme_coffee:active span,
#buyme_coffee:focus span{
top:-80px;
}

The first selector targets two tags, the #buyme_coffee link and the #buyme_coffee span span inside the link. I’m doubling up the rules by targeting both tags because both tags share quite a few similar tags. As for the rules that are different, I’ll correct in the next selector.

This first selector sets both A tag and SPAN tags to block (since they are inline by default), sets the width and height, and then sets the overflow to hidden. The overflow:hidden here is the key. This causes the A tag to act as a window that only views the content in its height x width box. All other content is simply cutoff or put away from view.

The second selector, #buyme_coffee span, resets the height to the height of the background image, which is larger than the viewport (A tag), but gets cutoff from view. The text-indent:-9000px is a cheap way of shoving the text off the screen so that this text is replaced by the background image. The background image contains the three states we want: Default, Hover and Focus/Active. Here’s a preview of that background image:
CSS sliding sprite window button image

You probably guessed it. The top image will show as default.

K, we’re almost done. The third and fourth selectors target the :hover and the :active and :focus states respectively. This is uber simple. When the link (or window) is hovered, push the top of the span (or canvas) up by 40px, showing the hover state. When the link is active or focused, push the span up by 80px, revealing the active state.

That’s it! So why is this better than just panning the background position you ask? Good question. I started using this method when I needed to make the background an alpha-transparent PNG, which as you know, doesn’t display correctly unless you use an IE alpha image loader filter, which as you know doesn’t play nicely with background image positions. With this method, you can apply an alpha image loader filter to the span element and it works like a charm.

Hope you enjoy. Cheers!

Update: Based on @Justin’s suggestion, I’ve included some modified CSS below to show this technique sans the a text-indent:-9000px for screen reader friendliness. A demo of the modified CSS can be seen here.

#buyme_coffee,
#buyme_coffee span{
display:block;
width:160px;
height:40px;
position:relative;
overflow: hidden;
}
#buyme_coffee span{
height:140px;
background: url(coffee_button.png) 0 0 no-repeat;
line-height: 20px;
white-space: nowrap;
top:-20px;
}
#buyme_coffee:hover span{
top:-60px;
}
#buyme_coffee:active span,
#buyme_coffee:focus span{
top:-100px;
}

Comments

18 Comments

  1. Jessica Caldwell said 1725 days ago

    Awesome!! I can’t wait to try this!! Keep up the good work :)

  2. Daniel said 1725 days ago

    Looks great Rogie!!! Selectors are too much fun!! :)

  3. Waldini said 1725 days ago

    Rogie, you are a geen-ee-ous! As always, I enjoy stealing your work. ;o)

  4. Andreas said 1725 days ago

    I’m sorry, but isn’t this technique reallllllllyyyyyy old? About 2003?

  5. Rogie said 1724 days ago

    @Andreas – Don’t be sorry. It may be. I’m not sure. Also, it may be a variation of an older technique as well. I’m not sure, but I thought I’d just share ;)

  6. CSS Sliding Sprite?Windows | i-arts.eu said 1724 days ago

    [...] Read more about it at komodomedia.com [...]

  7. Doug said 1724 days ago

    Don’t forget to add position:relative to the first CSS statement. Otherwise, nothing changes on hover.

    Also, I usually group the :focus selector with the :hover selector (instead of :active). Makes more sense to me that way.

    @Andreas: What’s new here – at least it’s new to me – is changing the position of the span rather than just the background image itself. Very clever.

  8. Rogie said 1723 days ago

    @Doug – Thanks, somehow I had that position:relative; in the working code, yet not in the post. Good catch!

  9. Justin said 1722 days ago

    I’d usually use the span to hide the text. Isn’t using text-ident to hide the text bad for SEO purposes?

  10. Rogie said 1722 days ago

    @Justin – Sure. If you’d like to stay away from text-indent to hide your text, with this method, we can’t hide the span – because the span contains the image.

    I’ll edit the post to show alternate CSS for those wanting to shy away from the text-indent rule.

  11. Sam Subotic said 1721 days ago

    Amazing! I searched something like this :D

  12. Simon Jensen said 1721 days ago

    Thanks – always wondered how these “more elements in one image”-links worked?!

    Now I know, thank you very much :)

  13. Alistair said 1711 days ago

    Great tutorial, found this one out about 4 weeks ago. May I also add, that if you add an id to you body tag you can have the currently active page set to the hover state.

    Then in your css you could just use…

    #home #buyme_coffee,
    #home #buyme_coffee span{
    display:block;
    width:160px;
    height:40px;
    position:relative;
    overflow: hidden;
    }
    #home #buyme_coffee span{
    height:140px;
    background: url(coffee_button.png) 0 0 no-repeat;
    line-height: 20px;
    white-space: nowrap;
    top:-20px;
    }
    #home #buyme_coffee:hover span{
    top:-60px;
    }
    #home #buyme_coffee:active span,
    #hom #buyme_coffee:focus span{
    top:-100px;
    }

    Maybe not exactly how it would go but you get the idea. You would simple change the id of whatever page to activate which ever button you wanted as active.

  14. Bruno said 1699 days ago

    A small (but important) FYI – for Rogie and anyone who wants to use this technique…

    A friend pointed me to your site while trying to implement a CSS rollover similar to the one I’ve had on my site for the last few years, but with better alpha support for IE. Long story short, he couldn’t get your style to work in IE6.

    I just took a look and have found the problem. Unfortuunately you’re missing a critical property to make this work elsewhere.

    #buyme_coffee:hover {
    background-position: 0 bottom;
    }

    The example on your own page works only because you have that background property within your main v4 css file on the first hover selector. The example you’ve posted in the zip file and quoted in this post however, will not work as-is in IE6 (works fine in IE7 and non-crap browsers though).

    Anyway, it’s a great post otherwise. I’m using something very similar in a template I’ve been designing for another friend. Though I much prefer the times when developing sites without MS compatibility requirements. Much less cruft.

  15. Bruno said 1699 days ago

    Another comment… With regards to SEO and text indenting, I have some personal experience.

    I don’t believe Google (the most important crawler anyway) is automatically penalizing overflowed and clipped text. However, if you’re using the technique to hide irrelevant or misleading text, then they will react to complaints and may remove your page(s) or site from their index.

    As long as you’re using the text to properly label the image you should be OK. I have used the same indenting technique to label graphical nav buttons that would otherwise produce no output if someone disabled page styling.

    The text, even though it’s clipped and not visible, is an assistive service and important for accessibility.

    Hiding it vertically as in the second example pretty much accomplishes the same goal and has the same caveats for anyone thinking about using it for trying to cheat robots/spiders.

  16. Bruno said 1699 days ago

    Last post I promise. I should have mentioned that it’s likely a better idea to specify the background position as “0 0″ since it’s the presence of the property that causes the technique to work in IE6, not the “bottom” value specifically.

    The setting of bottom may cause unwanted movement in your image depending on how you’re aligning everything in your specific implementation. 0 0, is the normal alignment, so it makes a good starting point.

  17. CSS knep som ?r v?rt att ta en titt p? | Webbrelaterat said 1670 days ago

    [...] CSS Sliding Sprite Windows I want to share a CSS technique I

  18. .exe said 1652 days ago

    the only ‘problem’ I found with this is when the user right clicks the image, then the clicked state would appear.

Sorry, the comment form is closed at this time.