Skip to page content or Skip to Accesskey List.

Work

Main Page Content

Javascript Navigation Cleaner Not Meaner

Rated 4.22 (Ratings: 11)

Want more?

  • More articles in Code
 
Picture of codepo8

Chris Heilmann

Member info

User since: 29 Jul 2002

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

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

evolt.org Evolt.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.