Add something new to Virb:

Virb

Are you sure you want to delete that?

or Cancel

 

Posted on Jan 11, 2008

Simple, accessible jQuery menu

Not every website needs to be powered by a content management system, or even a simple blog engine. Sometimes, a fully powered CMS like Drupal or Joomla is just a little too much. Sometimes it's not even possible to use a database and all you have is your webserver, maybe equipped with PHP or ASP. For a simple website, it's even overkill to add the complexity of a database, and all you want is just some folders with static HTML files in them. But to make it easier to maintain and expand this website, you create some simple templates for the header and the footer, so you don't have to change all files if you need to change the copyright date or the tagline. These are included via some server-side processing, for example, with Apache server-side includes, or PHP includes.



But then you run into a roadblock when you try to maintain your navigation in a similar vein. Being a good standardistas, you use an unordered list for your navigation, and use CSS to present it. But in your navigation, you want to highlight the currently viewed page, since this greatly enhances the usability of your website and lets readers know where they are. And that requires a predetermined strategy to setup and maintain, such as using body id's and menu id's, or using PHP to match the page with the proper menu. These solutions have some drawbacks which led me to investigate an alternative solution. In this article, we'll look at some common techniques for highlighting the current menu item in an otherwise static website, and at a Javascript-based solution.





The ALA way



First of all, the most common solution is to add a class to the active menu item and style it with CSS. For example:







And in your CSS:




#nav a {
color: #999;

}



#nav a.active {
color: #000;
font-weight: bold;

}



That's easy enough to build, but it requires that your menu adapts itself to the current page in order to add the required class. You could use PHP to solve this, by adding some logic in the navigation file to match the current page with a menu item. This is essentially the approach that is explained in the ALA article Keeping navigation current with PHP. For each page, a unique id is added to the top, and each menu item in the separate navigation.php checks to see if the page id matches the menu id. If it does, a class is added which is styled with CSS:







It's a nice solution, but it still requires too much work: each page must include a unique identifier, and for each menu item you have to add a verbose check. We're looking for a solution that doesn't require any server-side logic, just some means to include files. Adding a page to your site should be as easy as creating a new page and adding a new link in the navigation file.



CSS-only does the trick



An alternative technique uses body id's and navigation id's. Each page page is assigned a unique id, just as each navigation item. If the body id and the navigation id are the same, then the menu item should be highlighted. Then you can add CSS rules for each combination of page and navigation id. Here's an example:




#home a#nav-home,
#products a#nav-products,
#contact a#nav-contact {
color: #000;
font-weight: bold;
}


Essentially, it's the same solution as the PHP method above, except it uses CSS to determine the logic of matching page id's with menu id's. Therefore it has the same drawbacks: each page requires a unique id, and adding a page means that your CSS needs to be changed. Our solution shouldn't require that much work or that much code, and should be unobtrusive: it has to work with our current markup and CSS.



The Javascript way



With Javascript, we can maintain our HTML and CSS seperate from the main file. We can use it to figure out if the page we're currently viewing matches a menu item, and if so, add a class to it which is styled with CSS. This solution doesn't require any page identifiers, serverside scripting or additional CSS rules for new pages. We start with the following minimal markup:







And this minimal CSS:




#nav a {
color: #999;

}



#nav a.active {
color: #000;
font-weight: bold;

}



To make it really easy, we use the excellent jQuery library to do the hard work for us, all we need to do is add the logic to figure out if the current page matches a menu item, and add the class="active" to this item. This is accomplished with merely four lines of code:




jQuery(function($) {
var path = location.pathname.substring(1);
$('#nav a[@href$="' + path + '"]').addClass('active');
});


It looks a bit complicated at first sight, but it's not so difficult.



The first line, jQuery(function($) { is shorthand for $(document).ready() and makes sure that all code within will be executed as soon as the DOM is ready. The second line, var path = location.pathname.substring(1); creates a variable called path which contains the path to the current page as it appears in the browser address bar. The third line is a bit more complicated. The first part, $('#nav a[@href$="' + path + '"]'), searches within the nav element the link whose location (the href) is equal to our variable path. The second part, .addClass('active'); adds the class attribute with a value of "active" to that element. The last line, }); closes the jQuery function and finishes our code.



That's all that is required. I've created a basic example that includes all of the above ingredients.



This is an accessible solution that only requires minimal markup. Since we use valid and semantic markup, all content is readily available for search engines, screen readers, mobile devices and other user agents. We enhance this markup by using CSS for presentation, and add Javascript to further improve the user experience. And finally, it's easy for us to setup and maintain.



Spicing it up



But wait: we can go further with this! What if your site grows and you decide to add some articles. To make it easy to maintain, you put each article in its own folder under /articles/. Your navigation.php would look like this:







As you can see, it's still a simple list, and the the articles submenu uses a nested list for it's sub navigation. Clean and easy, just as we like it. Our Javascript file is well equipped to handle nested lists, but wouldn't it be nice to only show the sub navigation if the articles link is chosen? Remember, since our Javascript is added on top of semantic markup that is styled with CSS, it works unobtrusively and enhances the page for users with Javascript enabled, but doesn't interfere with clients that don't have it enabled.



Let's see what we can come up with. First of all, we'll hide the subnavigation with Javascript. Since we also will use Javascript to show it, we make sure all functionality stays in the same layer. No Javascript, and everything is shown. This is easily accomplished with jQuery with this line:




$('#nav ul').hide();


The first part selects all unordered lists within our #nav element, and the second part hides it. This is an important design principle of jQuery, namely the ability to select HTML elements and apply behaviour to it by chaining them. We will use this ability to expand the menu matching code and add an action that will show the sub navigation:




.siblings("ul").slideDown();


Chained together, it looks like this:




$('#nav a[@href$="' + path + '"]').addClass('active').siblings("ul").slideDown();


The siblings selector makes sure that when a menu item is chosen, all lists within the same element will slide down. Remember that our sub navigation is in a list item together with the link. Therefore, the

    is a sibling of our link and can be targeted with that jQuery selector.



    Finally, to make sure the menu stays expanded when a sub menu item is selected, we need one last line to show the parent list.




    $('#nav a[@href$="' + path + '"]').parents("ul").show();


    We need this to be a separate line since in an expanded menu, only the sibling's unordered lists are shown, not the parents.



    Altogether, our site.js looks like this:




    jQuery(function($) {
    $('#nav ul').hide();
    var path = location.pathname.substring(1);
    $('#nav a[@href$="' + path + '"]').addClass('active').siblings("ul").slideDown();
    $('#nav a[@href$="' + path + '"]').parents("ul").show();
    });


    I've also created an example of this slightly more advanced menu. Note how the sub menu slides down when you click on articles, and stays shown when you select an article.



    So there you have it, an easy "plug and play" Javascript solution for keeping your current menu item highlighted that will allow you to use minimal markup in a seperately maintained navigation file that can be included with your method of choice (this is left as an exercise for the reader).



    Was it helpful? Was something not clear? Can you think of improvements or do you use another technique? Feel free to leave your feedback in the comments!

Loading comments...

Likes

Details

Viewed 87 times

© 2008 Jeroen Coumans

virb.com/t/411087
tweet!

Flag this text post!

Flag this text post as:

or Cancel

 

Advertisement

Flag this profile!

Flag this profile as:

or Cancel