Rollover Tabs

There are many ways to do rollovers but as a general rule of thumb you should never swap an image on hover unless the image has been seen first so that it has been cached. Otherwise there will be a delay when the element is first hovered and the result is not very pleasing.

The simplest way to achieve a smooth rollover is to load the over state of the image into the background of the list item and then place directly on top of that another background image in the anchor. This is basically stacking one image on top of another and both images get loaded when the page is called for. To make the rollover work then all we need do is to make the anchors background transparent on hover and the image underneath shines through without delay.

Here is a simple example

I have used images for the rollovers and if you look at the images you will see they are actually much bigger than we need.

Normal state of imageOver state of image

The reason I have made the images bigger is in case the user resizes the text from the browsers controls. Had we made the images exactly the size we wanted then as soon as the text was resized the layout would break badly and make no sense.That is also the reason that the nav has been size in ems as well and if you enlarge the text through the browsers control you will see that the whole nav scales up and down in perfect harmony without breaking. As the text increases in size more of the background image is revealed to complete the illusion. This is so much better than letting the layout break in an ugly fashion.

Although I have used images for the rollovers I still prefer to use text for my navigation as it is much better for SEO and accessibility. However you could include the text in the image and use one of the many image replacements techniques that abound (see some of my other demos).

Here is the code used in the above demo and as you can see it is quite logical and straight forward.


ul#cssnav {
margin:0 0 2em 17px;
ul#cssnav li {
font-family: arial, verdana, helvetica, sans-serif;
background: url(images/rollover2.gif) no-repeat left top;/* over state of image*/
width: 8em;
height: 2em;
#cssnav li a {
width: 8em;
height: 2em;
display: block;
color: #FFF;
text-decoration: none;
background: url(images/rolloff2.gif) no-repeat left top;/* normal state of image*/
#cssnav li a:hover,#cssnav li.current a {background:transparent;color:#000} /* hide anchor on hover (and set current tab)*/

Here is another example that uses a different image for each rollover and therefore more classes are necessary to identify each list item so that each element can have a different image.

As the source is fully documented I will leave to you to investigate and see how this works. There is a basic image replacement with text-indent but there are better methods of image replacement which you will find in one of my other demos.

The over (on) state of the image is placed in the background of the list and the normal state (off) is placed in the background of the anchor. This ensures that both images are loaded at run-time and are cached ready for use.

On hover the background of the anchor is made transparent and the image underneath shows through. This means there is no delay. As a general rule you should never swap an image on hover as the image doesn't get loaded until the first hover takes place and a delay is observed.


#test li{
width:80px;/*size of image*/
height:80px;/* size of image*/
#test li.first{ background:url(imgon.jpg) no-repeat left top;}/* this holds the rollover state of the image1*/
#test li.second{background:url(imgon2.jpg) no-repeat left top;}/* this holds the rollover state of the image2*/
#test li.third{ background:url(imgon3.jpg) no-repeat left top;}/* this holds the rollover state of the image3*/
#test li.fourth{background:url(imgon4.jpg) no-repeat left top;}/* this holds the rollover state of the image4*/

#test a{
#test li.first a{background:url(imgoff.jpg) no-repeat left top;}/* this holds the normal state of the image1*/
#test li.second a{background:url(imgoff2.jpg) no-repeat left top;}/* this holds the normal state of the image2*/
#test li.third a{background:url(imgoff3.jpg) no-repeat left top;}/* this holds the normal state of the image3*/
#test li.fourth a{background:url(imgoff4.jpg) no-repeat left top;}/* this holds the normal state of the image4*/

ul#test a:hover{background:transparent}
/* on hover we just hide the anchor and let the image underneath show through.
This makes for pre-loaded rolovers unlike changing the image on hover which is slow.*/

/* the above code assumes a different image for each anchor but is much simpler if only one image is used as the individual classes are not necessary. */
ul#test{text-indent:-999em}/* hide text*/

