Building an Awesome Navigation Menu with jQuery: Part 1

menu expanded
Do you need to build a navigation interface that has to handle hundreds of product links? All grouped in categories, subcategories? Perhaps even containing thumbnails? If the answer is yes, here’s a usability path to avoid :

  1. select categories, wait for a page to load
  2. select a subcategory, wait for another page to load
  3. check out products
  4. click to go to desired product

The typical web user only wants to click once or twice to get to the product they want. And if clicks are unavoidable, make sure page loads are minimized! The more clicks and the more page loading they have to go through, the higher the risk they will get lost and never come back to your site. The good news is that you can achieve a good navigation menu that reduces page reloads.

This article is an in-depth tutorial on how you can achieve an expandable navigation menu using valid xhtml coding, valid css and a bit of javascript.

The concept

In order to achieve a fully functional menu for our huge website, we need one that will enable users to choose a category or subcategory in a timely manner, then browse hassle-free for the product they like. In Part 1 of the tutorial, we will create a horizontal bar that contains all the main categories of the products our customer is selling. This menu bar will expand so users will see all sub-categories. In Part 2 of the article, we’ll create the functionality where clicking on a sub-category will trigger an overlay that displays a list of the individual products.

menu sketch

In the image above there’s a sketch of what the site layout should be. We have the menu bar, right under the menu comes a header that can contain images, paragraphs of text, news. You get the picture. Then comes the content area. The menu will expand and push the header together with all elements that come after it down the page, as you can see in the following image.

menu expanded

Sneak peak at what we’re building here

Just in case you cannot wait for the end of the article, just check out the demo over here.

Coding the HTML and CSS

The navigation bar will consist of an unordered list. I have chosen this tag because menus contain lists, therefore an unordered list is the best way to go for this. The part of the menu that will slide will be contained by a div, each item in the navigation menu having a separate div for its information. We will have the header and the content section also contained in a div. Here’s a view on the XHTML structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 	
<head>
	<!– head meta tags, css , javascript links will be here–> 	
</head> 	
<body> 	
	<div id="wrapper"> <!– used only for cosmetic purposes. IE: The site background image in the top –> 		
		<ul id="menu" class="all-rounded"> <!– the menu ul I talked about. all-rounded class will round the corners –> 				
			<li><a href="" target="_self">home</a></li>
			<li><a target="_self" >cleaning</a></li>
			<li><a target="_self" >cooking</a></li>
			<li><a target="_self" >gardening</a></li>
			<li><a href="" target="_self">about us</a></li> 			
		</ul> 			
	<div class="menu-extend cleaning"> <!– extended menu div –>
		<ul> 					
			<li><a href="" target="_self">Pressure Washers</a></li>
			<li><a href="" target="_self">Pressure Washers Accessories</a></li>
			<li><a href="" target="_self">Hoses and Water Fittings</a></li>
			<li><a href="" target="_self">Water Pumps</a></li>
			<li><a href="" target="_self">Dry Vacuums</a></li>
			<li><a href="" target="_self">Wet Vacuums</a></li>
			<li><a href="" target="_self">Industrial Vacuums</a></li>
			<li><a href="" target="_self">Specialist Vacuums</a></li>
			<li><a href="" target="_self">Vacuum Cleaner Bags</a></li>
		</ul>
 		<ul>
			<li><a href="" target="_self">Steamers</a></li>
			<li><a href="" target="_self">Scrubber Dryers</a></li>
			<li><a href="" target="_self">Buffers</a></li>
			<li><a href="" target="_self">Floor Care Chemicals</a></li>
			<li><a href="" target="_self">Carpet Care Chemicals</a></li>
			<li><a href="" target="_self">Carpet Cleaning Machines</a></li>
		</ul>
		<ul>
 			<li><a href="" target="_self">Trolleys</a></li>
			<li><a href="" target="_self">Household Cleaning Chemicals</a></li>
			<li><a href="" target="_self">Vehicle Cleaning Chemicals</a></li>
			<li><a href="" target="_self">Cleaning Equipment</a></li>
			<li><a href="" target="_self">Brooms and Brushes</a></li>
			<li><a href="" target="_self">Interchange System</a></li>
		</ul>
		<span class="clear">&nbsp;</span> 
	</div>
 
	<div class="menu-extend cooking"> <!– same as above div –>
		expanded menu goes in here for cooking
		<span class="clear">&nbsp;</span>
	</div>
 
	<div class="menu-extend gardening">
 		expanded menu goes in here for gardening
		<span class="clear">&nbsp;</span>
	</div>
 
	<div id="header"> <!– header div with an image –>
		<img src="images/header.jpg" width=900 height=200 alt="Header" /> 		</div>
 
	<div id="content"> <!– finally the content area –>
		<h1>Fancy menu</h1>
		<p>Fancy menu info goes here </p>				 		</div>
	</div> 	
