Using JavaScript to Style Active Navigation Elements

active navigation element

I’m all about efficiency when I’m writing web code. Any time I find myself writing the same functionality more than once or twice, I try to consider whether my repeated code could be wrapped into a function of some sort.

Navigation is often one of those areas where I try to improve my efficiency. I like my navigation elements to pull double duty. I want them to:

  1. Show the user where they can go, and
  2. Show the user where they currently are.

In other words, I want some sort of visual indication in my navigation that shows my user which section of my site they’re in. You can see this on the CSS Newbie site: if you click on the TOC (Table of Contents) link in the bar at the top of the page, you’ll see that link gets special styling when the table of content loads.

Now, I could manually set this on every page using a CSS class. But that’s inefficient — depending on the size of my site, I could end up writing dozens or hundreds of lines of one-off code. And why go to all that work, when you could just wrap it all up into a nice JavaScript function?

First, I’ll explain the logic behind my functions — because they won’t work equally well for every site. Then I’ll walk you through a few examples of the code that makes it all happen.

The Logic

All of my functions assume a very clean, straightforward directory structure. For example, if you have an About section, a Blog section, and a Contact section on your site, a logical directory structure might be:

/
/about/
/blog/
/contact/

And if you had several blog entries inside your blog directory, your structure might grow like this:

/
/about/
/blog/
/blog/post-one/
/blog/post-two/
/blog/post-three/
/contact/

And therefore, a function could logically assume that anything inside the blog directory should be considered a part of the blog section of your site, and mark the blog link as active for those pages. This makes our job a lot easier. And luckily, most CMS platforms make this sort of directory structure pretty easy to create.

The functions also assume that you have either a fairly shallow directory structure, or that you're not linking to too many similarly nested directories. What I mean by this is, if you have this sort of a structure:

/
/contact/
/contact/me/
/contact/me/here/

And you wanted to link to both /contact/ and /contact/me/here/ in your navigation bar, you might run into problems distinguishing between the two. There are ways to increase precision, but they come at the cost of flexibility.

But enough of that. Let's get to the good stuff!

A JavaScript Solution

I've written about this method before, when I previously talked about building intelligent navigation bars. This technique is nice because it doesn't rely on any JS frameworks, so you can add it to older sites without needing jQuery or the like. The basic function looks like this:

function setActive() {
  aObj = document.getElementById('nav').getElementsByTagName('a');
  for(i=0;i<aObj.length;i++) {
    if(document.location.href.indexOf(aObj[i].href)>=0) {
      aObj[i].className='active';
    }
  }
}

This function looks for an element with an id of "nav" (presumably your navigation bar), then looks at each of the anchor tags inside it. It then compares the anchor tag's href tag with the page's URL. If the href tag is contained within the URL anywhere, it gives that link a class of "active," which I can then style specially in my CSS.

As an example of what I mean by all that, if I had an anchor tag in my navigation bar that linked to "/blog/" and the page I was on was "/blog/this-is-a-post.html", my blog link would be styled as active, because "/blog/" is contained within "/blog/this-is-a-post.html".

As a final note, you wouldn't want to call this function until the page was finished loading: if you call it too soon, your links won't exist yet! So you can either call it at the very end of your document, or dynamically call it when your page is done loading, with something like this:

window.onload = setActive;

A jQuery Solution

If you are already loading a framework like jQuery (like I do on almost every site I work on these days), this sort of functionality could be written even more succinctly. And like I said earlier, I'm a sucker for efficiency. Here's a jQuery solution that does essentially the same thing in a much smaller space:

$(document).ready(function() {
	$('#nav a[href^="/' + location.pathname.split("/")[1] + '"]').addClass('active');
});

This function is making use of both native JavaScript and jQuery tricks to reach a whole new level of brevity. First, the whole thing is wrapped in a "document ready" function, which means it won't fire until the page is loaded and our links are in place. Next, we're looking for anchor tags inside our "nav" ID. And really, we're looking for a very specific anchor tag: one whose href starts with (^=) a slash, followed by a part of our page's location (location.pathname). Specifically, we're looking for the first directory in our page's URL.

We're doing this by making use of the JavaScript split() method, which lets us take any string (for example, "/blog/this-is-a-post.html") and break it into an array based on a substring (in our case, the forward slash). If you're familiar with PHP, it's similar to the explode() function. In our example, we'd end up with a three-part array that looked like this:

["","blog","this-is-a-post.html"]

Which means that if we look at the second value of our array (arrays start counting at zero, so [1] is the second value), that should give our first-level directory ("blog", in our example). This lets us match any subsequent child directories with our parent in the navigation bar.

