View the entire menu in action
If you are a Front End Developer who gets frustrated, working with back end system where you can never seem to have fine control over the menu design. With the following technique, you should now have an extra option if you can’t explain what is required to a back end developer.
If you can’t sense my frustration, let me explain why I decided to write this solution to an obstacle that seems very real in the industry, to me anyway.
There have been a few occasions over the last few years where I wanted to produce a really functional, usable navigation system that just works. Unfortunately, my full time job as a Front End Developer, which I love, means that I do not make calls on Back End Development. It’s not that I want to either, we have a great system for content management and the necessary Development team members to carry out the Development work on these sites. As a front End Developer, my time is better spent working on new and creative ways to use XHTML, CSS and jQuery, so thats the way I decided to try and solve this issue.
What I want is a left aligned vertical navigation list that contains a nested list of links (so it is accessible). It lent itself to being an accordian style of functionality, for which there are 10′s of scripts. I’ve included the simple accordian script in this article but that isn’t the main point of it.
That’s only the half of it
The real functionality that I want to show you in this article, is the page recognition and how you can use this to make your menu much more usable. Firstly, the following script shows the snippet of html that will structure our menu:
<script src="js/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script src="js/jquery.effects.core.js" type="text/javascript"></script>
<script src="js/jquery-functions.js" type="text/javascript"></script>
<!-- #primarylinks ul li a { display: block; padding: 6px .5em 6px .5em; background: #f6f8f9; color: #000; text-decoration: none; text-decoration:underline; /*width: 9.6em;*/ font-size:0.9em; } #primarylinks ul li a:hover, #primarylinks ul li a.active { background: #ffffff; color: #333; text-decoration: none; } #primarylinks ul li ul { border-bottom: 0; margin: 0; } #primarylinks ul li ul li { border-top: 1px solid #fff; border-bottom: 0; margin: 0; } #primarylinks ul li ul li a { padding: 4px .5em 4px 1.3em; background-color: #f9fbfc; width: 13.3em; margin-bottom: 0; } -->
...
<div id="primarylinks">
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="about-us.html">About us</a>
<ul>
<li><a href="who-we-are.html">Who we are</a></li>
<li><a href="what-we-do.html">What we do</a></li>
</ul>
</li>
<li><a href="news.html">News</a></li>
<li><a href="publications.html">Publications</a>
<ul>
<li><a href="#">Publication 1</a></li>
<li><a href="#">Publication 2</a></li>
<li><a href="#">Publication 3</a></li>
<li><a href="#">Publication 4</a></li>
<li><a href="#">Publication 5</a></li>
<li><a href="#">Publication 6</a></li>
<li><a href="#">Publication 7</a></li>
<li><a href="#">Publication 8</a></li>
</ul>
</li>
</ul>
</div>
As you can see, it is a fairly standard nested list of links with a div around it with an id to make it unique.
Once this was in place and styled, you can see that full nested list. If you want to test this between different pages, you can save the same menu as ‘about-us.html’ and ‘who-we-are.html’. When you navigate between them, there is currently no active class. Of course there isn’t, nothing is telling to. This is the bit that should be generated dynamically. You can also achieve this using the jQuery below:
var loc = window.location.toString().split("/")
loc = loc[loc.length - 1]
$('a[href="'+loc+'"]').addClass('active');
//accordianMenu();
//nestCheck();
});
Ignore the two commented functions for now, these will be added next. Basically, what is happening here, is that we are assigning the current page location via javascripts built in window.location function and splitting it at the ‘/’. This creates an array of path locations, then discards all but the last one and applies an active class to any links that match this location. Go on, try it!
One step beyond
For usability and style, I wanted to add an accordian to the whole thing, closing up the nested list to hide all child elements and leave only the uppermost list. The top level sections if you like. I have to admit to finding a great slimline script after much hunting around and trying out plugins that just didn’t quite do what I wanted.
$('#primarylinks ul').hide();
$('#primarylinks ul:first').show();
$('#primarylinks ul li a').hover(
function() {
var checkElement = $(this).next();
if((checkElement.is('ul')) && (checkElement.is(':visible'))) {
return false;
}
if((checkElement.is('ul')) && (!checkElement.is(':visible'))) {
$('#primarylinks ul ul:visible').slideUp('normal');
//hug();
checkElement.slideDown('normal');
return false;
}
},function () {
//$('.hug').remove();
}
);
}
With a feeling of utter chuffedness, I then realised that in an ideal world, the menus with child elements should remain open if the user was either on the parent page or the child page of a section with a second list below it.
With a mixture of logic, my understanding of iterating through the DOM, the script I made prior to this and pure godlike Intellect
I came up with the following function to find the current active class, iterate through the parent or child elements and make sure that the current page elements are left open.
var numUlBelow = $('a.active').siblings('ul').size();
var numUlAbove = $('a.active').parents('ul').size();
if(numUlBelow >= 1){
$('a.active').parent().find('ul').show();
return false;
}
else if(numUlAbove >= 2){
$('a.active').parent().parent().parent().find('ul').show();
return false;
//alert(numUlAbove);
}
}
I did have a few headaches getting the function to work in conjunction with the others. The order is very important and once I included the accordian followed by this nestcheck function, I got the effect I was after.