Skip to page content or skip to Accesskey List.
Search evolt.org
evolt.org login: or register

Work

Main Page Content

Javascript navigation - cleaner, not meaner

Rated 4.21 (Ratings: 11) (Add your rating)

Log in to add a comment
(19 comments so far)

Want more?

 
Picture of codepo8

Chris Heilmann

Member info | Full bio

User since: July 29, 2002

Last login: April 27, 2006

Articles written: 17

It is common practise to enhance the user experience of an HTML document by adding interactivity via Javascript. DHTML drop downs, tabs, layer navigations, image slide shows and so on and so forth are scattered all over the web.

The times are changing

In the days of the wild wild web, when browsers sported fours in their navigator string many a bloated script was developed to make the pages come alive. Developers followed the dark path of browser detection and implemented several different DOM solutions in parallel to support every dodgy brower that claimed to understand CSS and Javascript. Furthermore, they did the nasty by making the navigation dependent on Javascript, rather than enhanced through it.

The times have changed, the browsers have matured and so should we. Accessibility guidelines and SEO practises tell us not to rely on Javascript, but neither do they forbid us to use it.

The trick is to use it wisely.

This article is not showing off any special javascript navigation treat, all it does is to show a small trick that helps us keep our markup as clean as possible.

The HTML structure

Every Javascript enhanced navigation should provide a real link, to avoid dead links should Javascript be turned off (if this is still news to you and you wonder why, read the superb Links & JavaScript Living Together in Harmony article). Normally, this is achieved thus:

<a href="#target" 
onclick="myfunction(myparameters);return false">Link</a>

If you want to ensure that your links are also usable for people without a mouse, add an onkeypress handler.

<a href="#target" 
onclick="myfunction(myparameters);return false"  
onkeypress="myfunction(myparameters);return false">Link</a>

In most navigation scripts, myparameters is some sort of ID. The script does something with that, and, should javascript be disabled, the browser simply takes the user to the target the link points to.

Easy and fully accessible — but bloated.

Leaner but not meaner

Let's be greedy. All we want to appear in our HTML is this:

<a href="#target">Link</a>

Impossible? No, actually it is rather easy. We need a helper, who adds the onclick and onkeypress handlers and we need to find the right ID somehow.

Adding the event handlers is rather easy. Let's take this navigation for example:

<ul id="mainnav">
	<li><a href="#why">Why</a></li>
	<li><a href="#now">Now</a></li>
	<li><a href="#brown">Brown</a></li>
	<li><a href="#cow">Cow</a></li>
</ul>

To add the handlers to this one, we need to execute the following after the page has loaded:

1  function init()
2  {
3   	if(document.getElementById && document.createTextNode)
4		{
5			var mn=document.getElementById('mainnav');
6			var as=mn.getElementsByTagName('a');
7			for (var i=0;i<as.length;i++)
8			{
9				as[i].onclick=function(){show(this);return false}
10				as[i].onkeypress=function(){show(this);return false}
11			}		
12		}
13 }

First, we check if the browser is capable of handling the W3C DOM(line 3). Then we grab the element with the ID mainnav (line 5) and get all the elements with the name A that are inside this element — our links(line 6).

Then we loop through these links (line 7 to 11) and add an onclick (line 8) and an onkeypress (line 9) handler to them, assigning both these handlers a function that calls the function show() with the link object itself as the parameter and ending with a return false to prevent the browser from jumping to the anchors after the script was executed. (line 8 and 9)

After this loop is executed, all links in the navigation will call the function show() with the link object as the parameter.

Clickable, but what about the parameter?

The this we send onclick and onkeypress is a mighty tool. We can read all the attributes of the link from it. In our case, we need the url value of the link. This means our function show() should do the following

function show(l){
	var urldata=l.href;
}

to retrieve the url data. Now, the only remaining issue, is that the url sent from the browser is the complete one, whereas all we need is the last bit, the name of the ID we'd like to manipulate.

Regular Expressions help us there:

