views:

250

answers:

1

I've created a custom jQuery horizontal menu with drop downs. Initially it just faded a sub-menu in when hovering on a list item, and faded it out when moving away.

However I want to create an effect where if you move the mouse out of the sub-menu, it doesn't disappear instantly (e.g. if you overshoot it by a pixel). I was made aware of the hoverIntent plugin in a previous question, but it has an annoying delay when opening sibling sub-menus. So I started from scratch with my own functionality in mind.

My HTML is a standard nested list, ul#menu > li > ul > li. My Javascript is as follows:

var menuVisible = false;
var cancelTimeout = false;

$(document).ready(function(){
  $('ul#menu > li').hover(
    function(){
      menuMouseOver( $(this) );
    },
    function(){
      menuMouseOut( $(this) );
    }  
  );
});

function menuMouseOver( $li )
{
  // if one of the menus is down, check which one we're hovering
  if ( menuVisible ) {
    cancelTimeout = true;  
    if ( $li.find('>ul').css('display') == 'block' ) {
      // do nothing if we're hovering over current menu
    }
    else {
      // turn off all menus
      $li.parent().find('>li').each( function() {
        menuOff( $li )
      });
    }
  }

  menuOn( $li );
  menuVisible = true;
}

function menuMouseOut( $li )
{
  setTimeout( 
    function(){
      if ( !cancelTimeout ) {
        menuOff( $li );
        menuVisible = false;
      }
      cancelTimeout = false;
    },
    2000
  );

}

function menuOn( $li )
{
  $li.css('background-position', 'left bottom');
  $li.find('>ul').fadeIn('fast');
}
function menuOff( $li )
{
  $li.css('background-position', 'left top');
  $li.find('>ul').fadeOut('fast');
}

The following things work:

  • Moving over a top-level li opens the sub-menu.
  • Moving away from the sub-menu closes it after 2 seconds (for testing purposes; will be reduced in the final version).
  • Moving away from the sub-menu and back cancels the timeout and therefore stops the menu from disappearing

However, these don't work:

  • When moving from one top-level list item to the next, the previous sub-menu doesn't disappear. I want it to fade out straight away, without the normal delay.
  • If I move across two top-level list items, menuVisible is set to false, which screws up the system. This is because cancelTimeout is set to true when you move over the first sibling, and it is still true as you move to the second sibling.

I'd appreciate any insight into why this happens, and of course, how to fix it.

+2  A: 

Have you tried the Superfish menu jQuery plugin?

I've used it in my project and I think it will solve these problems for you.

Daniel Robinson
This plugin is nice too: http://css-tricks.com/simple-jquery-dropdowns/
fudgey
@fudgey: that doesn't do what I want at all. The menu disappears the instant you move your mouse away. I already did that in 5 minutes (by which I mean the jQuery is dead simple).
DisgruntledGoat
Thanks Daniel, the Superfish plugin works pretty well. I'm normally a stickler for plugins with superfluous functionality, but Superfish is pretty minimal even with drop shadows and other pointless crap.
DisgruntledGoat
@DisgruntledGoat: Cool, I'm glad I could help. I've noticed that it's been a week without a better answer. Perhaps you could accept this answer to help others out there who might be looking for questions without accepted answers.
Daniel Robinson
"Accepted Sep 22 at 23:50" - maybe you're missing the green background color, too?
DisgruntledGoat