Using JavaScript to Style Active Navigation Elements

Published April 28, 2009 by CSS Newbies.

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.

60 Responses

  1. Hoi (reply)

    Pretty shitty method.
    Just do this.addClass(‘active’) in the onclick.
    If you want to refresh the entire page just store the number of the nav in a variable and set it active on page load.

    1. Rob Glazebrook (Author) (reply)

      While I appreciate the feedback, storing an item in a JavaScript variable and then refreshing the page would wipe out that variable — hence the URL comparison stuff. You could admittedly use cookies instead of a variable to store information about the click, but in a lot of ways this is simpler.

  2. facebook hacker (reply)

    Last spring Summit Entertainment requested viewers to avoid viewing or clicking on hot photos
    having disclosed on the Internet, especially scenes of Bella and Edward in bed.

    Very often in corporate environments it is very easy to walk around an office and gain access to their systems just by looking out for post it notes
    attached to screens or desks. However, if you are concerned about complete security and need
    help regarding virus attacks then it is advisable to seek help from an expert in this
    matter.

  3. crown hill remodeling expo (reply)

    Great blog! Do you have any suggestions for aspiring writers?
    I’m planning to start my own blog soon but
    I’m a little lost on everything. Would you
    recommend starting with a free platform like WordPress or go for a paid
    option? There are so many options out there that I’m totally confused
    .. Any recommendations? Cheers!

  4. ujeb.pl (reply)

    The Memory Healer Program’s easy-to-use abilities
    will appeal to some number of people. That is our resolution as
    regards to The Memory Healer Program.

  5. newcaredentist (reply)

    Hi! I am using the code, that you provided above, in two navigation bars, one in the middle and a second one in the footer my blog
    http://newcaredentist.blogspot.gr/
    but only one of them works. I mean only one of them, the one that was added last,
    marks the current page as active. Does it have to do with the simultaneous “onload”? Is there a way to overcome this and make both navigation bars work properly? Thank you in advance!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>