Rollover Lite: A CSS Rollover Everyone Can Enjoy

August 27th, 2008 in Design Tips & Tutorials

by: Matthew Griffin

I realize that there are about a million rollover tutorials out there. Some use JavaScript, some use CSS, but there are very few that are geared toward creating semantically correct rollovers that degrade gracefully. That's exactly what I'll be doing here.

Using rollover effects on navigation buttons has been the standard for just about as long as I've been designing websites. If fact, I still have nightmares about rollover malfunctions in Front Page 2000. Does anybody remember Front Page extensions? Fortunately, we've come a long way since then. We don't need proprietary Microsoft extensions or even JavaScript. We can do it all with CSS. In this example, I'll be using an unordered list and some links to build a horizontal navigation bar. Then I'll be adding some CSS to create a super light rollover effect. Here's the HTML:

This is a great example of semantic markup that will degrade gracefully in just about any situation. I'm using list items to contain my navigation links because that's exactly what they are: a list of links. Slap this HTML in a page and preview it in a browser and you will find that the navigation links appear and function as necessary. It's not real pretty, but it works. This should be the test for any new HTML page. When you take away the images, the style, and the Flash, does it still work?

Building the Nav Buttons

But we want more than just a website that works—we want it to look good. Next, I'm going to create a set of navigation buttons that have the inactive state of the button in the upper portion of the graphic and the rollover state in the lower part of the graphic. I'll create one of these graphics for each link. When lined up side-by-side, they should look something like this:


Now all I have to do is add some CSS to my page to make the rollovers function.

Dropping in the CSS

Adding rollover effects with CSS is actually pretty easy. First I'm going to set up my tag properties so that they  function more like

s. To do this I must set their display property to "block". Then I'll add a height and width to each element that corresponds to the graphics we created in the last step. It's important here that the height of each element is set to half of the height of its corresponding graphic. This will allow only the top half—the inactive state of the button—to show.

Next, I'll set my buttons as backgrounds for their corresponding links. Then I'll use the pseudo-class "hover" to nudge the background up when the mouse hovers over the button. This will reveal the rollover state of the graphic. Since both the inactive and rollover state of the button are downloaded together as one image, there is no need for pre-loading images and no possibility of annoying rollover delay.

Finally, in order to hide the text links that are in the actual HTML markup, I will set the text-indent property to a negative number. Here's what the CSS should look like:

#nav a {
    display: block;
    height: 30px;
    text-indent: -9999px;
#nav li { list-style: none; float: left; }

#nav li.home a { background: url(images/lite_rollover_01.gif) no-repeat; width: 92px; }
#nav li.about a { background: url(images/lite_rollover_02.gif) no-repeat; width: 131px; }
#nav a { background: url(images/lite_rollover_03.gif) no-repeat; width: 130px; }
#nav a { background: url(images/lite_rollover_04.gif) no-repeat; width: 147px; }

#nav li.home a:hover { background: url(images/lite_rollover_01.gif) no-repeat 0 -30px; }
#nav li.about a:hover { background: url(images/lite_rollover_02.gif) no-repeat 0 -30px; }
#nav a:hover { background: url(images/lite_rollover_03.gif) no-repeat 0 -30px; }
#nav a:hover { background: url(images/lite_rollover_04.gif) no-repeat 0 -30px; }

There you have it. Not only does this simple CSS rollover eliminate the flicker that JavaScript rollovers are susceptible to, it degrades gracefully and requires less code. Here's a link to a live example. Feel free to copy code and images.

One More Application

The text-indent trick is also a good one to use to increase the accessibility and search engine friendliness of graphics that contain lots of text. This goes for graphics that don't have a rollover state at all. For example I could create a

and set its background to an image with information about how to contact my business. Then I could type the information from the graphic directly into the
and set the text-indent of the
to -9999px. The graphic would be visible to the visitor and the text would be visible to search engines. This is also helpful to blind users and mobile users who have styles disabled.



