You are here
Build a Navigation Menu Using Design Patterns
Download the source for the Navigation Menu.
Goal: This easy project will combine powerful tools with some simple components to produce a flexible navigation menu capable of displaying horizontally or vertically with never-ending submenus.
Tools & Materials:
Before Beginning: Take a look at the posts on the Iterator and Composite patterns to become familiar with them. Be sure to download the code for them, as we will be using them for the base of the project.Step 1: Getting our Class up to Snuff
We’re going to be using the NavComponent and subclasses developed in the post on the Composite Pattern. This design pattern fits the needs of the project exactly and only needs minor modifications to get it working the way we will want it to. Currently, our NavMenu spits out a list of hyperlinks one after the other without much actual structure so the first thing we want to do is give our menu a containing element.
It turns out the list is a great way of implementing a menu but we just have it done wrong, we’re just outputting our links to a new line, let’s change that by opening NavButton.class.php and finding the display() method. Instead of just displaying a hyperlink followed by line-break let’s make each button a list item:
public function display() {
echo '<li><a href="' . $this->_link .
'" title="' . $this->_text .
'">' . $this->_text . '</a></li>';
}
Next we need to open the NavMenu.class.php and add a couple of private member variables and a couple methods to help use those variables. Currently, our NavMenu only displays its title and then all its components. We need it to also work as a link in some cases so the first variable we’ll add will hold that info, the second variable will be a boolean and will tell us when to show the link. We’ll also add a getter method for the link and a setter method for the $_topLevel variable, the default value is false so this will only need to be used for the very top-level menu. Make sure to update the constructor as well so we can set the link upon instantiation:
private $_link;
private $_topLevel = false;
public function __construct($text, $link) {
$this->_text = $text;
$this->_link = $link;
}
... other methods here ...
public function getLink() {
return $this->_link;
}
public function setTopLvl($tl) {
$this->_topLevel = $tl;
}
Before we get out of here we have to make some changes to the display() method. Our old method just spit out the name of the menu and then called the display() method on each of its components. Now that each button is a list item we can turn each menu into an unordered list to contain them. At the very top level we only need the <ul> tag to start us off but we’ll want submenus to display as a list item while starting a new list of their own to contain the components that will be called by the submenus display() method and so on recursively until the entire menu structure has been built. After each menu has been built we need to apply the appropriate closing tags and move on:
public function display() {
if($this->_topLevel) {
echo '<ul>';
} else {
echo '<li><a href="' . $this->_link .
'" title="' . $this->_text .
'">' . $this->_text . '</a></li><ul>';
}
$itr = new NavIterator($this->_components);
while($itr->hasNext()) {
$obj = $itr->next();
$obj->display();
}
if($this->_topLevel) {
echo '</ul>';
} else {
echo '</ul></li>';
}
}
Using the test file that came with the NavComponent class and subclasses you should get something just like this:

Step 2: Adding Style and That Cool Drop Down Thingy
Not too shabby but it doesn’t look much like a menu, that’s where the CSS and JavaScript come in: by adding some CSS to our menu we can get our structure looking more familiar and with the help of the jQuery library we’ll get our submenus to fade in and out when the parent has the mouse hovered over it. I won’t go through every step of creating a web page in HTML, check out the W3C tutorials for more information, but as most of the stuff we need to use goes in the header I’ll start there.
First thing let’s get our style sheets imported, for this example I have simply left them in the root project directory but feel free to put them anywhere. One of the style sheets being used is a CSS reset, this will “zero-out” HTML tag elements so that any further CSS we use will be applied consistently* across multiple browsers. The other style sheet will contain our structure and styling for the menu itself. I’m using the style created by Myles Angell for his Suckerfish Style menu with some modifications for color, typography, and button sizes.
<link rel="stylesheet" type="text/css" href="reset.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
We’re also going to be using the jQuery library and some embedded javascript to get our menu working right. We’ll tack our javascript on after the title. The embedded javascript are the functions we use to utilize the jQuery functionality we want. The first function is called when the document object is ready and adds a fade-in effect to the submenus. It also applies a CSS class to submenus when they are called, which is defined in the second function:
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
//when the mouse is hovering over a button, show the
//submenu if there is one
$("#navbar li").hover(
function(){ $("ul", this).fadeIn("fast"); },
function() { }
);
if (document.all) {
$("#navbar li").hoverClass ("sfHover");
}
});
$.fn.hoverClass = function(c) {
return this.each(function(){
$(this).hover(
function() { $(this).addClass(c); },
function() { $(this).removeClass(c); }
);
});
};
</script>
Now that we have the CSS and JavaScript in place we’re going to need to make one small change to the display() method inside the NavMenu class, when the top level of the menu is created we want to give the list an id and class to link into the style sheet:
if($this->_topLevel) {
echo '<ul id="navbar" class="nav">';
} else {
echo '<li><a href="' . $this->_link .
'" title="' . $this->_text .
'">' . $this->_text . '</a><ul>';
}
Once everything is in place give it a whirl, you should get something similar to this:
See a working example of the Horizontal Navigation Menu
Step 3: To Infinity and Beyond
Things are starting to shape up, we’ve got a pretty decent menu working now, but we’re lacking the ability to create submenus for our submenus and have them display correctly. Unfortunately, in order to achieve the desired results, we’re going to have to re-structure our files and make some (final) changes to our code. We’re going to be adding a few more files to our project so to better keep them organized let’s update our file structure. We’ll keep the CSS, javascript, classes, and images in separate directories with the index.php in the root of our project like so:

