CSS Rollover Button

Everyone likes a good rollover button. It creates interactivity for the user (which younger website users like) but also gives an indication that the button is clickable (which is important for older and less experienced website users). There are a lot of ways of implementing a good rollover. Most people jump to Javascript to do this because they think that’s the only way. However, this requires you to write javascript that preloads your images so that there is no delay on the rollover for the first time. Well, I’ve found a much better solution using only CSS that is clean, easy to implement, won’t break, and works across all browsers. I love it so much that I use it for all of my buttons on my fulltime employer’s website.

So now you must be asking, how does this wondrous CSS miracle work? It is actually quite simple. Using only one image, you will restrict the size of your button (to only show part of the image which will be set as the background), and then use the pseudo-class :hover to shift the background-position of that image into the hovered portion. Again, this allows your full image to be preloaded so there is no delay on rollover. This has been cross-browser tested in Firefox 2 and 3, Internet Explorer 6* and 7, Safari, Opera, and Chrome, and it works perfectly. Here is an example below including the full image, the image as it will appear/work, the HTML, and the CSS.

This is the HTML:

<div class="rollover" id="exampleButtonIDHere">
  <a href="link location here">
    Put a summary of your button here. A few words will suffice, imagine this as the "alt" text for your image/link  

This is the CSS that made the image on the left into the button on the right.