</body> 
</html>

I chose to round up the corners of the menu. To create this effect we will use some CSS level 3 and browser specific markup. The navigation bar will also have vertical separators between the items. The separator is consisted of two different lines, each with a custom color. We won’t use images for the separators. Instead we will use the css border property. Each list item in the navigation bar will have a 1px solid left border, and a 1px solid right border. The first element in the list and the last one won’t have the left border, and right border respectively. Here’s the html markup of the modified list, to reflect that there won’t be the above mentioned borders, and the css code:

8
9
10
11
12
13
14
<ul id="menu" class="all-rounded">
	<li class="no-left-border"><a href="" target="_self">home</a></li>
	<li><a target="_self" >cleaning</a></li>
	<li><a target="_self" >cooking</a></li>
	<li><a target="_self" >gardening</a></li>
	<li class="no-right-border"><a href="" target="_self">about us</a></li>
</ul>
.all-rounded	{
	border-radius:9px;
	-moz-border-radius:9px;
	-webkit-border-radius: 9px;
	}
 
/* these are the rounded corners */
#menu  {
	display:block;
	margin:0px auto;
	width:898px;
	border:1px solid #DD4CAB;
	height:48px;
	background:url('../images/menu_bg.jpg') repeat-x; color:#DD4CAB;
	 } 
 
/* ul style */
#menu li {
	display:block;
	width:178px;
	height:48px;
	line-height:48px;
	float:left;
	text-align:center;
	border-right:1px solid #DD4CAB;
	border-left:1px solid #AD3B87;
	}
 
/* li items style */
#menu li.no-left-border {
	border-left-style:none;
	}
 
/* no border as we said */
#menu li.no-right-border {
	border-right-style:none;
	}

Because I chose to round the corners of the menu, there are some issues while hovering the menu items, so the links that are held by the li items will have to have rounded corners as well. The first link in the menu will have rounded corners on the left side, while the last one will have rounded corners on the right side. Here’s the code for that:

#menu li a	{
	display:block;
	height:48px;
	color:#DD4CAB;
	text-decoration:none;
	}
 
#menu li a:hover	{
	display:block;
	height:48px;
	color:#DD4CAB;
	text-decoration:none;
	background:url('../images/menu_bg_hover.jpg');
	}
 
#menu li.no-left-border a:hover  {
	border-top-left-radius:9px;
	border-bottom-left-radius:9px;
	-moz-border-radius-topleft:9px;
	-moz-border-radius-bottomleft:9px;
	-webkit-border-top-left-radius:9px;
	-webkit-border-bottom-left-radius:9px;
	}
 
#menu li.no-right-border a:hover  {
	border-top-right-radius:9px;
	border-bottom-right-radius:9px;
	-moz-border-radius-topright:9px;
	-moz-border-radius-bottomright:9px;
	-webkit-border-top-right-radius:9px;
	-webkit-border-bottom-right-radius:9px;
	}

Coding the behavior of the menu using jQuery

I am not going to reinvent the wheel here, but jQuery seems to be the best javascript framework out there. If you’re not familiar to jQuery you can find some great tutorials and examples over here.

Javascript for menus? Are you insane!

Some people out there say you must not use javascript for navigation under any circumstances. I am sorry guys, but if you write your code professionally, using javascript for menus can seriously enhance your site’s functionality. The trick they’re talking about is what do you do when javascript is unavailable in the visitors browsers? Well, you have to code your menu in such a way it has progressive enhancement and works just fine if javascript is off. And yes, this menu achieves progressive enhancement. If javascript is turned off, the menu will be directly visible, including the part that should slide when needed. Nothing is inaccessible. Moreover, search engine’s bots will see the site just as if they were a visitor without javascript, so search engine optimization is preserved if using this menu.

