Film-strip rollovers: a simpler way to do rollovers

by Joe Gillespie — Apr 1, 2004

JavaScript rollovers are unnecessarily complicated requiring a set of normal and 'over' images to be preloaded into the browser before they work correctly. The code then swaps one image for another based upon an 'onmouseover' event.

What I'm going to describe here is an alternative method of achieving the same effect that has several advantages. It uses less code, loads more efficiently and makes it simple to have multiple button states.

First a little history. Back in the 1980s, Apple had a wonderful little program called HyperCard. HyperCard was essentially a black and white program that made it very easy to produce interactive multimedia titles.

When colour Macs were introduced in the late '80s, HyperCard still had only very rudimentary support for colour and along with a few others, I developed a technique for producing 'rollover' buttons, in colour, and used them in projects for Apple, UK. The technique involved importing a large image file into a small picture box where it would be 'clipped' - much like looking though a small rectangular hole in a piece of paper at a larger image behind. By moving the background image in steps, you get a different view with each shift. This is exactly how movie film works. Different images are quickly moved into place as the films passes through the projector's 'gate'

I have now adapted this same technique to use on Web graphics.

Instead of swapping multiple images with JavaScript, these 'film-strip' rollovers only use one 'composite' image. If the various visual button states are placed on an image like a strip of movie film and the button is only the size of one frame, you can only see one state at a time. This is made possible by a CSS div's background image position property. The background image can be three or four times the size of the actual div itself, the different states are created by simply shifting the background image's x or y position. I'm only moving the y in these examples but it would work equally well with the x - or even both.

three button states

Here is a composite image with three button states, each 24 pixels high. You will recognise the similarity to a strip of movie film.

In the diagram below, I have given the button a red frame for clarity, it wouldn't normally have one. The hidden parts are dimmed.

button sequences

  1. The button (div) is 86 x 24 pixels and can be placed on the page with absolute or relative positioning.
  2. The background image, by default, has an x and y position of zero. I've also set it to 'no-repeat'.
  3. If the y position is shifted to -24 (with JavaScript), the whole background image moves up one 'frame' showing the 'over' state of the button. If you only want two states, you only need two frames but this technique makes it very easy to have multi-state buttons. I'm using three to give an extra 'clicked' state.
  4. Like text links, buttons can also have active and visited state - and anything you like in-between. By shifting the y position to -48, we get an 'active' or 'clicked' state.

The JavaScript function that does all this is very short and sweet. Compare this to the amount of stuff you need for conventional image-swap rollovers. The n parameter is the number of the button (so that we can use the same script for several, similar buttons) and y, the vertical position.

function fsButton(n,y) { if (document.getElementById) { var button = document.getElementById("b"+n); button.style.backgroundPosition="0px"+y+"px"; } }

To call this JavaScript, we use onmouseover and onmouseout as usual and can add onmousedown and onmouseup actions too, to provide the additional visual states, if required.

Of course, we have to attach these actions to an anchor, but we can't use the background image for that. We could use text and try to centre the button caption in the div but text in tight spaces can cause all kinds of problems. Instead, I'm going to use another image – a transparent GIF or PNG.

As this is a demonstration rather that a real situation, the text on the button is changing according to the rollover state so I'm using an empty, clear GIF foreground image and the words are part of the background image. In the more usual situation where you have several buttons with different text on them, the buttons would all share a common background image and have a different transparent GIF foreground image inside the div.

Using a single, shared, background image is more bandwidth-efficient than loading lots of separate button state images. In speed terms, one 300 byte image will download faster than three 100 byte images – as there is only one request to the server instead of three.


 

The y position for the 'normal' state is 0, the 'over' state is -24 and the 'clicked', or 'active' state is -48.

The CSS style for the button looks like this...

#b1 { position: relative; float:right; overflow: hidden; width: 86px; height: 24px; background-image: url(../img/but1.png); background-repeat: no-repeat; background-position: 0 0; }

Here is a slightly more elaborate button done with Photoshop layer effects. The principle and code are exactly the same, only the image is different.

button 1
button 2
button 3

Then, if we want a bank of buttons, it's only necessary to add more selectors to the styles. You don't need a separate style for each button unless the background changes.

#b3, #b4, #b5 { position: relative; float:right; overflow: hidden; width: 92px; height: 30px; background-image: url(../img/glassbut.png); background-repeat: no-repeat; background-position: 0 0; }

Here, we use exactly the same background image for each button just changing the foreground image and the button number in the script for each one...

Button 3 etc.

 

You might notice that I've 'snuck' something else in here – this is an optional extra. onfocus="doBlur(this)". Microsoft Internet Explorer puts a particularly ugly outline around images that have links attached to them regardless of which rollover method you use. This is supposedly to indicate the tabbing order for people who use a keyboard instead of a mouse for navigation, okay, but other browsers manage to do this in a more tasteful way. This function removes that outline in Explorer but if you feel that you might need the outlines for accessibility reasons, just leave that bit, and the following function out.

function doBlur(n) { if (navigator.userAgent.indexOf("MSIE")!=-1) { n.blur(); } }

So, there you have my 'film-strip' rollovers. This tutorial has only scratched the surface. With a little imagination, it is possible to do some very weird and wonderful things using this technique including animation - with GIFs, JPEGs and PNGs.

Finally, some small print. Like most CSS-dependent techniques, these tricks work fine in modern browsers, but not in old ones. If you absolutely must support legacy browsers like Netscape 4.x, it's a good idea to provide an alternative page or stylesheet.

Del.icio.us Digg Technorati Blinklist Furl reddit Design Float