HTML Dog

Skip to navigation

Sons of Suckerfish

By Patrick Griffiths and Dan Webb.

Sons of Suckerfish is a collection of articles that explain how you can best create the effects of the :hover, :active, :focus and :target CSS pseudo-classes to achieve some interesting results on just about any HTML element on just about any browser. Hey kids - A Suckerfish isn't just for dropdowns (although it's a damned good, lightweight way of making them too).

Back in November 2003, 'Suckerfish Dropdowns' was published in A List Apart. Since then it has been a popular method of applying dropdown menus thanks to its lightweight, standards-compliant, accessible, cross-browser nature.

The basic idea is that you construct a dropdown menu with CSS and then bolt on a small piece of JavaScript to mimic the :hover pseudo-class that certain browsers (namely Internet Explorer) don't fully support. This :hover mimicking could, of course, be used on any element and not only with dropdowns.

While working on a new and improved Suckerfish Dropdowns method, we got a little bit carried away and both widened the idea and made it more general. So now, not only is there a brand spanking new and improved version of Suckerfish Dropdowns with improved Suckerfish :hover JavaScript so miniscule you almost need an electron microscope to see it, there are a few siblings that have popped out to mimic other dynamic pseudo classes too - :focus, :active and :target.

This collection comprises seven articles:

The Suckerfish

Right. So, basically, in browsers such as Mozilla, Opera and Safari you can use :hover, :active and :focus to achieve the effects that the CSS standards intend. The trouble is that when it comes to anything other than links, Internet Explorer ignores these pseudo-classes (and it doesn't like :focus at all). To get around this we can use JavaScript similar to the following:


sfHover = function() {
	var sfEls = document.getElementById("nav").getElementsByTagName("LI");
	for (var i=0; i<sfEls.length; i++) {
		sfEls[i].onmouseover=function() {
			this.className+=" sfhover";
		}
		sfEls[i].onmouseout=function() {
			this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
		}
	}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);

This is the code used in the Suckerfish :hover and Son of Suckerfish Dropdowns articles.

The function sparks up once the page has loaded and loops through the elements in question (in the above example the li elements under an element with the id 'nav') and adds a class name when a particular event handler is invoked (in this case onmouseover) and removes that class name when another event handler is invoked (in this case onmouseout). With a little bit of adjustment to the CSS, this can essentially be used to mirror the behaviour of a pseudo-class (such as :hover).

The main difference between Suckerfish :hover, Suckerfish :active and Suckerfish :focus is simply the event handler that is used (Suckerfish :target is a little more complicated and explained in detail in that article).

Once the Suckerfish is in place, all you then need to do is replicate the pseudo-class selector with a standard class selector. So, for example:


li:hover { display: block }

Becomes:


li:hover, li.sfhover { display: block }

The main change from the original incarnation of Suckerfish is that the function is called using the IE only window.attachEvent() method to ensure that only IE runs it. This is slightly more accurate than the old document.all&&document.getElementById and will also allow you to add other events to onload easily without interrupting the operation of Suckerfish.

The way it finds the elements to attach behaviour to has also been changed. Now all elements underneath a container are collected, rather than just first-children, which is much more flexible and essential to the workings of a multi-level Suckerfish Dropdown for example.

Finally, a regular expression is now used to remove the class that is initially added for much greater accuracy. With the old Suckerfish, in the unlikely event that your elements already had a class like 'sfhovermonkeymonkey' applied to them and the Suckerfish was instructed to remove 'sfhover', it would have left a worthless class called 'monkeymonkey'.

The example above specifically looks for li elements within an element with an id of 'nav'. But you can manipulate the second line of the JavaScript to be even more specific or more general. For example, by adjusting the second line like so:


var sfEls = document.getElementsByTagName("LI");

The Suckerfish would apply to all li elements in a page regardless of the element they are in.

This more general approach may seem preferable because you can then have more general code, but this also adds to the work the browser has to do so the more specific you can be (such as if you know you only want to apply it to li elements in an element with a specific id), the better.

Suckerfish vs. .htc

IIIIN the blue corner we have Suckerfish, the original lightweight, accessible, cross-browser, standards-compliant :hover mimic. IIIIN the red corner we have '.htc' - the JavaScript files accessed via CSS to mimic :hover.

Ding ding!

And Suckerfish instantly lands a heavy blow on .htc's validity - .htc simply isn't standards compliant CSS.

Oooo... .htc sneaks in a crafty jab without the need for additional selectors...

Suckerfish bounces around the ring. He's much lighter weight than his opponent.

And OH! The IE 5.0 uppercut! That's something that .htc just doesn't have the skill to do, whereas Suckerfish can work IE 5.0 seamlessly.

.htc is dazed! And the contest is over! Suckerfish wins on points! TKO!

Onward!

So that's the theory. To take a closer look at how it can all be implemented, with a few examples thrown in for good measure, take a look at Suckerfish :hover, Suckerfish Dropdowns, Suckerfish :focus, Suckerfish :active, Suckerfish :target and how to bring them together with Suckerfish Shoal.