function show(l){
	var urldata=l.href.match(/#(\w.+)/)[1];
}

The variable urldata now contains the id that we want to manipulate (we checked the url data for the hash character and matched the following word).

Ok, nice, but what then?

This is it, we turned the UL with the links into a javascript enhanced navigation, that executes the function show() onclick and onkeypress. What we want to do with it, is ours to explore.

One quick example? OK:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html dir="ltr" xml:lang="en" lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> 
	<title>Showme hideme</title>
	<script type="text/javascript">
		function init()
		{
			if(document.getElementById && document.createTextNode)
			{
				var mn=document.getElementById('mainnav');
				var as=mn.getElementsByTagName('a');
				for (var i=0;i<as.length;i++)
				{
					as[i].onclick=function(){show(this);return false}
					as[i].onkeypress=function(){show(this);return false}
				}		
				hidem();
			}
		}  
		function show(l)
		{
			hidem();
			var id=l.href.match(/#(\w.+)/)[1];
			document.getElementById(id).style.display='block';
		}
		function hidem()
		{
			for (var i=0;i<document.getElementsByTagName('div').length;i++)
			{
				document.getElementsByTagName('div')[i].style.display='none';
			}
		}
		window.onload=init;  
	 </script>
</head>
<body>
<ul id="mainnav">
	<li><a href="#why">Why</a></li>
	<li><a href="#now">Now</a></li>
	<li><a href="#brown">Brown</a></li>
	<li><a href="#cow">Cow</a></li>
</ul>
<div id="why">...why data...</div>
<div id="now">...now data...</div>
<div id="brown">...brown data...</div>
<div id="cow">...cow data...</div>
</body>
</html>

We added a new function called hidem() Which hides all the DIV elements in the document (granted, a crude approach, as you might want to use other DIVs). We call this function in the init() function to hide all texts our navigation points to (this could have been done in CSS, too, but that'll mean the page is not accessible, as it needs Javascript to show the text!). Then we call it again in our show() function to hide the last shown text (we could use a global variable for that and spare us the looping, knock yourselves out). Then we retrieve the ID via the regular expression, and show the DIV with this ID.

Currently employed in London as a Lead Front End Developer, Chris has been bouncing around the globe working for several agencies and companies. A web enthusiast from 1997 on workplaces include Munich, London, Santa Monica and San Francisco. More of Chris' writings can be found at http://icant.co.uk and he blogs at http://wait-till-i.com

onkeypress vs. onfocus

Submitted by notabene on February 17, 2004 - 02:06.

I've tested this onkeypress option with Firebird using only my keyboard, and found that it activates whatever one wants to activate (fill a form, change a CSS property, etc) when I tab out of the control.

When the activation is onfocus, the action takes place when I tab into the control.

Can you explain why you chose onkeypress and not onfocus, then?

(I'm sure it's got to do with other browers, but haven't had time to test further so far)

login or register to post comments

RE: onkeypress vs. onfocus

Submitted by Jeff Howden on February 17, 2004 - 02:35.

Stef,

I think maybe Firebird's implementation of the onkeypress event handler may be broken/too greedy. Internet Explorer only triggers the onkeypress event handler when an alphanumeric key is pressed, but not tab, backspace, and some other special keys.

onkeypress Event at MSDN

I'm not really at a place where I can dig for similar Mozila or W3C DOM references. Anybody have some links handy?

.jeff

login or register to post comments

I agree with jeff here

Submitted by codepo8 on February 17, 2004 - 02:56.

I used onkeypress firstly as the WAI recommends it: http://www.w3.org/TR/WCAG10-HTML-TECHS/#directly-accessible-scripts.

I know about the problems with mozilla and opera, but they are not mine to fix, and logically onkeypress is the right thing to to.

Mozilla seems to be aware of it:http://bugzilla.mozilla.org/show_bug.cgi?id=184637.

login or register to post comments

RE: onkeypress vs. onfocus

Submitted by notabene on February 17, 2004 - 05:25.

I'll test further with other event handlers, like maybe onkeydown, and I'll let you know.

login or register to post comments

Show or Start?

Submitted by mcombs on March 3, 2004 - 14:39.

I'm a JavaScript rookie, so I read this stuff pretty carefully, trying to figure it out. Your article says:

After this loop is executed, all links in the navigation will call the function start() with the link object as the parameter.

Should that be show() instead of start()?

login or register to post comments

Oh my

Submitted by codepo8 on March 3, 2004 - 14:58.

Cheers for that, will edit it.

login or register to post comments

Google Crawls Javascript

Submitted by nainil on April 8, 2004 - 17:55.

Hi,

I read this article about "Google Crawls Javascript"

http://www.markcarey.com/googleguy-says/archives/google-crawls-javascript.html

I am pretty sure..that better javascript coding would only help in SEO techniques rather than causing a dramatic effect on the web dynamics adopted by the Search Engines.

login or register to post comments

@ .jeff

Submitted by haidary on April 20, 2004 - 21:10.

The Firefox implementation isn't broken afaik. onkeypress does exactly what it should do, execute the funcion when a key's pressed. It's IE that has it wrong imo. You should always check to make sure it's the enter key being pressed when using onkeypress with navigation.

~ sipher

login or register to post comments

Nice modularity

Submitted by tupholme on May 13, 2004 - 11:04.

Good article, it's nice the way the code is fully generalised so that it just handles data passed into it rather than having to have knowledge of the page it accompanies. Elegant, where lots of Javascript isn't!

On the other hand, is it solving a genuine problem? Markup is the top layer in the architecture we work with, and there's really no conceptual difficulty with it knowing about Javascript functions & parameters, data or anything else in the layers below.

Jeff

login or register to post comments

Jainrahul

Submitted by codepo8 on May 17, 2004 - 19:08.

I cannot really follow your comment, what exactly do you want to achieve? This article shows a technique how to keep Javascript cleaner and uses a navigation as an example, you are invited to make your own functions in the same way.

However, you are _not_ invited to link every dash to your own web site to get more links. Please don't abuse this commenting system!

login or register to post comments

XP sp2 security

Submitted by babygoat on December 10, 2004 - 11:51.

I love this, I noticed though that when I create an HTML file with your code and try to view it with IE6.0 on WinXP sp2 I get a security prompt saying that some code on the page could harm my computer and that it as been blocked. Basically the resut is the same as if the init function was not called! Anyway around this you think?
Thanks

login or register to post comments

Brown Cow

Submitted by complexprocess on August 30, 2005 - 13:05.

I know I'm WAY late to the party, but shouldn't it be "how now brown cow?"

Also, I'm guessing babygoat will never read this (as his comment was posted nearly a year ago,) but for anyone else's benefit that issue should only effect files on your local machine. If the files are uploaded to a webserver and tested, there shouldn't be any prompt.

login or register to post comments

Learning Javascript

Submitted by lsbushell on September 20, 2005 - 15:30.

Looking over your code I am wondering how do I get the first div of content (the why) to load initially so that some content will display when the page loads. Maybe a simple question but again am new to all of this. Thanks

login or register to post comments

Wow what a superb code!

Submitted by supertrusted on December 14, 2005 - 11:31.

I'm grateful you posted this code Chris - I've been searching for a while, I can tell you!

I make templates with an included list-based menu in each which can have any number of links and I would like a way to dynamically style the link to show that you're on the current page for that link (sort of "if page url = link then style the link"). Your neat solution would be brilliant if I could get the syntax right.

Thanks for any help you can offer!

login or register to post comments

how to?

Submitted by grieco on January 15, 2006 - 17:26.

How to make first div eg. div#why - default visible after load page?

login or register to post comments

This script

Submitted by downsjn on June 8, 2006 - 17:26.

this code really helped me design our page the way we wanted it. with a little help from some friends who are much more knoledegeable about javascript. thanks see it in use here http://sacramentofrenchfilmfestival.org/program06.htm (beta now) http://sacramentofrenchfilmfestival.org/program.htm (live soon) http://sacramentofrenchfilmfestival.org/archives/program06.htm (once it's archived in a year)

login or register to post comments

first div (or any div) visable on load

Submitted by downsjn on June 8, 2006 - 17:39.

i had the same issue.
my buddy kevin provided the solution
see it in action here
http://sacramentofrenchfilmfestival.org/program06.htm (now)

http://sacramentofrenchfilmfestival.org/program.htm later

login or register to post comments

help with DIVs

Submitted by jhype on August 13, 2007 - 17:17.

(granted, a crude approach, as you might want to use other DIVs)
Yes, I have to use other DIVs! I am new at javascript and have not had any luck trying to adjust the scrip to use IDs or classes instead of DIVs for hiding and showing the content. Any help is much appreciated...

login or register to post comments

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.orgEvolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.