Mouseover Images

One of the most popular "wow" items that’s popping up all over the World Wide Web is the mouseover. In its simplest form, the mouseover is some part of a Web page that causes a change in the page display when the user’s mouse passes over it. More and more creative uses for mouseovers show up all the time, from providing visual cues to the meanings of links on a page, to adding full, fly-out, cascading menu systems in DHTML (see my popup menu script for a good example of this).

Mouseovers first became technically possible with the release of Netscape Navigator 2.0, which included a new scripting language called JavaScript. The idea was to allow the Web to transcend for the first time the basic functionality of HTML. With JavaScript, Web developers were able to do more than just jump to a new location when a user clicked on a hypertext link — they could actually modify the contents of the currently-loaded page. When Microsoft released their own Web browser, Microsoft Internet Explorer 3.0, they included their own variation on the theme — JScript. Recently Microsoft and Netscape have agreed to settle on a vendor-neutral standard, which is being developed by the European Computer Manufacturers Association under the name ECMAscript.

As standards in this area converge, the use of scripting on the Web is becoming more feasible. The swell in popularity of the script-powered mouseover (as opposed to the comparatively slow and clunky Java implementations that were popular for a brief time) is a testament to the usefulness of JavaScript and its kin.

The Image Object

Strictly speaking, you don’t need to know any JavaScript to understand this article, as everything is explained from the ground up. However, if you haven’t had much programming experience and don’t know any JavaScript at all, you might want to read SitePoint’s JavaScript 101 if it really starts to look to you like I’m writing in Greek.

In most respects, JavaScript is an object-oriented language, which means that in the world of JavaScript, everything is an object. A browser window is an object (referred to as the window), a Web page is an object (the document) and the images in the Web page are objects in their own right. The nice thing about objects is that they have properties that you can change.

If you are familiar with the basics of HTML (check out our HTML Tutorial if you’re not), you’ll be used to the concept that you can create an image object on a Web page using the <IMG> tag:

<IMG SRC="imagefile.gif" WIDTH="75" HEIGHT="40"> 

Now, without knowing it, when you type this, you automatically create a JavaScript image object, which will allow you to change its properties later on if you like. This is exactly what we want to do to create a mouseover. When the mouse moves over the image we want to change what the image looks like, and what the image looks like is a property of the image object.

To simplify referring to this particular image object later on, we can assign it a name. This is pretty easy to do, and just requires us adding the NAME attribute to our <IMG> tag.

<IMG SRC="imagefile.gif" NAME="myimage" WIDTH="75" HEIGHT="40"> 

Now our image object is named "myimage", and can be referred to as such. At this point, it’s worth pointing out that JavaScript is largely case sensitive. In other words, our image named "myimage" cannot be referred to as "MYIMAGE" or "MyImage".

I’ve said that objects in JavaScript have properties that we can change. We can set a property of our "myimage" object with the following general JavaScript statement:

document.images["myimage"].property = newvalue; 

Where property is the name of the property you want to change, and newvalue is the new value you are assigning it. This line can be read:

"In the current document, in the image called "myimage", set property to newvalue."

By now I’m sure you’re itching to know how to apply this to the humble mouseover. Well in a mouseover, we change the image displayed by the image object. Just as in HTML, where we use the SRC attribute of the <IMG> tag to indicate the URL of the image file we want to display, in JavaScript we set the src property of the image object to the URL of the image file we want it to display.

Using the general JavaScript statement I showed you above, this is written simply:

document.images["myimage"].src = "newimage.gif"; 

How Mouseovers Work

Now that you know how to change an image’s appearance using JavaScript, we need to figure out how to do this when the user places the cursor over the image. Also, we need to know how to switch it back again when the user’s mouse isn’t over the image anymore. The feature of JavaScript that allows us to do this is called event handlers.

Event handlers can be thought of as "triggers" that cause things to happen when a certain condition is met. The two event handlers that interest us when it comes to Mouseovers are onMouseOver and onMouseOut. These allow you to define certain pieces of JavaScript to be run whenever the user’s mouse hovers over or passes out of a given HTML element.

While the HTML 4.01 specification says that we should be able to define onMouseOver and onMouseOut event handlers for any HTML element, Netscape Navigator falls a bit short by only providing this facility for the anchor reference (<A HREF>) tag. This means that Netscape can only detect the mouse moving over and out of hyperlinks, and if we want to make a Mouseover, the element that is "sensitive" to the mouse must be a link. This isn’t too much of a problem if we want to make a mouseover that isn’t also a link, because we can easily make a "link to nowhere" around our image as follows:

<A HREF="javascript:void(0)"><IMG SRC="imagefile.gif"   
NAME="myimage" WIDTH=75 HEIGHT=40 BORDER=0></A>