Let’s get down to the jQuery

jQuery uses html IDs and classes to identify elements in the html page that it needs to work with. Our menu currently has unique ID, but the “cleaning”, “cooking” and “gardening” links don’t, so we add a class for each of them. The classes are unique too.

8
9
10
11
12
13
14
<ul id="menu" class="all-rounded">
	<li class="no-left-border"><a href="" target="_self">home</a></li>
	<li><a target="_self" class="cleaning-but">cleaning</a></li>
	<li><a target="_self" class="cooking-but">cooking</a></li>
	<li><a target="_self" class="gardening-but">gardening</a></li>
	<li class="no-right-border"><a href="" target="_self">about us</a></li>
</ul>

In order to achieve progressive enhancement, we must first disable javascript and load the menu page. So far, due to our code the menu displays in its entirety, including the part that in a few minutes will slide beautifully if javascript is on. But if it has to slide, it has to be hidden first, and this is the trick we pick out from our sleeves. The first thing we’re to do with jQuery is to hide the sliding part of the menu. By doing this, people having javascript turned on will not see the menu until they click to expand it. They will only see the menu bar. Here’s the jQuery code needed to achieve this:

$('.menu-extend').hide();

The rest is simple. When you click one item in the navigation bar, you are taken to a page. This happens for the Home and About us links. When you click one of the links in the middle of the menu, the menu will slide and reveal the contents. If there’s another menu visible, clicking to expand one other item will make the expanded section slide back under the navigation bar, then the required content will slide back out. How cool is that?

jQuery code step by step
There’s a bit of jQuery to be written here, so you can take a peak below to the full source code, then continue to the part I dice the code in pieces and explain what I’ve done.

jQuery(document).ready(function($)
 	{
 	// start the magic
 	// if javascript is on, the menu will work ok
 	// Therefore we hide the expanded menu 	$('.menu-extend').hide();
 	$('.clear').height(0);
 	// if the "Detailed menu" button is clicked, fade it out and fade in the "Close menu button"
	// also slide the expanded menu into place
 	$('.cleaning-but').click(function ()
 		{
 		var isVisible = $('.menu-extend').is(':visible');
 		var isVisiblecleaning = $('.cleaning').is(':visible');
 		var isVisiblecooking = $('.cooking').is(':visible');
 		var isVisiblegardening = $('.gardening').is(':visible');
 		if(isVisible)
 			{
 			if(!isVisiblecleaning)
 				{
 				if(isVisiblecooking)
 					{
 					$('.cooking').slideUp("1000", function() { $('.cleaning').slideDown("1000") });
 					}
 				else if(isVisiblegardening)
 					{
 					$('.gardening').slideUp("1000", function() { $('.cleaning').slideDown("1000") });
 					}
 				}
 				else
 				{
 				$('.cleaning').slideUp("1000");
 				}
 			}
 		else
 			{
 			$('.cleaning').slideDown();
 			}
 	    });
 	$('.cooking-but').click(function ()
 		{
 		var isVisible = $('.menu-extend').is(':visible');
 		var isVisiblecleaning = $('.cleaning').is(':visible');
 		var isVisiblecooking = $('.cooking').is(':visible');
 		var isVisiblegardening = $('.gardening').is(':visible');
 		if(isVisible)
 			{
 			if(!isVisiblecooking)
 				{
 				if(isVisiblecleaning)
 					{
 					$('.cleaning').slideUp("1000", function() { $('.cooking').slideDown("1000") });
 					}
 				else if(isVisiblegardening)
 					{
 					$('.gardening').slideUp("1000", function() { $('.cooking').slideDown("1000") });
 					}
 				}
 				else
 				{
 				$('.cooking').slideUp("1000");
 				}
 			}
 		else
 			{
 			$('.cooking').slideDown();
 			}
 	    });
 	$('.gardening-but').click(function ()
 		{
 		var isVisible = $('.menu-extend').is(':visible');
 		var isVisiblecleaning = $('.cleaning').is(':visible');
 		var isVisiblecooking = $('.cooking').is(':visible');
 		var isVisiblegardening = $('.gardening').is(':visible');
 		if(isVisible)
 			{
 			if(!isVisiblegardening)
 				{
 				if(isVisiblecooking)
 					{
 					$('.cooking').slideUp("1000", function() { $('.gardening').slideDown("1000") });
 					}
 				else if(isVisiblecleaning)
 					{
 					$('.cleaning').slideUp("1000", function() { $('.gardening').slideDown("1000") });
 					}
 				}
 				else
 				{
 				$('.gardening').slideUp("1000");
 				}
 			}
 		else
 			{
 			$('.gardening').slideDown();
 			}
 	    });
 	});