.rollover a{
   display: block;
   text-indent: -9999px;
   margin: auto auto auto auto;
   cursor: pointer;
   outline: transparent solid 0px;
#exampleButtonIDHere a{
   height: 100px; /*This height is the visible portion of the button only*/
   width: 200px; /*Put your image width here*/
   background: url('Put your image location here') no-repeat left top;
#exampleButtonIDHere a:hover{
   background-position: left -100px; /*This negative value should match the height above*/

So basically, a div, with a background image of both buttons, and a height and width restricted to the size of only one of the default button, shifts on :hover to pushing the hover portion of the image up into the viewable portion of the div, with the default portion of the image pushed out. Simple right? I know! If you are going to have a lot of these buttons, I’d suggest a whole separate CSS document for them. You can also combine the .rollover with the #exampleButtonIDHere. I keep them separate because it reduces the length of the CSS document with lots of buttons.

Don’t forget the a tag inside the div tag, and include the a as part of your CSS style declarations. Each portion of that CSS is very important! The “display: block;” allows for the image to not be pushed out of it’s own div. The “text-indent: -9999px;” pushes the alt text out of the way, the “margin: auto auto auto auto;” eliminates any cross-browser issues with default settings, the “cursor: pointer;” forces every browser to display it as a link with the mouse icon changing, and the “outline: transparent solid 0px;” forces browsers to not outline the link when being clicked. If you have any trouble implementing this, let me know, because I completely swear by this amazing CSS trick. I’d also love to hear if you’ve had successes implementing this on your own website.

*Be careful, if you use png images for your buttons (which I do because they are far superior to gifs with transparency) then IE6 won’t allow your rollover to work. Most png fixes that I have found so far disable background-position properties in CSS in IE6. Annoying, but really not the end of the world. Either live with it for whatever percentage of your users are IE6 users, or use jpgs and gifs instead. I say the pngs are worth it for the better transparency quality and lower file size.

20 Responses to “CSS Rollover Button”

  1. todd says:

    what if i wanted to make a few buttons and have them centered on the page? floating prevents this no?

  2. David says:

    Todd, floating does remove auto margins, but the CSS above doesn’t use floating. If for some reason you need to employ a float but also want your buttons centered, you’ll have to hardcode your margins.

  3. chad wagner says:

    Hi David-
    I am trying to put 6 buttons side by side and having trouble. Can you help? Take it easy on me, I’m a newbe 🙂

  4. David says:

    Chad, I have to see an example of your code to be able to help. Basically, the code above would work for putting 6 buttons side by side, just add css to the div itself to float: left so that they line up next to each other.

  5. Mugur Marculescu says:

    Very simple and to the point.

    I do have one issue and workaround. When I try this, the hit area that activates the roll over is the parent div (which is correct) but the hit area for the link is only the space taken up by the “a” tag, which depends on the size of the font, line-height and who knows what else; if it’s small, it may not be anywhere near the size of your button.

    I simply set the padding of the specific “a” tag manually to fill the parent box. Any ideas on why this is happening. Maybe there’s something I could be doing to prevent the need for the fix.
    Thanks for the example.

    • David says:

      If you apply the CSS correctly, the a tag is what has the rollover effect, not the parent div. so you really shouldn’t have this problem.

  6. David says:

    Mugur, the workaround shouldn’t be necessary. If you look at the CSS closely, it applies to the a tag, and not to the div surrounding it. The div is what contains the class and ID information that identifies the correct a tag to apply the CSS to, but technically you can bypass the need for the div and apply a class and/or ID to the a tag directly.

  7. Mugur Marculescu says:

    Thanks for the reply; I double checked my css code and found the mistake. Simply forgot to target the A and was setting the properties for the DIV instead.

  8. ali says:


    love you man – you saved me from oblivion.

    i had a fantastic rollover that worked just fine in firefox and explorer but was leaving an ugly space/gap on top of the graphic in chrome/opera/safari. i know a bit about css but not much. i was lost until i found this tut and discovered i was missing:

    margin: auto auto auto auto;
    cursor: pointer;
    outline: transparent solid 0px;

    that did the trick. dont know what it means – but it works :-))

    cheers !

  9. dave says:

    just tested this on ie6 and it goes blank on rollover 🙁 your png’s on the page go all strange too (rss image etc..). might be worth doing a small png fix.

    • David says:

      Thanks for the thoughts Dave. You are absolutely correct, and that’s because I make all my rollover buttons using a PNG file format. As a web designer, I’ve decided not to go out of my way to support IE6 unless my clients specifically request it. I think it is antiquated and almost exclusively used in corporate settings where they have custom software built around IE6. Users for sites I’ve worked on (including my own) are well below 5% and rapidly dropping. Truthfully, you just gotta pull the trigger at some point, and I already did. Thanks for pointing it out though, I appreciate it!

      If you are looking at how to implement this and have it work in IE6, just use gifs or jpgs instead and it should work just fine.

  10. Darryl says:

    I am trying to use the tutorial you did to do 3 links side by side by second link is not responding to the rollover. Am I able to use the same div name with different ids to accomplish this? The first link work but the second doesn’t. Can you help me.

  11. David says:

    Sure Darryl. Different IDs shouldn’t be a problem seeing as this CSS is built with that in mind. Here’s what your code would probably look like:

    <div class=”rollover” id=”link1″><a href=”#”>link 1</a></div>
    <div class=”rollover” id=”link2″><a href=”#”>link 2</a></div>
    <div class=”rollover” id=”link3″><a href=”#”>link 3</a></div>

    Just check to make sure that your HTML and CSS mirrors what you see above, and if you encounter more problems, share your code so I can parse it out.

  12. Joe says:

    I’m building a blog for someone and I made a tableless css layout that mostly uses floats… this was exported out of CS5 Fireworks program. I’m now creating my navigation buttons for my “social icons”. I’m debating if I should make the rollovers in CSS like your coding shows or simply put Dreamweaver rollover bottoms inside my div tag and float them left in my div container. Any reason why I shouldn’t use old school html rollover code inside the div tag?

    • David says:

      Good question Joe. This code is optimally used for very customized image buttons that have text that search engines can crawl. Because of how the CSS is applied, and how the text is written in the source code, the user sees a beautiful button, but the search engine crawls a text link. Now, if I understand what you are thinking of using, you’d lose some of the customization that you can have with these image rollovers, though you’d keep the link crawlable. I say base your decision off of how customized you wish your button to be. Also, just in case, remember that IE6 and some other browsers out there do not recognize the pseudo-class of :hover on anything but links…

  13. Audrey says:

    Thank you kindly for the tutorial; I’m using this for rollover buttons on our music department pages, and it works like a charm!

  14. Grub says:

    Thanks, so simple!!!

  15. Monica says:

    For some reason I can’t get the text to hide off the button. I copied the code just as you typed it, with the text-indent: -9999px; bit, but the text appears as a link on top of the button. I’m trying to do this in the body of a wordpress theme, but it shouldn’t matter, should it?

    • David says:

      Sorry for the delayed response, I’ve been pretty busy and just saw this. Are you doing anything different like a text-align: right that would apply to this link? I’ve seen right aligned text mess up text-indent before…

  16. ettubrutus says:

    awesome. I had never thought of doing a rollover like this. I like the fact that it cuts down on the amount of image files a method like this usually takes.

    Thank you for publishing this!!