This creates a link that does nothing (void) when clicked. If you did want it to link to something, you’d just stick your URL in the place of javascript:void(0). To add our event handlers is as simple as inserting them as attributes to the <A HREF> tag:

<A HREF="javascript:void(0)" onMouseOver="overmyimage()"   
onMouseOut="outmyimage()"><IMG SRC="imagefile.gif" NAME="myimage"  
WIDTH=75 HEIGHT=40 BORDER=0></A>

In the above, overmyimage() and outmyimage() are JavaScript functions that handle changing the image between the "on" and "off" states. A function is a piece of JavaScript that has been set aside to be "triggered" at some later time. In most cases, functions are defined in the header of your HTML file (between the <HEAD> and </HEAD> tags). Our overmyimage() function would look something like this:

<HEAD>  
<SCRIPT LANGUAGE="JavaScript">  
<!-- Hide from older browsers  
 
function overmyimage() {  
... code here ...  
}  
 
// End script hiding -->  
</SCRIPT>  
</HEAD>

We would insert the code that’s to be run whenever this function is called (triggered) at the spot I’ve indicated.

Now, armed with a basic knowledge of the image object, event handlers, and functions, we are now ready to create…

Our First Mouseover

If you’ve been following closely and fully understand the elements I’ve covered so far, their assembly into a working mouseover should be almost obvious. If you’re a bit confused though, don’t worry — I’ll take you through it step by step in this section so that everything becomes clear.

First, let’s start by creating our image. It will be 70 pixels wide and 30 pixels high, and the filename for the "inactive" image will be "off.gif". We do this just as we would normally, using the HTML <IMG> tag. We’ll also use the NAME attribute to assign it the name "my1stMouseOver".

<IMG SRC="off.gif" WIDTH=70 HEIGHT=30 BORDER=0 NAME="my1stMouseOver"> 

Now we’ll add a "link to nowhere" around our image, so that we can hook in onMouseOver and onMouseOut event handlers, set to trigger JavaScript functions that "activate" and "deactivate" the image. Appropriately enough, we will call these functions activate() and deactivate().

<A HREF="javascript:void(0)" onMouseOver="activate()"   
onMouseOut="deactivate()"><IMG SRC="off.gif" WIDTH=70  
HEIGHT=30 BORDER=0 NAME="my1stMouseOver"></A>

Now all that’s left is to write the JavaScript functions, activate() and deactivate(). The activate() function will change the src property of the "my1stMouseOver" to the "active" image file, which we’ll call "on.gif".

function activate() {  
document.images["my1stMouseOver"].src = "on.gif";  
}

Similarly, the deactivate() function will change the src property of the "my1stMouseOver" back to the "inactive" image file, "off.gif".

function deactivate() {  
document.images["my1stMouseOver"].src = "off.gif";  
}

And that’s it! We’ve now created an image that displays "off.gif", except when the user places the mouse pointer over it, at which time it changes to display "on.gif". When the user moves the mouse away again, it goes back to displaying "off.gif".

See it in action! | View the code

In the following sections, we’ll take the basic mouseover that we created in the last section and add a couple of bells and whistles that will improve its expandability and performance. Overall, these are good skills to know if you’re going to be making serious use of mouseovers in the pages you design.

Sharing Functions

In our basic mouseover, we used one <IMG> tag and two JavaScript functions to obtain the effect we were looking for, but on a page with 5 mouseovers, that would mean having to write 10 different functions (not to mention coming up with 10 different names for them!). What if there was a way to use the same two functions for all the mouseovers on your page?

As it turns out, this is surprisingly easy to do. First, we must create JavaScript variables that contain the filename of each mouseover’s "on" and "off" image. If, for example, we had created a page with three <IMG> tags that we wanted to be mouseovers, and we’d named these images "first", "second" and "third" using the NAME attribute of the <IMG> tag, we would create variables with names of the form name_on and name_off, like this:

var first_off = "image1off.gif";   
var first_on = "image1on.gif";  
var second_off = "image2off.gif";  
var second_on = "image2on.gif";  
var third_off = "image3off.gif";  
var third_on = "image3on.gif";

The next thing we have to do is set up the onMouseOver and onMouseOut event handlers to pass the name of the image to change to our functions. For example, the code for our "second" Mouseover would look like this:

<A HREF="second.html" onMouseOver="activate('second')"    
onMouseOut="deactivate('second')"><IMG SRC="image2off.gif"  
WIDTH=70 HEIGHT=30 BORDER=0 NAME="second"></A>

