Every now and again, I find myself wishing that I could use
something like the CSS selectors to apply some JavaScript to a load of
different elements at once. For example, imagine that you had a handful
of images that you wanted to implement rollovers on*.
Commonly, you might have an image called, say, "foo.png", and the
rollover image called "foo_on.png". With JS rollovers you need to
attach an onmouseover and
onmouseout handler to each image. If you've only got one
image then you might do it like this:
<img src="roll.gif" id="rollfirst"
onmouseover="document.getElementById('rollfirst').src='roll_on.gif'"
onmouseout="document.getElementById('rollfirst').src='roll.gif'">
which would look like this:
If you need more than one image on a page to roll over, then a
pretty common technique is to name your images specially (as I have
done; the rollover version of myimage.gif is
myimage_on.gif) and then have
rollover and rollout functions which know how
to "generically" roll over and roll out of an image:
<script type="text/javascript">
function rollover(imgID) {
// get the image object we're referring to
var thisimg = document.getElementById(imgID);
// and add "_on" to its src
thisimg.src = thisimg.src.replace(/(\.[a-z0-9]+)$/i,'_on$1');
}
function rollout(imgID) {
// get the image object we're referring to
var thisimg = document.getElementById(imgID);
// and remove "_on" from its src
thisimg.src = thisimg.src.replace(/_on(\.[a-z0-9]+)$/i,'$1');
}
</script>
. . .
<img src="roll.gif" id="roll"
onmouseover="rollover('roll')"
onmouseout="rollout('roll')">
<img src="roll2.gif" id="roll2"
onmouseover="rollover('roll2')"
onmouseout="rollout('roll2')">
which would work like this:
But this still involves adding something (whether it's a load of JavaScript or a call to a neat little encapsulated function) to every image that needs to roll over. Wouldn't it be nice if you could apply a JavaScript event handler to images, say, based on their class, with a CSS selector? So you'd want to do something like:
img.rollover {
mouseover: rollover_handler;
mouseout: rollout_handler;
}
. . .
<img src="roll.gif" class="rollover">
<img src="roll2.gif" class="rollover">
Like this, in fact:
The bit above which says:
img.rollover {
mouseover: rollover_handler;
mouseout: rollout_handler;
}
is part of a JavaScript Event Sheet. Essentially,
it looks like a stylesheet, but instead of defining style properties on
elements indicated by the selector, it defines event handlers. Inside a
block of declarations, you specify an event that can occur on the
object (common examples would be click,
mouseover, mouseout) and then the name of a
JavaScript function which should be attached as the event handler for
that event to all elements indicated by the selector.
"But who cares?", I hear you crying. "JavaScript-based image rollovers are lame anyway!"
True enough. But you can attach all kinds of things rather
conveniently here. Most of my unobtrusive DHTML scripts have a big
section, done on document load, that walks through the DOM and attaches
event handlers to specified elements. This would make that a lot
easier; just add a JSES sheet* with, say,
ul.aqtree3 in it to do the binding of event handlers.
JSES sheets are linked to a page in the same way as CSS stylesheets: with a LINK tag. Just add a tag like:
<link rel="jses" href="test.jses">
to your pages. You also need to include the Javascript library to make it work, and the WebFX XmlExtras library:
<script src="jses.js" type="text/javascript"></script>
<script src="xmlextras.js" type="text/javascript"></script>
There are a few limitations with this technique.
<jses> tag like there are <style>
and <script> tags, and we can't just make one
up.As with a lot of this stuff, it was built by standing on the shoulders of giants. In particular, WebFX's XML Extras library and Simon Willison's getElementsBySelector were crucial. Thanks, guys!
Updated 2006-01-13 to use the corrected addEvent function.
Stuart Langridge, November 2003