Effortless Rollovers

One of the cheapest eye-candy but still-useful effects for websites is the ubiquitous “rollover effect”. Although purists might opt to use CSS, image rollovers are really most effective in JavaScript. So, here’s my nugget of JavaScript wizardry for handling rollovers.

I’ve always felt rollovers are more a behavior than a style. Following the principle of separation of content, behaviors should really be implemented in JavaScript, not CSS. At least, that’s the way I’ve always approached it – but that’s a subject for another post.

CSS Rollovers

Now, there are cases where CSS rollovers are particularly useful. Say, for example, when you’re creating a pure text-based menu. CSS is ideal in this situation because you have very little, if any, in the way of external assets to load.

The fatal flaw of using CSS to create image-based rollovers is pre-loading. Intuitively, you would use element:hover CSS snippet with a different background-image to complete the rollover effect. However, when you load the final product off your web hosting provider you’ll find a slight-but-noticeable delay when you rollover any of your CSS :hover-enabled images for the first time. This is because the hover image doesn’t load with the rest of the page, it waits until it is requested, or until you trigger the rollover. Subsequent rollovers are as fast as you would expect – nearly instant. Once your hover image gets loaded after the first rollover is triggered it’s saved to your browser’s cache for blazing fast recall the rest of the session. Now, you might think that the slight delay on the first rollover is a livable solution, but guaranteed it will be a sore spot that makes your website feel un-refined. If you want to deliver a polished web experience, you need to pre-load your rollover images.

Really, we just need a way to pre-load the images in CSS and we’re alright, right? Unfortunately, there just isn’t a straightforward way to pre-load images in CSS. Sure, you can use some trickery with positioning elements off the page, or otherwise hidden elements, but that kind of workaround just adds superfluous content and mark-up to your HTML and CSS.

My JavaScript Solution

Re-enter JavaScript. Yeah, I said re-enter because JavaScript is how we did rollovers in the late ’90s using a primitive and un-evolved DOM – but it worked, and it even pre-loaded the images back then. So, over the course of my 10 years doing web development, I’ve written and re-written a rollover routine at least 10 times. Lately, I re-wrote it yet again with the explicit purpose to make it tiny-er and easier-to-use than ever.

So, here’s the gold I came up with:

var moz = (document.nodeName)? true:false; // Check if browser is mozilla
var ie = (document.all)? true:false; // Check if browser is ie

As usual, we need to first know which beast of a browser we’re dealing with. A long time ago, I realized there’s basically two ways of doing things: the standards way (like Mozilla) or the Microsoft way (IE == proprietary BS). Regardless, we still have to deal with them both – such is the existence of web developers.

function initRollover (element,normal,hover) {
var link = (ie)? document.all(element) : document.getElementById(element);
if (link) {
var normalImg = new Image();
normalImg.src = normal;
var hoverImg = new Image();
hoverImg.src = hover;
link.onmouseover = function () {
this.src = hoverImg.src;
};
link.onmouseout = function () {
this.src = normalImg.src;
};
}
}

This function is the heart of it. It takes just 3 arguments: element, normal, and hover. The element argument is where you specify the id attribute of the element you want the rollover attached to. Then you pass the path to your normal-state image (the regular, non-rollover image) and the hover-state image with the normal and hover arguments, respectively.

The initRollover() function will grab your element, pre-load both the normal-state and hover-state images and auto-magically attach the onMouseOver and onMouseOut events to the element. The only thing you need to do in your HTML is add the referenced id="…" attribute to the element you want the rollover effect on.

window.onload = function () {
initRollover('element-id','path/to/normal-image.gif','path/to/hover-image.gif');
}

I usually define my window.onload handler to run any functions I need after the page loads completely. Most DOM programming doesn’t behave properly if the page hasn’t loaded entirely by the time the script executes. Consider that your free bonus tip!

So, for each rollover you need, just add an initRollover() for it in your window.onload handler and you’ve got rollover magic where ever you need it. No breaking your HTML with invalid inline event handlers, perfect separation of behavior and content.

No Comments

Leave a Reply