Tweaking for Home Links

Our jQuery function works great in most scenarios, but it fails if you have a "home" link where you're just pointing to the root directory, like this:

<a href="/">Home</a>

And because I tend to have a link like that, I needed a workaround. Here's a way to get around that with just a little more code to account for our special case:

$(document).ready(function() {
	if(location.pathname != "/") {
		$('#nav a[href^="/' + location.pathname.split("/")[1] + '"]').addClass('active');
	} else $('#nav a:eq(0)').addClass('active');
});

Here, we're checking to see if we're in the root directory. If so, we're skipping the loop through our anchor tags and just making a specific anchor tag active. In this case, I'm giving the active class to the first anchor in our list (which is the most common location for a home link).

And that's that. If you know of even more efficient or fool-proof ways to accomplish this task, I'd love to hear about them in the comments section. Or if you're skilled in a framework other than jQuery, feel free to share the equivalent code!

Note: I apologize for the long gap between articles. I had some problems while rebuilding my PC (DOA motherboard) and was without my computer for several weeks.

6 Comments

  1. On April 28, 2009
    10:30PM

    Chris Gates said:

    Great to have these instructions. Thanks a lot!

  2. On May 03, 2009
    8:05AM

    paris said:

    nice article , there are lots of problems to make this effective thought!

    what if home was “” and not “/” (if u use the base tag) or even “/index.html”

    what if ‘contact/’ is the same as ‘contact.php?ref=site1234′ or ‘contact.php’

    what if links in the menu were in the style of “../path/to/file”

    what if menu item was “/path/index.htm” and url was “/path/”

    there are lots and lots of things to consider besides the obvious to make this work right :)

    found this jquery plug-in in the past which got lots of this right however, could not cover all of what i mentioned above :)

  3. On May 03, 2009
    8:06AM

    paris said:

    ups forgot to mention the jquery plugin that partially covers this
    http://devkick.com/lab/path/

  4. On May 05, 2009
    1:32PM

    Rob Glazebrook said:

    That looks like a pretty useful plugin, Paris — I hadn’t seen it before. Thanks for sharing it!

  5. Semblance said:

    This is really awesome. But you don’t happen to have an idea why:
    The active link show correct on the pages that I am on, but then also keep showing the home page active. So basically, each page that I visit has the home page link active + the current page link active?

  6. Ricardo Zea said:

    Well… what if my URIs are to files and not to folders?

    For example:
    http://www.website.com/about-us.php
    http://www.website.com/products.php
    http://www.website.com/contact.php

    Thanks.

12 Responses Elsewhere

  1. Matt the web designer » links for 2009-04-29 said:

    [...] Using JavaScript to Style Active Navigation Elements (tags: css javascript jquery navigation) [...]

  2. 10 Tips to Create a More Usable Web | Webdesigner Depot said:

    [...] As a third option, you can easily create active navigation with JavaScript. [...]

  3. 提高网站可用性的10个小技巧 | 互联网的那点事... said:

    [...] 另外,你可以方便的 使用JavaScript创建当前位置导航菜单。 [...]

  4. 10个提高网站可用性的实用技巧 - 菠菜博 said:

    [...] 另外,你可以方便的 使用JavaScript创建当前位置导航菜单。 [...]

  5. On June 12, 2009
    10:49PM

    提升网站用户体验的小技巧_ 金枫网络 said:

    [...] 另外,你可以方便的 使用JavaScript创建当前位置导航菜单。 [...]

  6. Using JavaScript to Style Active Navigation Elements | Design Newz said:

    [...] Using JavaScript to Style Active Navigation Elements [...]

  7. 10个提高网站可用性的实用技巧 « Dfey Creative Minds said:

    [...] 另外,你可以方便的 使用JavaScript创建当前位置导航菜单。 [...]

  8. 10 Tips to Create a More Usable Web | JB's Personal Portfolio said:

    [...] to style each navigation element directly is also a fine choice.As a third option, you can easily create active navigation with JavaScript.Your active navigation state should always be different from your hover state.2. Clickable labels [...]

  9. 提高网站可用性的10个小技巧 said:

    [...] 另外,你可以方便的 使用JavaScript创建当前位置导航菜单。 [...]

  10. 网站设计10个可用性技巧 - 静狼的交互设计 said:

    [...] 另外,你可以方便的 使用JavaScript创建当前位置导航菜单。 [...]

  11. 10个提高网站可用性的实用技巧 « theU0net.Blog said:

    [...] 另外,你可以方便的 使用JavaScript创建当前位置导航菜单。 [...]

Leave a Comment