To get the desired functionality we’re going to need to bring in another component called Superfish, a jQuery plugin that takes an existing pure CSS drop-down menu and adds some enhancements like keyboard accessibility and drop shadows. To use Superfish we need to add a couple more style sheets to the ones we have already (make sure to copy the arrow and shadow .png’s to your images directory and update the CSS). These two files will allow us to create both vertical and horizontal menus with drop-downs with some modifications for color, typography, image locations, and button sizes:
<link rel="stylesheet" type="text/css" href="css/reset.css" />
<link rel="stylesheet" type="text/css" href="css/style.css" />
<link rel="stylesheet" type="text/css" href="css/superfish.css" />
<link rel="stylesheet" type="text/css"
href="css/superfish-vertical.css" />
We also need to alter the original style.css, most of it is not needed any more as the necessary style components are included in the Superfish CSS files. You can get rid of everything in the file except the following lines that apply the hover effects for the submenus:
#navbar li:hover a,
#navbar li.sfHover a {
background: #999900;
color: #CCCC00;
}
#navbar li:hover ul a,
#navbar li.sfHover ul a {
background: #CCCC99;
color: #CC9900;
}
#navbar li:hover ul a:hover,
#navbar li.sfHover ul a:hover {
background: #CC9900;
color: #CCCC99;
}
Next thing we need to do is add includes for the javascript files we are using as part of the Superfish plugin; the hoverIntent file is optional should you choose not to use it. We also need to change the embedded javascript to reflect the new plugin. The following ties the Superfish code to the navigation menu through the sf-menu class and adds an animation to the mouse-over with a delay to fade-out on mouse-out:
<script type="text/javascript" src="javascript/jquery.js"></script>
<script type="text/javascript" src="javascript/superfish.js">
</script>
<script type="text/javascript"
src="javascript/jquery.hoverIntent.js">
</script>
<script type="text/javascript">
//controls the Superfish menu plugin
jQuery(function(){
jQuery('ul.sf-menu').superfish();
});
$(document).ready(
function(){
$("ul.sf-menu").superfish({
// slide-down effect without fade-in
animation: {height:'show'},
// 4 second delay on mouseout
delay: 400
});
});
</script>
With the javascript and CSS in place the last thing we need to do before testing is make one last change to the NavMenu class.
In order to make the class more flexible we’re adding a private member variable to store a class name as a string that is used to assign a CSS style to the list. We need to change the constructor to reflect this but we aren’t going to require it for instantiation, we’ll also provide default value for the link for the same reason. The last thing we need to do is add a setter method for the class variable and update the display() method.
Note: I also changed the name of the $_topLevel variable to $_isTopLevel to make it a little easier to read.
private $_class;
public function __construct($text, $link='#', $class='') {
$this->_text = $text;
$this->_link = $link;
$this->_class = $class;
}
... other methods here ...
public function setClass($class) {
$this->_class = $class;
}
public function display() {
if($this->_isTopLevel) {
echo '<ul id="navbar" class="' .
$this->_class . '">';
} else {
echo '<li><a href="' . $this->_link .
'" title="' . $this->_text .
'" class="' . $this->_class . '">' .
$this->_text . '</a><ul>';
}
$itr = new NavIterator($this->_components);
while($itr->hasNext()) {
$obj = $itr->next();
$obj->display();
}
if($this->_isTopLevel) {
echo '</ul>';
} else {
echo '</ul></li>';
}
}
A completely optional change to the test file that I also made at this time was moving the menu construction to another file and then including it. While doing this make sure to update the call for the top level menu to include the class required to apply the Superfish styles:
$menu = new NavMenu('menu', '#', 'sf-menu sf-vertical');
Assuming you are using the vertical version of Superfish you should see something strikingly similar to this:
See a working example of the Vertical Navigation Menu
Provided the proper CSS styles you should be able to switch between horizontal and vertical versions of the menu just by changing the class used by the top-level menu. This may seem like quite a bit of work to create a navigation menu, after all there isn’t much markup required to code an <ul> by hand, but the real strength of this type of menu creation lies in its portability and dynamic nature, you could just as easily use this as a navigation menu populated from a SQL database as you could use it to represent players as they log into an online game with the submenus serving as commands used to interact with them.
One final note: It might be easier to condense all the style sheets in one file and then have just one style sheet to link. How you do it is completely a style choice.
Download the source for the Navigation Menu.