Son of Suckerfish dropdowns in jQuery

September 22nd, 2008  |  Published in Uncategorized  |  2 Comments

If you’ve never heard of Suckerfish menus, they’re a simple way to get drop-down menus working in IE6. IE6 has lacks many features of modern browsers. One of the most important missing features is the ability to define hover pseudo classes to elements other than A (anchor links). The original Suckerfish dropdown code from A List Apart is as follows:

startList = function() { if (document.all && document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {this.className+=" over"; }
node.onmouseout=function() { this.className=this.className.replace(" over", ""); }
}
}
}
}
window.onload=startList;

As you can see, this code isn’t very neat and fails if “over” is part of another class name. It also overrides any other onload events you have and only runs the code when the page (including images) is fully loaded. The site HTML Dog updated the code to Son of Suckerfish dropdowns:

 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 much neater and uses a nice regular expression to remove the class name. It also uses Microsoft’s attachEvent, which is much easier to make non-distructive. There is still a problem with this: the code only executes when the page is fully loaded. What we really need is to wait until the DOM is ready to be manipulated, then run the code. Unfortunately, as we’re aiming this code at IE6, we can’t just do a document.addEventListener(”DOMContentLoaded”, sfHover). The only way we can get a DOM ready event is by creating an empty script with defer=”defer” and listen for it to load, then run our code. This was thought up by Matthias Miller.

The code is now starting to get more complex. We’re also going to be creating functions we’ll probably reuse in the future. Instead of writing our functions from scratch, we’ll use a jQuery, a JavaScript library to do most of the hard work for us.

The jQuery version:

$(function() {
$("#nav li").hover(
function() {$(this).addClass("sfhover)},
function() {$(this).removeClass("sfhover)}
);
};

Responses

  1. Ryan says:

    November 24th, 2008 at 11:06 am (#)

    Thanks for the jQuery version!

    Son of Suckerfish has an IE7 issue (IE6 not affected) that manifests when you hover from one LI element directly to another. When this happens, as opposed to hovering off #nav, then back on, .sfhover does not get removed. Undesirable result: The menu item you just hovered off remains visible, along with the new menu item.

    Easy to fix is to change lines 3-4 to:

    function() {$(’#nav li’).removeClass(’sfhover’)},
    function() {$(this).addClass(’sfhover’)}

  2. Ryan says:

    November 24th, 2008 at 11:37 am (#)

    Turns out the “solution” I posted above causes the hover out to stop working in IE6 when your mouse moves out a menu and off of #nav.

    I’ve tested this with good results in Firefox 3 Mac, Safari 3 Mac, IE7 XP and IE6 XP:

    $(’#nav li’).hover(
    function() {

    jQuery.browser.version = jQuery.browser.msie &&
    parseInt(jQuery.browser.version) == 6 &&
    window[”XMLHttpRequest”] ?
    “7.0″ :
    jQuery.browser.version;
    if(jQuery.browser.version == ‘7.0′) $(’#nav li’).removeClass(’sfhover’);

    $(this).addClass(’sfhover’);

    },
    function() {$(this).removeClass(’sfhover’)}
    );

Leave a Response