Mouseovers

This new script only works in W3C DOM compatible browsers. If you must satisfy old browsers, too, try the old script.

One of the most popular and widespread scripts is the standard image-swap mouseover. When the user moves over an image, the image changes slightly, giving a nice effect. In fact, you load a different image at the place the first image was.

This new script makes mouseovers far simpler than they ever have been.

These are the mouseover images:

Note the light weight XHTML. I have done away with all inline event handlers, no more onmouseover="over(1)" and similar trash in our beautiful XHTML!

<ul id="mouseovers">
<li><a href="intro.html"><img src="pix/mo_home.gif" width="80"
	height="50" border="0" /></a></li>
<li><a href="placejs.html"><img src="pix/mo_place.gif" width="80"
	height="50" border="0" /></a></li>
</ul>

The script

The script below adds mouseover behavior to all images in the <ul id="mouseovers">. Run init() onload and it works.

var W3CDOM = (document.createElement && document.getElementsByTagName);

var mouseOvers = new Array();
var mouseOuts = new Array();

window.onload = init;

function init()
{
	if (!W3CDOM) return;
	var nav = document.getElementById('mouseovers');
	var imgs = nav.getElementsByTagName('img');
	for (var i=0;i<imgs.length;i++)
	{
		imgs[i].onmouseover = mouseGoesOver;
		imgs[i].onmouseout = mouseGoesOut;
		var suffix = imgs[i].src.substring(imgs[i].src.lastIndexOf('.'));
		mouseOuts[i] = new Image();
		mouseOuts[i].src = imgs[i].src;
		mouseOvers[i] = new Image();
		mouseOvers[i].src = imgs[i].src.substring(0,imgs[i].src.lastIndexOf('.')) + "_omo" + suffix;
		imgs[i].number = i;
	}
}

function mouseGoesOver()
{
	this.src = mouseOvers[this.number].src;
}

function mouseGoesOut()
{
	this.src = mouseOuts[this.number].src;
}

Image names

This script expects the names of the mouseover images to be exactly the same as the names of the normal images, except that they have an extra _omo suffix. So my example uses the following images:

Make sure all your images conform to this naming scheme. If they don't, the script doesn't work.

Explanation

First of all we check whether the browser supports the W3C DOM.

var W3CDOM = (document.createElement && document.getElementsByTagName);

Then we create two arrays mouseOvers and mouseOuts. These serve to store all images related to the mouseovers.

var mouseOvers = new Array();
var mouseOuts = new Array();

The reason we store the images in these arrays is preloading. If we immediately load the mouseover images they are already available in the browser's memory when the user mouses over them. If we didn't preload them, the user might have to wait a few seconds before seeing the mouseover image.

Blah!

window.onload = init;

Then we start our init() function which prepares the ground for our mouseover behavior. If the browser doesn't support the W3C DOM we end it immediately: there's no point in continuing.

function init()
{
	if (!W3CDOM) return;

Then we take all <img> elements that are descendants of the element with id="mouseovers". In my example this element is a <ul>, but it could be anything.

	var nav = document.getElementById('mouseovers');
	var imgs = nav.getElementsByTagName('img');

We loop through all <img> tags.

	for (var i=0;i<imgs.length;i++)
	{

Each <img> tag receives a mouseover and a mouseout event handler, so that it executes the necessary script onMouseOver and onMouseOut. Below I describe these scripts in more detail.

		imgs[i].onmouseover = mouseGoesOver;
		imgs[i].onmouseout = mouseGoesOut;

Immediately afterwards we store the normal image and the mouseover image in their respective arrays. The normal image has already been loaded, but the browser now fetches the mouseover image, so that it will be available when the first mouseover event takes place.

First we find out which suffix (.gif, .jpg, .png, whatever) the image uses.

		var suffix = imgs[i].src.substring(imgs[i].src.lastIndexOf('.'));

We create an entry in the mouseOuts array and store an Image object with a src property. This Image object is of course none else than the image that's already shown. It is this image that we should restore onMouseOut.

		mouseOuts[i] = new Image();
		mouseOuts[i].src = imgs[i].src;

Then we create an entry in the mouseOvers array and do the same. Here we have to fetch a new image. Since the script knows that the only difference between the names of the normal and the mouseover images is the _omo bit, we can easily concatenate the name of the mouseover image.

		mouseOvers[i] = new Image();
		mouseOvers[i].src = imgs[i].src.substring(0,imgs[i].src.lastIndexOf('.')) + "_omo" + suffix;

Finally we add a number property to the <img> tag itself. It will serve to retrieve the correct mouseover and mouseout images from our two arrays.

		imgs[i].number = i;
	}
}

Everything is ready, we wait for the user to mouse over. If he does, we execute the mouseGoesOver function. This function uses the this keyword, which refers to the image the user mouses over.

We set the src of the image to the correct mouseover image. We know which mouseover image we need by using the number property we set in the init() function.

function mouseGoesOver()
{
	this.src = mouseOvers[this.number].src;
}

onmouseout we restore the original image in the same way.

function mouseGoesOut()
{
	this.src = mouseOuts[this.number].src;
}

That's all. Clean mouseovers without ugly inline event handlers.