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.
|