English-only | Jenom česky | Bilingual/Dvojjazyčně

CSS Technique: Fast Rollovers Without Preload

When using CSS image rollovers, two, three, or more images must be loaded (and often be preloaded for best results). We've got one image for each state (normal, hover, active, visited etc). Putting all states into one image makes dynamic changes faster and requires no preload.

Let's have a simple example. The menu items are the a-elements with display:block. Proper padding and background image for a, a:hover and a:active make the rollover. To simplify the rollover, I used only one picture containing three states of a button — normal, :hover, and :active.

rollover background image

Fig. 1: Three states together in one image

Usually, in CSS rollovers, we use background images in this way:

#menu a {
   ...
   background: url("button.gif") top left no-repeat;
   }
#menu a:hover {
   ...
   background-image: url("button-over.gif");
   }
#menu a:active {
   ...
   background-image: url("button-active.gif");
   }

/* etc... */

Using one common picture, we don't need to change the background image. We just change its background-position. The :hover state will use the background image moved proper count of pixels (in the example the shift is 157px to the left), the :active state will use bigger shift (by 314px in the example).

#menu a {
   background: url("button.gif") 0 0 no-repeat;
   ...
   }
#menu a:hover {
   background-position: -157px 0;
   ...
   }
#menu a:active {
   background-position: -314px 0;
   ...
   }

That's all. Just one image is used. No preload is needed. State switching is as fast as possible (moving background position is much faster than replacing background image). AFAIK, it works in every CSS2 capable browser (IE5+, Mozilla, Opera, Safari etc.)


Update

Simple yet strong update comes from Marek Blaha (Czech author). This workaround solves the problem when Windows IE sometimes slowly reloads the background image. It causes the element flickers while mouse hovering.

The solution is just simple: the background image (moved to the "hover position") is attached to the outer element, and the same background is attached to the inner A element as well (in the "base position", though). The :hover state just changes the A's background to transparent making the 'outer' background bellow visible. Thus, no background is beeing switched and IE has no more reason to flicker.

Check the source code of the Example 2 to see the solution at work. It works fine in every browser I've met (excluding MacIE, which fails here)...