The first jQuery code is $(‘.clear’).height(0);. This is used to set the height of the clearing div to 0. We added a clearing div to each of the expanded menu’s divs because all content inside them floats to the left, and would therefor cause the expanded menu div to collapse. By adding the clearing div we avoid that, but we also add 20 unnecessary pixels to the expanded menu’s height. We fix this problem with the code mentioned above.

Then, we have three different onclick functions. Each one does the same thing, but is triggered by a different element in the menu. I will explain the first one. $(‘.cleaning-but’).click(function () is used to trigger clicking on the href tag that contains the link to cleaning menu. That link is identified by the cleaning-but class we added previously. When that link is clicked we don’t have just one behavior, so everything has to go inside a function.

var isVisible = $(‘.menu-extend’).is(‘:visible’); is used to check if there’s any menu currently expanded. The variable will hold either true or false values. Here, the expanded menu is identified by the general class used for it menu-extend. We will use the same process to check what expanded menu is in fact expanded, be it the one for cleaning category, or another one. We will identify those by their unique classes cleaning, cooking and gardening.

We first check if the menu is visible. if(isVisible) will return true if there’s an expanded menu, or false otherwise. If false, we will simply slide down the menu using $(‘.cleaning’).slideDown(); located on the else side of the if. If there’s an expanded menu, we check to see if it is exactly the one we clicked. If it is the same one, we will slide it back up using $(‘.cleaning’).slideUp(“1000″);. If it is another one, we slide up that div using a similar piece of code, then slide down the one needed. $(‘.cooking’).slideUp(“1000″, function() { $(‘.cleaning’).slideDown(“1000″) }); slides up the cooking expanded menu, and after that process is completed, it slides down the cleaning menu. The syntax for such a process is $(‘identifier’).slideUp(duration, callback event – the one triggered after first one is completed);

Here’s a live demo version of the menu. Zip archive download will be available once we publish the second part of this article!

In the concept part we said that the contents of the expanded menu are in fact subcategories, and clicking on a subcategory will reveal the products located in that category. But that is another story and we will discuss it in the second part of the article.

Coming up next
Part 2: Displaying menu items using overlay

Comments

9 Responses to “Building an Awesome Navigation Menu with jQuery: Part 1”
  1. monstordh says:

    Nice tut. It would be really nice if you used the Geshi syntax highlighting for cleaner, more easy-to-read code. thanks for the tut.

  2. Bogdan says:

    Hey monstordh,

    Glad you liked the tutorial. About the Geshi syntax highlighting, is it available as a WP plugin? I haven’t used it, but I guess John would be pleased if it can be simply installed in WP.

  3. John Cottone says:

    Thanks monstordh, good feature request. Bogdan forwarded me a plugin that I’ll be testing out this week on this article.

  4. John Cottone says:

    Looks like the Geshi plugin is working well here, Part 2 getting published tonight!

  5. This looks great. One issue i have see, is that the demo is jumpy when sliding if you view it in IE. Any ideas how to fix this?

Trackbacks

Check out what others are saying about this post...
  1. [...] of a two-part series that will help you build a complex sliding menu, enhanced with modal windows. Click here to read Part 1. This second part will cover building a modal window and coding its behavior. If you don’t [...]

  2. [...] 4. Building an Awesome Navigation Menu with jQuery [...]

  3. [...] 4. Building an Awesome Navigation Menu with jQuery [...]

  4. [...] Building An Awesome Navigation Menu with jQuery: Part 1 | … [...]



Speak Your Mind