Posted By: insert name here on 08/27/08

the only problem with this method is anyone with images turned off but css turned on get invisible links which isn't the most accessible solution ...

Posted By: Matthew Grffin on 08/27/08

I have to admit, in that situation the navigation would not be very accessible. However, I think I would be correct in assuming that in just about every situation CSS and images will either stay or go together. You can't make everyone happy.

Posted By: Duncan Freeburn on 08/28/08

I have only one small improvement - I've seen recommendations to place all the navigation images side-by-side in one image file (like your "lite_rollover.jpg" above). That way, there is only one HTTP request for the navigation images, increasing page load time. You can use the background-position property of each navigation element to 'bump' the background over to show the correct button. This probably wouldn't save a whole lot of page load time, but it's the principle of the thing, right?

Posted By: Philip on 08/01/09

This idea could be extended to 3 (or more images (by varying the background position) so that you could uses effects to identify pages such as visited pages, or pages the user is currently on!

Posted By: Phil Myers on 09/03/09

I use this method: In CSS: img.hover {display:none;border:0;} A:hover img.hover {display:inline;} A:hover img.nohover {display:none;} In HTML: <A HREF="#"> <img src="button1.gif" class="nohover" border=0> <img src="button2.gif" class="hover" border=0> </A>

Posted By: Phil Myers on 09/03/09

Here it is again: In CSS: img.hover {display:none;border:0;} A:hover img.hover {display:inline;} A:hover img.nohover {display:none;} In HTML:

Posted By: ERIC on 09/09/09

Um, yeah I did it just like this, but I merely made some small changes as far as the actual button sizes, & well, one button won't show up at all. I don't get it. Also, & this is just as annoying as the missing button, I cannot get it to run horizontally like your does. What the hell?! __ERIC

Posted By: ERIC on 09/09/09

Oh yeah, & they do NO rollover at ALL either! :o WTF?!

Posted By: Matthew Griffin on 09/09/09

Eric, maybe you can give me a link and I can tell you what you're doing wrong.

Posted By: Chris on 11/11/09

I've got the exact same problem. Straight copy and paste into new documents - with basic alts to apply to my image names and sizes. They seem to run horizontally, except the images are not appearing at all, just the area where the image should be.

Posted By: Another Chris on 11/15/09

I think it would be worthwhile to establish some definitive HTML/CSS code for a navigation menu using IMG tags, like what Phil was trying to attempt above... The daft thing is I pulled it off a few days back (with some handsome "Pixy fast no-preload rollovers" no less!) after a lot of amateur trial-and-error. However, when I found out about the CSS {background-image:url(#)} method of doing it, I went straight for that instead and saved over days of much slower (but ultimately desireable) code creation. I figured out too late that when images don't display, there is no ALT text to basically guide you through the website, which IMG tag-linked images will happily do if properly created... I offer a valuable transport service in a place with a lot of senior folk and I dare conject that many would have older browsers and/or 56.6k dialup, both of which are not entirely image/float friendly. They may be using obsolete standards, but that doesn't make them any less valuable as customers! IMG tags seem to be more cumbersome but fail-safe from an accessibility point of view. I am perplexed at how quickly I've forgetten my approach to it, but I do know there was a quite a bit of nesting involved. In my attempt to recreate it an hour ago, I managed half of the process but cannot get the background positions to shift and thus no more fast rollovers. Oh well, I'll keep at it for another few days until I get success!

Posted By: Another Chris on 11/15/09

Come to think of it, it may have been {background:url(#)} all along - Dagnabit! Here I was getting all excited again. No wonder I can't find anything about it on the web. Surely though, in the "1000 approaches to the same issue" nature of web developing, that someone somewhere has made it possible to make rollovers with IMG tags? To even have a hybrid of the two - where there is an image placeholder placed under a background image and becoming visible when the background image disappears (z-order perhaps?)... I dunno, maybe I'm being too ambitious!

Post Your Comment

Comments are closed.