/* The code below is an ie5 bug with text indent - remove if you don't care about ie5 */
* html ul#test{text-indent:0;te\xt-indent:-999em}
* html ul#test span{text-indent:-999em;}

Another example:

Although the image are now pre-loaded and there is no delay when swapping the image you will find that IE will flick the hourglass on and off when you roll over the anchors. This even happens when rolling over an anchor that just has a background image and no rollover swap at all and is an annoying habit in IE only.

On some fast machines the hourglass flicker is barely visible but on slower machines it can flick annoyingly on an off to spoil the view. There is nothing that can be done about this (as far as i know) when using these and similar techniques. All css rollover techniques that I have seen including the manipulation of the background position technique all seem to suffer from this hourglass effect.

The only way I know to offset this effect is to have the image in the html instead of the background.

Now repeatedly flick your mouse over the links (remember this is only in ie) and you will see that the hourglass doesn't flick on at all. If you then try the same thing with the previous menu you will see that the hourglass does flick on and off rather annoyingly. The reason for this is that the anchor has no background image at all and the over state is placed in the background of the list instead. On hover the image is made invisible and the list image shows through. This makes for super fast rollovers with no flicker and no hourglass at all.

What are the drawbacks of having the image in the HTML ?

Actually the drawbacks are few and the benefits are many. Firstly the main drawback is that of course the image is now in the html and if we wanted to change the look of the site we would need to edit the html and not the stylesheet. The second drawback is obviously more code is needed in the html which makes the pages heavier. Apart from those minor problems there are not really any other problems that I can see.

The benefits are of course firstly the flicker and hourglass free rollovers that this technique allows. There are also accessibility benefits in that if the rollover was part of the main navigation then the image is in the html and the alt attribute is available to screen readers to aid with the navigation. If the images were in the background then there would be no information in the link if images were disabled or missing and then the visitor would see nothing.

If images are missing but the img tag is in the html then most browsers will display the contents of the alt attribute so there would still be a means of navigation. The same also applies if css was disabled.

As a matter of interest you could actually put the rollover state in the background of the image itself although that might seem quite strange! This will allow the background of the list to be used for other effects in a complicated layout. It is not usually realised that you can place things in the background of the image but if you think about it it is much the same as any other tag and can have a background applied.

The problem is that you won't be able to see the background because the image is in front and obscures it. We can get around this by setting the images height to zero on hover and applying an equivalent amount of padding top that equals the height of the image and will hide the image but reveal the background.

The following example shows this in action:

Note:The above image demo doesn't work in ie5 or 5.5

The code is as follows:

ul.cssnavy0 li {
font-family: arial, verdana, helvetica, sans-serif;
width: 125px;
height: 25px;
margin:5px 0;
padding: 0;
border:1px solid red;
.cssnavy1 img {background-image:url(images/over1.gif);}
.cssnavy2 img {background-image:url(images/over2.gif);}
.cssnavy3 img {background-image:url(images/over3.gif);}
.cssnavy4 img {background-image:url(images/over4.gif);}
.cssnavy5 img {background-image:url(images/over5.gif);}

ul.cssnavy0 li a {
font-size: 11px;
width: 125px;
height: 25px;
display: block;
margin: 0;
padding: 0;
color: black; text-decoration: none;
ul.cssnavy0 li a img{border:none;}
ul.cssnavy0 li a:hover {visibility:visible}
ul.cssnavy0 li a:hover img{height:0;padding:25px 0 0 0}
ul.cssnavy0 li span {position:absolute;left:5px;top:2px}

Most of the work is done in this line which reduces the height to hide the image and applies some padding so we can see the background image.

ul.cssnavy0 li a:hover img{height:0;padding:25px 0 0 0}

The beauty of css is that there is always something new to learn and if you think hard enough about something you will find a solution that you hadn't thought of before.

^ Back to Top ^