Notice that the argument (the text to be passed to the function) is surrounded by single quotes ('). This is so that they don’t interfere with the double quotes (") that surround the event handler.

By passing the name of the image to be changed to our activate and deactivate functions, we give them a way to know which image to change when they’re triggered. This is how we manage to share the two functions between as many mouseovers as we want. All that’s left is to modify these functions to receive this image name, and use it to modify the correct image.

The code for our new functions will look like this:

function activate(imgName) {   
document.images[imgName].src = eval( imgName + "_on" );  
}  
 
function deactivate(imgName) {  
document.images[imgName].src = eval( imgName + "_off" );  
}

By placing the word imgName between the parentheses that follow the name of the functions, we tell them to accept a value that’s being passed to them (in this case, the name of the image to change), and stick it into a variable called imgName until we finish processing the function. We then make use of this variable in two places. First, we use it to indicate which image object who’s src property we want to change (images[imgName]). Second, we use it to refer to the variable that contains the correct filename. This is done using the eval(...) built-in function.

eval( imgName + "_on" ) 

All this does is takes the value of the imgName variable, sticks it together with the piece of text "_on" and then evaluates the result as if it were a normal piece of JavaScript code. To make this as clear as possible, let’s go through what would happen if the onMouseOver event handler were triggered on the image named "third".

When the onMouseOver event handler is triggered, it runs the activate function, and passes it the name of the image — "third". The function accepts this argument, and places "third" wherever the variable imgName appears.

function activate("third") {   
document.images["third"].src = eval( "third" + "_on" );  
}

The eval(...) built-in function sticks the two strings it has together (as indicated by the ‘+‘ operator) and then evaluates it as if it were a normal piece of JavaScript:

document.images["third"].src = third_on; 

Now third_on is the name of the variable containing the "on" image filename for the "third" image, so its value is substituted in:

document.images["third"].src = "image3on.gif"; 

And that’s it — we’re left with a statement of the same form we used for our basic mouseover, which will change the src property of the "third" image to "image3on.gif"! The key was in naming the variables that contained the filenames so that the eval(...) function could come up with the variable name by just tacking "_on" or "_off" onto the end of the name of the image.

See it in action! | View the code

Preloading Images

Most Web browsers these days are pretty smart. When they load something, they put it into a cache on your system where it will remain for a little while for quick and easy access in case it’s needed again. Most browsers aren’t smart enough to load things ahead of time, though. In most cases, this isn’t a big problem, but when it comes to mouseovers it can be an unsightly weakness.

When a user places the cursor over one of your mouseovers, the Web browser will realize it needs to display the "on" image. If this is the first time this user accesses your site, chances are that image isn’t in the cache, and must be loaded from your site. This causes a delay that can often be longer that it takes for the user to have moved the mouse back off the mouseover, having never seen that pretty light-up button you’d planned to display. Worse, if the "on" image is only partially loaded, the user may see a horrible, blurry mess in the place of the slick image you’d planned.

How do we overcome this problem? The solution is to preload the images required by the mouseover into the user’s cache so that we can be sure they’re available before we attempt to display them. To do this, we must make creative use of the JavaScript image object.

Up until now, we’ve only created image objects with the standard HTML <IMG> tag. We can, however, create them using only JavaScript. Such JavaScript-only image objects do not display on the Web page, but they do load and cache, and they have the same properties as an image object created with HTML. The strategy, then, is to create JavaScript-only image objects for every one of the image files to be used in your mouseovers. To do this for our example of the three mouseovers used in the previous section, we can replace our variable declarations with the following image declarations:

var first_off = new Image();    
first_off.src = "off1.gif";    
var first_on = new Image();    
first_on.src = "on1.gif";    
   
var second_off = new Image();    
second_off.src = "off2.gif";    
var second_on = new Image();    
second_on.src = "on2.gif";    
var third_off = new Image();    
third_off.src = "off3.gif";    
var third_on = new Image();    
third_on.src = "on3.gif";

For each image file, we create a new image object, then set its src attribute to the appropriate filename. In setting this property, the browser decides it needs to download the image file, at which point it is stored in the cache for quick retrieval when it is actually needed for display. We obey the same naming convention for the image objects as we did for the filename variables in the previous section.

Now all that’s left is to adjust our activate and deactivate functions (yes again) so that they use the values of the src properties of the JavaScript-only image objects instead of the values of the variables.

function activate(imgName) {    
document.images[imgName].src = eval( imgName + "_on.src" );    
}    
   
function deactivate(imgName) {    
document.images[imgName].src = eval( imgName + "_off.src" );    
}

Finally, we can make one more adjustment to make doubly sure that the user never sees a half-loaded image. Although this preloading technique does load the mouseover images ahead of time, it is still possible for the user to trigger a mouseover before the images have completely loaded. To guard against this, we put a little "valve" in the activate and deactivate functions:

function activate(imgName) {    
if ( eval(imgName + "_on.complete") ) {    
document.images[imgName].src = eval( imgName + "_on.src" );    
}    
}    
   
function deactivate(imgName) {    
if ( eval(imgName + "_off.complete") ) {    
document.images[imgName].src = eval( imgName + "_off.src" );    
}    
}

This makes use of another property of the JavaScript image object. We already know the src property contains the URL of the image file it represents. Here we use the complete property, which is true if the image has completed loading, and false if it has not. These newly-modified versions of activate and deactivate only change the displayed image if the JavaScript-only image object responsible for preloading the new image is complete.

See it in action! | View the code

Advanced Techniques

Finally, this section will show you a simple way to make sure your mouseover pages are compatible with older browsers, as well as a neat trick to prevent preloading mouseover images from slowing down the rest of your page.

Browser Compatibility with Object Detection

Now that you know all about how to make mouseovers that work well, it’s worth taking a moment to learn how to make ones that don’t work just as well. While mouseovers of the type I’ve outlined up until now will work consistently on all recent JavaScript-enabled browsers (Netscape 3+, as well as MSIE 4+), there are some browsers that support JavaScript, but don’t fully support the image object.

One such browser is Microsoft Internet Explorer 3.0. If we were to load a page that contained mouseovers with the code I’ve used up until now on MSIE 3.0, we’d see a lot of ugly JavaScript errors. Since we can’t do Mouseovers on this browser, the least we can do is get rid of the error messages.

While there are several ways to detect the version of the user’s browser in JavaScript and react accordingly, such techniques can sometimes prove unpredictable in the face of less mainstream Web browsers. Also, whenever either Netscape or Microsoft release a new version of their browser software, any page using such browser detection scripts would need to be updated.

Much more reliable and efficient is a little-known technique called object detection. The idea is that, instead of detecting the version of the browser, we detect the features that the browser supports. As any browser that supports the image object will be capable of mouseovers, we need only detect whether or not the browser knows what image objects are before we do anything that requires support for them. This is done with a simple if statement:

if (document.images) {     
... code here ...    
}

Which can be read:

"If the current document contains images then do the following…"

If we add an if (document.images) to the activate and deactivate functions, and place one around the image declarations, we’ll have mouseovers that quietly disappear on browsers that don’t support the image object.

See it in action! | View the code

Delaying Image Loading

Preloading images is all well and good, but what if you have 20 mouseovers on a given page? Do you really want to have the browser busy downloading 20 images before it even gets to start loading the actual content of the page? Usually not. A nice way around this is to use the onLoad event handler of the <BODY> tag to trigger a function that loads the mouseover images only after the HTML code for the page has been loaded. This way, all the images actually displayed on the page are put ahead of the mouseover images in the download order.

The use of onLoad is fairly straightforward:

<BODY onLoad="loadImages()"> 

All that’s left is to put the preloading of the mouseover images inside the loadImages() function.

if (document.images) {     
var first_off = new Image();    
var first_on = new Image();    
   
var second_off = new Image();    
var second_on = new Image();    
   
var third_off = new Image();    
var third_on = new Image();    
}    
   
function loadImages() {    
if (document.images) {    
first_off.src = "off1.gif";    
first_on.src = "on1.gif";    
   
second_off.src = "off2.gif";    
second_on.src = "on2.gif";    
   
third_off.src = "off3.gif";    
third_on.src = "on3.gif";    
}    
}

Be sure to notice that I’ve left the creation of the JavaScript-only image objects outside the loadImages() function. This is done for two reasons. First, the creation of the objects doesn’t load any files: only the setting of the src properties does that, so leaving the object declarations outside the function won’t slow down the loading of the rest of the page. Second, objects or variables that are created inside a function only exist inside that function. If we were to move the creation of the image objects inside the function, they would disappear as soon as the function finished running, and then the activate and deactivate functions would no longer be able to use them.

That’s it! Now our mouseover images will only be loaded when the onLoad event handler of the <BODY> tag is triggered, and this only happens once the HTML code for the whole page has been loaded, and any images on that page have started loading. Whether this is desirable or not is up to you to judge, but it can be a good idea in cases where there are a lot of mouseovers on a page and their being immediately available is not that important.

See it in action! | View the code

In Summary

In this article I’ve endeavored to present a complete picture of the techniques involved in making Web page elements respond to the movement of the user’s mouse. Not only did I cover the basics in terms that, hopefully, were accessible to anyone with a rudimentary knowledge of Web design and general programming, but I also covered some more advanced topics that would prove useful to the more experienced Web developer.

More information related to this article can be found at:

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.