jQuery – Requisite Navigation Drop-down Menu!
Everyone on the internet has their own jQuery navigation menu, but this one is mine. It’s very simple, but it’s also easy to expand on. Plus, I’ll explain why I did it the way I did it.
First, the overview – the navmenu is an unordered list (<UL>) containing list items (<LI>) containing anchors (<A>) which serve as the menu categories. The list items in turn contain unordered lists which contain list items which contain anchors which serve as the menu choices. Catch your breath. I know I said my menu is very simple, but no doubt you’ve seen this method before. Pretty much every other jQuery or generic JavaScript menu – be they drop-down, slide-out, jump-up, dance-around, or never-appear menus – use the same HTML basis.
But why?!? I think the answer is simple, but no one really explains it. The unordered list is the natural semantic choice for a menu, and for a menu of submenus of items, it makes sense to nestle a UL inside of the LIs of another UL. In a screen-reader or text to speech situation, it’s likely this is going to make sense to the user. If you design your links properly, you can also make it so that those dastardly villains who disable JavaScript can still navigate your site (by making the “menu categories” link to pages where the “submenu” items can be found as prominent links).
And anchors with the display:block property are just fun (actually, display:block on an anchor tag means the user doesn’t have to precisely and accurately place the mouse over the text to make the menu pop – they can hover anywhere in the block).
Next, the HTML. Here’s a shortened version of just the navmenu UL.
<ul id="navmenu">
<li class="menubutton"><a href="">Home</a></li>
<li class="menubutton"><a href="">Menu One</a>
<ul class="submenu">
<li><a href="">Item One</a></li>
<li><a href="">Item Two</a></li>
<li><a href="">Item Three</a></li>
<li><a href="">Item Four</a></li>
<li><a href="">Item Five</a></li>
</ul>
</li>
<li class="menubutton"><a href="">Menu Two</a>
<ul class="submenu">
<li><a href="">Item One</a></li>
<li><a href="">Item Two</a></li>
<li><a href="">Item Three</a></li>
<li><a href="">Item Four</a></li>
<li><a href="">Item Five</a></li>
</ul>
</li>
</ul><!-- end #navmenu ul -->
Of course, this HTML is simple, which is exactly what it should be. The only really important parts are where the few class declarations are… and there are few of them because the jQuery does most of that work for us (as you’ll see later).
Now, let’s look at the CSS. It’s long, so let’s go in chunks.
This div defines the theoretical header of my page. It’s fixed-width, centered with auto margins, and bordered. Woo-hoo.
The H1 for my header div. Note two things – first, it’s an H1, not just some P tag. Semantic HTML is good for everybody. Second, and more important, I used a “>” – the child selector. I look at a lot of code, and I never see this selector used when it should be. The way I’ve implemented this menu, we want to be careful the properties we apply to the first set of list items isn’t inherited by the second set of list items (the “grandchildren” of the first LI tags). The child selector limits the “cascade” to the immediate children. This should become more obvious as we go on.
#navmenu is a UL tag. We take out its padding and margins because it’s really just functioning as a neutral container for us. It’s got the top and bottom border covered – the A blocks will have the right borders, which makes the rectangles.
Here, we float the list items left (so that they “stack” starting on the left edge and going to the right). This is just plain easier than pretty much any other method, even though I find it somewhat troublesome (“This isn’t what float is for!”). We also strip out the list-style-type, of course. But why is this position:relative? Simple – it’s relative so that its second child, a UL which will be position:absolute, will use it as the basis for its absolute positioning.
And here we have the anchor tag. Again, by making it a block, we let the user mouse over any of its space to open the menu.
Here we have the next unordered list which makes up the actual menus that appear. It’s display:none, which will be changed by the jQuery script. With its absolute position, it doesn’t mess up the flow of the tags around it. Its z-index doesn’t really need to exist, but it’s just there to set an initial value. The jQuery will modify the z-index, too. I added some padding to the top just to bring the menu items down a little.
Now we’re almost all the way down the ladder, to the list items inside the menus themselves. These are fairly boring.
#my-header > #navmenu > li > ul > li > a {color: #203050;}
And finally, the anchors in those list items.
Phew.
So, last of all, the jQuery. Thankfully, it’s short!
$(document).ready(function() {
$(".submenu").hide(0);
$(".menubutton").hover(
function() {
$(this).children("a").css(
{'background-color': '#223377', 'color':'#EEEEEE'});
$(this).find("ul.submenu").slideDown(100).show();
$(this).find("ul.submenu").css("z-index","10");
},
function () {
$(this).children("a").css(
{'background-color': '#99BBEE', 'color':'#330066'});
$(this).find("ul.submenu").slideUp(200);
$(this).find("ul.submenu").css("z-index","5");
}
);
$(".submenu").children().hover(
function() {
$(this).animate({
"text-indent": "0px",
}, 300);
},
function() {
$(this).animate({
"text-indent": "10px",
}, 300);
}
);
});
On the whole, I used the hover() method to pop open the menus… because it’s easy. It handles both “mouseover” and “mouseout” events, so it shortens the work. When you mouseover the menubutton LIs, it slideDown()s the UL. On mouseout, it slideUp()s the UL. The second hover() method covers the “back and forth” slide animation of the actual menu items. This visual cue is just a tiny enhancement which I accomplished by manipulating the text-indent css property.
By the by, the children() method makes life a little easier, since we don’t have to set a class for every tag. find() is also a great method for pinning down the tags you’re looking for (although we didn’t really need it here, it’s good to know). The only question you’re likely to have is… why do the hover() functions change the z-index? It’s pretty simple – when the user opens a new menu, I want that menu to be on top (because these menus definitely overlap each other). So, by switching around z-indexes (z-indices?), we assure the user always sees the right menu (even if it’s only for a few hundred milliseconds).
Alright, that’s it! It’s not winning me a Nobel prize, but I find a lot of people throwing out code samples for these things without explaining their decisions… so uh… I did the best I could with that.
Filed under Code Demos, jQuery
Posted on January 18th, 2012