3

I have a full-width drop-down menu that shows all submenu's on hover or on getting focus (to make it keyboard-accessible). It's a menu you see often, but keyboard accessibility I haven't found examples of implemented in a way that it simulates the hover-behaviour (in other words: expanding the menu).

Here's the HTML of the menu:

<div id="menu">
    <div class="container">
      <ul class="row">
        <li class="first"><a href="link">Home</a></li>
        <li><a href="link">Projects</a>
          <ul class="inner">
             <li class="first"><a href="link">Project 1</a></li>
             <li class="last"><a href="link">Project 2</a></li>
          </ul>
        </li>
        <li class="last"><a href="link">Contact</a>
          <ul class="inner">
            <li class="first"><a href="link">Visit us</a></li>
            <li class="last"><a href="link">Email</a></li>
          </ul>
        </li>
     </ul>
  </div>
</div>

I've been trying all kinds of ways to make this work with Jquery (still learning Jquery), and it works partially. The hover feature works kind of, still some strange things happening. The problem is with the focus/blur function. I've added a timeout to the blur function, otherwise it will fire every time I tab to another link. But with this timeout in place, the blur effect doesn't happen anymore. (the menu stays expanded).

What might make this different from other solutions is that I want the hover, focus and blur event to happen on the #menu div, not on individual links. I want it to work this way because it's a full width menu, you see all submenus at once when hovering the menu. I found out that adding 'tabindex = 0' to the div makes it possible to use focus and blur. Therefore I decided to add this by Jquery as well.

My Jquery looks like this:

$(document).ready(function() {

    /* dropdownmenu */
    $("#menu")
    .attr("tabindex",0)
    // HOVER
    .hover
    ( function () 
      {
       $(this).addClass('dropdown');
       $(this).animate({ height: '20em'});
      },
      //hover out
      function() 
      {
        $(this).animate(
            { height: '6em' }, 
            { complete: function() { $(this).removeClass('dropdown'); } }
        )
      }
    )
    // FOCUS
    .focus 
    ( function () 
      {
        $(this).addClass('dropdown');
        $(this).animate({height: '20em'});
      }

    )
    // BLUR
    .blur 
    ( function() 
      {
         setTimeout(function()
         {
        $(this).animate(
                    {height: '6em'}, 
                { complete: function() { $(this).removeClass('dropdown'); } }
            )
         },500);

      }
    );

I hope someone can help me a little to make this Jquery better. Is it way to long? And why is the hover function acting strange and the blur function not working at all? Should I go about this another way?

I also added this in jsfiddle: http://jsfiddle.net/CpdM2/1/ The heights are different here to demonstrate the behaviour better.

Thanks for any help!

EDIT

I'm now trying a different approach with the Jquery. I'm getting closer, the only problem remains with the blur function.

My new jquery:

$.fn.accessibleDropDown = function ()
{
    var el = $(this);

    $(el).mouseenter(function() {
        $("#menu").addClass('dropdown');
        $("#menu").animate({ height: '7em'});
    }).mouseleave(function() {        
            $("#menu").animate(
                   { height: '1em' }, 
                { complete: function() { $("#menu").removeClass('dropdown'); } }
            );
    });


    /* Make dropdown menus keyboard accessible */

    $("#menu").focus(function() {
        //alert("focus");
       $("#menu").addClass('dropdown');
        $("#menu").animate({ height: '7em'});
    }).blur(function() {
        setTimeout(function() { 
         if ($('#menu').find(':focus').length > 0) {
             return false;
        } else {
            alert("menu does not have focus");
            $("#menu").animate(
                { height: '1em' }, 
                { complete: function() { $("#menu").removeClass('dropdown'); } }
            );
        }
       }, 50);
    });
};



$("#menu").attr("tabindex",0).accessibleDropDown();
​

See it in action here: http://jsfiddle.net/kBNRv/

The code to see if the #menu div has lost focus is for some reason not working. I really hope someone can point me in the right direction. Thanks in advance.

Michelle
  • 43
  • 4

1 Answers1

0

A simpler approach would be to use this instead:

$("#menu").mouseenter(function() {
    $(this).addClass('dropdown');
    $(this).animate({height: '7em'});
    $(this).focus(); /*OPTIONAL*/       
});

$("#menu").mouseleave(function() {
    $(this).removeClass('dropdown'); 
    $(this).animate({height: '1em' });
    $(this).blur(); /*OPTIONAL*/  
});

The focus and blur method can be called on 'mouseenter' and 'mouseleave' since this list element is not an input type it will not accept focus by clicking into it the same way. Not sure why you need the focus unless your listening for that behavior in some way.

Also, beware that this approach much like your original approach does not take into consideration if an element has a z-index higher than your menu. If you where to have an element positioned above your menu, the 'mouseleave' method would be triggered if your mouse rolled over that element. To see an example just rollover the 'Result' box here: http://jsfiddle.net/CpdM2/17/. So to counter act that you may want to:

a) refrain from adding any elements over your menu.

b) check the x,y mouse positions to see if they are in/out of your menu area before triggering the 'mouseleave' method. An example of checking mouse position is here: http://docs.jquery.com/Tutorials:Mouse_Position

This was a common approach in flash back when using flash was cool.....sigh

AJames
  • 64
  • 3