DekGenius.com
[ Team LiB ] Previous Section Next Section

12.2 Swapping Images (Rollovers)

NN 4, IE 4

12.2.1 Problem

You want the picture displayed by an img or image-type input element to change when the user rolls the mouse over the element.

12.2.2 Solution

There are two parts to the solution. The first part is a generic and backward-compatible image swapping function, called setImage( ), that can be used by any number of images on the page. The following function assumes the existence of a custom object referencing precached images, as shown in Recipe 12.1:

function setImage(imgName, type) {
    if (document.images) {
        if (type =  = "hilite") {
            document.images[imgName].src = imagesHilite[imgName].src;
            return true;
        } else if (type =  = "normal") {
            document.images[imgName].src = imagesNormal[imgName].src;
            return true;
        }
    }
    return false;
}

Because the earliest browsers supporting swappable images did not support mouse events for img elements, the images had to be surrounded by a elements, which did respond to mouse events:

<a href="products.html" onmouseover="return setImage('products', 'hilite')"
    onmouseout="return setImage('products', 'normal')"><img name="products" 
    height="20" width="50" border="0" src="img/prodNormal.jpg" alt="Products"></a>

For IE 4 or later and NN 6 or later, you can skip the a element, and trigger the rollover directly from the img element's mouse events, provided you also program navigation you wish to associate with a click on the image:

<img name="products" height="20" width="50" src="img/prodNormal.jpg" alt="Products" 
    onmouseover="return setImage(this.name, 'hilite')"
    onmouseout="return setImage(this.name, 'normal')"
    onclick="location.href='products.html'">

image-type input elements provide mouse event support for the same generations of browsers, so you can use the same event handlers just shown inside an <input> tag to accomplish the rollover task with an image form control.

12.2.3 Discussion

Despite the apparent complexity of wrapping an image inside a hyperlink just to make an image rollover work, the scheme takes advantage of the inherent behavior of the hyperlink. For example, as the user rolls over the link, the destination URL appears in the status bar (unless scripted to display something else), a common creature comfort of experienced web surfers. But more important for public sites, search engine spiders and bots look for a elements and their href attributes to follow the bread crumbs through a site for indexing purposes. If your navigation is entirely scripted, the spiders won't get past this one page, perhaps lessening the chances of your other pages being indexed for users to find.

In both of the HTML portions of the Solution, note that the img element uses the name attribute. While that attribute validates in all HTML 4.01 varieties, it does not validate in strict XHTML 1.0. If that level of validation is important to you, substitute the id attribute for the name attribute. In the <img> tag, the first parameter of the setImage( ) function calls is this.id. Then, inside the setImage( ) function, replace document.images["imgName"] references with document.getElementById( ) to reference the img element objects:

document.getElementById(imgName).src = imagesHilite[imgName].src;

If I were designing a rollover system that works exclusively on modern browsers, I would move the event handlers out of the elements (furthering the goal of distancing content from design and scripting), and take advantage of advanced event propagation and handling to perform the rollovers. Top-level (i.e., at the document node point) event binding and event processing could occur in an external .js library file.

document.onmouseover = setImage;
document.onmouseout = setImage;

The <img> tag (which would still be inside an <a> tag if the image is to act as a link) has nothing more than typical attributes (including a class name identifying it as a swappable image on the page), as in this XHTML example:

<img id="products" class="swappable" height="20" width="50" 
src="img/prodNormal.jpg" alt="Products" />

All the heavy lifting occurs in the event handler function, which processes the mouse events only for those elements of the "swappable" class:

// generic swappable image changer
function setImage(evt) {
    if (document.images) {
        // equalize W3C and IE event objects
        evt = (evt) ? evt : ((window.event) ? window.event : null);
        if (evt) {
            // equalize W3C and IE event property
            var elem = (evt.target) ? evt.target : 
                       ((evt.srcElement) ? evt.srcElement : null);
            // filter out older browsers (elem=  =null) and unswappable elements
            if (elem && elem.className =  = "swappable") {
               // let event type govern state
                switch (evt.type) {
                    case "mouseover":
                        elem.src = imagesHilite[elem.id].src;
                        break;
                    case "mouseout":
                        elem.src = imagesNormal[elem.id].src;
                        break;
                }
            }
        }
    }
}
// top-level event handlers grab bubbled events
document.onmouseover=setImage;
document.onmouseout=setImage;

In the more recent browsers (IE 5 or later and NN 6 or later, but not Opera through Version 6), you can even accomplish link rollovers without img elements or scripting. Instead use CSS to define style rules for a block-level a element for both normal display and highlighted display, the latter occurring during what CSS calls a "hover" of the cursor over a link. The style rules for a "Products" image link look as follows:

a#products {background:url(prodNormal.jpg); display:block; height:20px; width:50px}
a#products:hover {background:url(prodHilite.jpg)}

In the HTML, all you need is the a element set with an ID associated with the style sheet rules:

<a id="products" href="products.html">...</a>

You need a pair of style sheet rules for all the a elements, each with a unique ID. The key to making this work is the display style sheet property for the a element. This forces the empty link to open to the block size specified in the rule.

12.2.4 See Also

Recipe 12.1 for precaching images; Recipe 3.8 for working with custom objects; Recipe 9.1 for cross-browser event handling.

    [ Team LiB ] Previous Section Next Section