Hello. I am a social media specialist, web designer and developer. When not hard at work, I am probably travelling the world! More about me

CSS drop-down menus: keeping the top level selected when hovering over a sub-menu, now in jQuery

Posted 6 September 2009 Tagged to , , , 5 Comments

Awhile back I wrote a JavaScript tutorial on how to keep the top level menu item selected when hovering over a drop down menu. Since then I’ve become a strong user and proponent of the JavaScript library jQuery. Not only is it easy to use, it also can help simplify your code-base very significantly. I’ve explained the updated code below. As you can see, it is much simpler.

How this works

There are two main components of the JavaScript, first the code for all browsers to keep the top level selected and a second code block to add the hover state for IE6 (since it only supports :hover pseudo-classes on anchors, not list elements as we use here).

First, you’ll need to add the jQuery equivalent of “onLoad”: $(function() {. Fortunately, the multiple onLoad and caching issues we addressed in the earlier tutorial are now handled in jQuery, so no need to use the “onEvent” function from the earlier tutorial. You’ll also sometimes see this as $(document).ready(function() {. The functionality is the same, so feel free to use either syntax.

Code for persistent top-level menu formatting

Next, the general code for maintaining the hover formatting on the top level. Basically, this function iterates through each of the drop-down <ul>s and adds a hover function to each. So, when a user hovers over a drop down menu, jQuery finds the parent of that drop down, finds all anchor tags, slices out all the anchors but the first and, finally, toggles the “active” class.

$("#menu ul").each(function(i){
  $(this).hover(function(){
    $(this).parent().find("a").slice(0,1).addClass("active");
  },function(){
    $(this).parent().find("a").slice(0,1).removeClass("active");
  });
});

Internet Explorer 6 functionality

To make this work in IE6, we need to add some additional code. First, we use jQuery’s built in browser sniffer to only target MSIE versions below 7. It then works fundimentally like the code above and the Suckerfish drop downs from the earlier tutorial. JavaScript cycles through each drop-down <ul> and adds a function that tells the its parent anchor tag to take on a particular class when the browser detects a mouseover on the menu.

if($.browser.msie && ($.browser.version < 7)) {
  $("#menu").each(function(i){
    $(this).find("li").hover(function(){
      $(this).addClass("sfhover");
    },function(){
      $(this).removeClass("sfhover");
    });
  });
}

In closing

Be sure to add the closing parenthesize and bracket for the jQuery on ready state: });.

Complete Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>

  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Menu Example</title>

  <style type="text/css" media="screen">

  body {
    margin: 20px;
    background: #fff;
    font-family: Verdana, Helvetica, sans-serif;
    font-size: 9pt;
  }

  * { margin: 0; padding: 0; }
  li { list-style: none; }
  a { text-decoration: none; }

  #menu li {
    float: left;
    display: block;
    font-size: 8pt;
  }

  #menu li a {
    position: relative;
    padding: 6px 10px;
    display: block;
    font-weight: bold;
    color: #333;
  }

  #menu li a:hover, #menu li a.active {
    background: #999;
    color: white;
  }

  #menu li ul {
    left : -999em;
    position : absolute;
  }

  #menu li ul li { float : none; }

  #menu li ul a {
    width : 136px;
    padding : 8px 10px;
    background : #f4f4f4;
    border-bottom : 1px solid white;
    font-weight : normal;
  } 

  #menu li ul a:hover {
    background: #FFCC99;
    color: #333;
  }

  #menu li:hover ul, #menu li.sfhover ul {
    left: auto;
    border-top: 1px solid #999;
  }

  </style>

  <script type="text/javascript" src="jquery.js">  </script>

  <script type="text/javascript" src="jquery.js">
  <!--

  $(function() {

    //Preserves the mouse-over on top-level menu elements when hovering over children
    $("#menu ul").each(function(i){
      $(this).hover(function(){
        $(this).parent().find("a").slice(0,1).addClass("active");
      },function(){
        $(this).parent().find("a").slice(0,1).removeClass("active");
      });
    });

    // IE6 Fix: Drop-down fix due to lack of support for :hover on list elements
    if($.browser.msie && ($.browser.version < 7)) {
      $("#menu").each(function(i){
        $(this).find("li").hover(function(){
          $(this).addClass("sfhover");
        },function(){
          $(this).removeClass("sfhover");
        });
      });
    }

  });

  // -->
  </script>

</head>

<body>

  <ul id="menu">
    <li><a href="#">Styles</a>

    <ul>
      <li><a href="#">Red/White</a></li>
      <li><a href="#">Ros?©/Blush</a></li>
      <li><a href="#">Sparkling</a></li>
      <li><a href="#">Dessert</a></li>
      <li><a href="#">Fortified</a></li>
      <li><a href="#">Fruit</a></li>
      <li><a href="#">Ice Wine</a></li>
    </ul>

    </li>
    <li><a href="#">Whites</a>

    <ul>
      <li><a href="#">Albari?±o</a></li>
      <li><a href="#">Chardonnay</a></li>
      <li><a href="#">Chenin blanc</a></li>
      <li><a href="#">Muscat</a></li>
      <li><a href="#">Pinot blanc</a></li>
      <li><a href="#">Pinot gris</a></li>
      <li><a href="#">Riesling</a></li>
      <li><a href="#">Sauvignon blanc </a></li>
      <li><a href="#">S?©millon</a></li>
    </ul>

    </li>
    <li><a href="#">Reds</a>

    <ul>
      <li><a href="#">Cabernet Sauvignon </a></li>
      <li><a href="#">Malbec </a></li>
      <li><a href="#">Merlot </a></li>
      <li><a href="#">Pinot noir </a></li>
      <li><a href="#">Syrah/Shiraz </a></li>
      <li><a href="#">Zinfandel</a></li>
    </ul>

    </li>
    <li><a href="#">Noted Regionals</a>

    <ul>
      <li><a href="#">Amarone</a></li>
      <li><a href="#">Beaujolais</a></li>
      <li><a href="#">Burgundy </a></li>
      <li><a href="#">Chianti </a></li>
      <li><a href="#">Madeira </a></li>
      <li><a href="#">Port </a></li>
      <li><a href="#">Sancerre </a></li>
      <li><a href="#">Tokaji </a></li>
      <li><a href="#">Vinho Verde </a></li>
    </ul>

    </li>
    <li><a href="#">Key Countries</a>

    <ul>
      <li><a href="#">France</a></li>
      <li><a href="#">Italy</a></li>
      <li><a href="#">Spain</a></li>
      <li><a href="#">United States</a></li>
      <li><a href="#">Argentina</a></li>
      <li><a href="#">Australia</a></li>
      <li><a href="#">South Africa</a></li>
    </ul>

    </li>
  </ul>

</body>
</html>

Comments (5):

  1. ehud

    22:26 UTC on

    21 September 2009

    look this

  2. Joe

    6:27 UTC on

    22 October 2009

    How could you make this multi-level?

  3. velu

    2:46 UTC on

    26 August 2010

    thanks

  4. fahmi

    8:08 UTC on

    18 August 2012

    hi, your demo page is not found

  5. Darren

    16:10 UTC on

    3 April 2013

    @fahmi Just updated the demo page. Looks like files didn’t make the latest migration.

Leave a Reply