jQuery Drop Down Navigation Tutorial
HTML Source Code
The jQuery drop down navigation requires the inclusion of two files. The first is called jqdropnav.js that contains the jQuery drop down plug-in and calling code. The second is a CSS style sheet called jqdropnav.css that contains a number of styles that dictate the layout of the drop down menus.
<head>
....
<link rel="stylesheet" type="text/css" href="jqdropnav/jqdropnav.css" />
<script type="text/javascript" src="jqdropnav/jquery.min.js"></script>
<script type="text/javascript" src="jqdropnav/jqdropnav.js"></script>
....
</head>
Effort has been made with the HTML code to ensure that the page is still presentable even if JavaScript / jQuery is not available. When the jQuery code is not executed, the result is a single row of top level navigation with all the sub-menus hidden using the CSS property display : none (see below - CSS line 28).
Once the jQuery is executed, the sub-menus display properties are changed to block. Additional effects such as opacity and box shadow are addedd for those browsers that support CSS3.
The top level items which contain sub-menus should be linked to pages that have an alternative method of navigation to the sub-menu's pages. This will ensure that those pages are still accessible if JavaScript is not enabled. For example, the "Products" link (HTML - line 4) should be linked to a page that has an alternative set of links to sub link 1a - sub link 6a (HTML - line 6 to 11).
<ul id="navigation">
<li><a href="#">Home</a></li>
<li><a href="#">About Us</a></li>
<li><a href="#">Products</a>
<ul class="submenu">
<li><a href="#">sub link 1a</a></li>
<li><a href="#">sub link 2a</a></li>
<li><a href="#">sub link 3a</a></li>
<li><a href="#">sub link 4a</a></li>
<li><a href="#">sub link 5a</a></li>
<li><a href="#">sub link 6a</a></li>
</ul>
</li>
<li><a href="#">Services</a>
<ul class="submenu">
<li><a href="#">sub link 1b</a></li>
<li><a href="#">sub link 2b</a></li>
<li><a href="#">sub link 3b</a>
<ul class="submenu">
<li><a href="#">sub link 1b</a></li>
<li><a href="#">sub link 2b</a></li>
<li><a href="#">sub link 3b</a></li>
</ul>
</li>
<li><a href="#">sub link 4b</a></li>
<li><a href="#">sub link 5b</a></li>
<li><a href="#">sub link 6b</a>
<ul class="submenu">
<li><a href="#">sub link 1b</a></li>
<li><a href="#">sub link 2b</a></li>
<li><a href="#">sub link 3b</a></li>
</ul>
</li>
<li><a href="#">sub link 7b</a></li>
</ul>
</li>
<li><a href="#">Contact</a></li>
</ul>
The plugin will work with any number of nested sub-menus but obviously if the navigation does require more than 3 levels (including the top level), you may wish to reconsider using drop down navigation. The deeper the levels of navigation the more difficult drop down navigation is to use and therefore reduces accessibility considerably.
CSS Source Code
The CSS styles required for the drop down navigation is provided in a separate file called jqdropnav.css. Remember that if you change the name of the parent unordered list's id attribute (default is navigation), that you also change the selectors in the CSS file to relect the change.
#navigation {
border:1px solid #888;
background:#333 url(images/gradient-gray.png);
font-family:"Arial";
font-size:12px;
font-weight:700;
height:36px; /*default for no javascript*/
}
#navigation li {
position:relative;
margin:0;
display:block;
width:120px; /*default for no javascript*/
float:left;
}
#navigation li a {
display:block;
padding:10px 25px 10px 10px;
text-decoration:none;
color:#fff;
font-variant:small-caps;
}
#navigation li a:hover {
background:url(images/gradient-gray-over.png);
}
#navigation ul.submenu {
position:absolute;
display:none;
border:2px solid #333;
box-shadow: 5px 5px 5px rgba(0,0,0,0.2)
}
#navigation ul.submenu li {
display:block;
width:120px;
background-color:#666;
}
#navigation ul.submenu ul.submenu {
position:absolute;
top:0px;
display:none; /*default for no javascript*/
border:2px solid #333;
left:130px;
}
jQuery Source Code
As this is an example of what can be done with jQuery, each line / block of code below has been commented. I am happy to answer any questions that you may have about the jQuery code and will accept any suggestions for improvements.
The following options can be set when calling the plugin to customise the way the drop down navigation looks and behaves :
itemwidth- defaults to 160. This determines the width of each nav button in pixels.navheight- defaults to 36. This determines the height of the nav bar in pixels.speed- defaults to 300. The speed setting determines the sliding speed of the drop down items.downchar- defaults to"∨". Determines the ASCII character used to mark top level drop down lists.leftchar- defaults to">". Determines the ASCII character used to sub level fly out lists.animate- defaults to false. True or false to decide whether to slide options in sub menus when hovered over.opacity- defaults to true. True or false to determine whether sub menus are partially transparent.color- defaults to "#333". Sets the background colour of the navigation.
(function( $ ){
//Define a method called jqdropnav and accept a user defined
//map of settings into a variable called 'options'.
$.fn.jqdropnav = function(options) {
//Supply a set of default values to use if not supplied.
var defaults = {
itemwidth: 160,
navheight:34,
speed: 300,
downchar: "∨",
leftchar: ">",
animate:false,
opacity:true,
color:"#333"
};
//Merge the supplied options with the plug-in defaults.
var settings = $.extend({}, defaults, options);
//If opacity is true store the value as 0.8, otherwise
//store the opacity value as 1.0 (no opacity).
settings.opacity = settings.opacity ? "0.8" : "1.0";
this.each(function() {
var $this = $(this); //store reference
//Set the background colour of the nav from the
//user defined options.
$this.css({backgroundColor:settings.color});
//Set the navigation bar height from the
//user defined options.
$this.css({height:settings.navheight + "px"});
//Set each list item width from the user
//defined options.
$this.find('li').css({width:settings.itemwidth + "px"});
//Set the left offset of the fly out sub-menu items so they appear
//to the right of the drop down menus.
$this.find('ul.submenu ul.submenu')
.css({left:settings.itemwidth + "px"});
//Next we wish to prepend a marker to those items in the navigation
//that have sub items. To do this we will need to investigate
//whether the item contains another unordered list.
$this.find('li').each(function() {
//Does the list item contain another unordered list?
if(subs = $(this).find("ul").size()) {
//If it does, is it a top level or sub level item?
if ($(this).is(".submenu li")) {
//If it is a sub level item, select the first list item
//in the list and prepend the sub level character.
$(this).children(":first-child")
.prepend(settings.leftchar + " ");
} else {
//Otherwise it is a top level item, so select the first
//list item in the list and prepend the top level character.
$(this).children(":first-child")
.prepend(settings.downchar + " ");
}
//Then set the background colour & opacity of all the list items
//from the user defined options.
$(this).find("li").css({backgroundColor:settings.color,
opacity:settings.opacity});
//Attach a hover event listener to the current list item.
$(this).hover(function(){
//On mouse over find the first unordered list in the
//list item, stop any other animation and then slide
//the unordered list down into view.
$(this).find("ul:first").stop(true, true)
.slideDown(settings.speed);
},
function(){
//On mouse out find all unordered lists in the
//list item, stop any other animation and then slide
//the unordered list up out of view.
$(this).find("ul").stop(true, true)
.slideUp(settings.speed);
});
//Attach a keydown event listener to provide keyboard navigation
//through the drop down navigation.
$(this).keydown(function(evt) {
//Look for presses of the TAB key.
if (evt.keyCode == '9') {
//If the TAB key is pressed on a list item that
//contains a unordered list, we then want to
//open that list for navigation.
$(this).find("ul:first").stop(true, true)
.slideDown(settings.speed)
}
});
}
});
//The sub-menu items can have their padding animated if the animate property
//is set to true in the user defined options.
if (settings.animate) {
//Attach a hover event listener to each link in the navigation
$this.find('ul li a').hover(function(){
//Stop any animation on the link and then animate
//the left and right padding to make the links look
//like they are moving to the right.
$(this).stop(true, true)
.animate({paddingLeft:"30px",paddingRight:"10px"},
settings.speed);
},
function(){
//Stop any animation on the link and then animate
//the left and right padding to make the links look
//like they are moving back to the left.
$(this).stop(true, true)
.animate({paddingLeft:"10px",paddingRight:"30px"},
settings.speed);
})
}
});
return this;
};
})( jQuery );
//Plugin calling code - This example assumes that the navigation unordered
//list will be called 'navigation.
$('document').ready(function () {
$('#navigation').jqdropnav({itemwidth: 120,
speed:300,
animate:true,
opacity:true,
color:"#333"});
});
jQuery Course Trainer
Bjorn has been involved in CSS based web design for nearly 10 years and has experience developing web applications in both small and large teams of developers.
Over the past few years he has closely followed the evolving standards for web development and has spent countless hours discussing appropriate markup with web designers in the industry. He has also run training courses on web standards and accessibility which stems from his vast experience with CSS web design.