Categories

Close

Design Lunatic

A Continuation of the Isotope Tutorial: Highlight the currently active link

In web design, the navigation bar is crucial in telling the user where he is located. Usually, the user is further helped out by highlighting the currently active menu item. For example, if the user is on the “About Us” page, the “About Us” link in the navigation bar will be styled to look different. Unfortunately, if the site uses Isotope.js, the user won’t know what is currently being displayed. In this post, I’ll show how that can be fixed so that the user can have an excellent experience even on a site using Isotope.

This post will be based on the code from the isotope tutorial I wrote a while ago, so grab a copy of the code from there.

HTML

The HTML we’ll use is identical to the code from the isotope tutorial you just downloaded, except for one small thing.

Add data-current="" to the #content div, so that the result looks like this:

<div id="content" data-current="">

We’ll be using this attribute to store the category that is currently being shown.

CSS

The CSS is exactly the same as from the isotope tutorial previously. No need to change anything here.

Javascript

We’ll rewrite the javascript code from the previous tutorial, as it has changed considerably.

First of all, make a nice $(document).ready function:

$(document).ready(function(){

});

Now, we need to write the code that will “isotope” the boxes on the page.

var $container = $('#content');
var toFilter = '*';

$container.isotope({
	filter: toFilter,
	animationOptions: {
		duration: 750,
		easing: 'linear',
		queue: false,
	}
});

Here, the variable $container is whatever container you want to isotope. The variable toFilter is what the $container is filtered by. The reason we have a variable for this is because later on in the code, we have to know what what $container is filtered by. The rest of the code is isotope-specific, and is completely self-explanatory.

Remember that “data-current” attribute on the $container? We’ll start to use it now.

$container.attr('data-current',toFilter);

This code sets teh “data-current” attribute to what the $container was originally filtered by. This way, we can highlight the currently active navigation as soon as the page loads. More on that later.

We can now write the function that will determine what the $container is currently being filtered by, which we’ll call “checkActive”.

function checkActive(){

	$('#nav a').each(function(){
	
	});

}

Inside the “checkActive” function, we have a .each function. This basically iterates over each element that matches the selector. In this case, the code inside the “each” function repeats itself for each #nav a.

Now, take a look at the title of each nav link. Notice the fact that it doesn’t have a “.” at the beginning of it. This needs to be fixed before we can accurately compare the “data-current” attribute with the title of each nav link.

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
	});

}

This takes the title attribute of the nav link the each function is currently iterating over, and adds a “.” to the beginnnig of it.

But wait! What if the title attribute is “*”, like in the link that says “All”?

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
	});

}


That fixes it.

In order to find out which link to highlight, we need to find out which category is currently being displayed.

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
		var currentCat = $container.attr('data-current');
	});

}

Now, we can compare the two to find out whether the link the each function is currently on is the right one or not.

if(title==currentCat){
	$(this).css({
		color: '#00ff00'
	});
}

Here’s what we have so far:

function checkActive(){

	$('#nav a').each(function(){
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
		var currentCat = $container.attr('data-current');
		
		if(title==currentCat){
			$(this).css({
				color: '#00ff00'
			});
		}
		
	});

}

However, there’s a slight problem with this code: the links won’t return to their previous states if the active category changes. We can fix this by making a type of “reset” that will make all links the way they were originally, and then changing whichever one needs to be changed.

function checkActive(){

	$('#nav a').each(function(){
		
		$(this).css({
			color: '#595959'
		});
		
		var title = $(this).attr('title');	
		title = '.'+title;
		
		if(title=='.*'){
			title = '*';
		}
		
		var currentCat = $container.attr('data-current');
		
		if(title==currentCat){
			$(this).css({
				color: '#00ff00'
			});
		}
		
	});

}

We can now create the rest of the javascript code.

Here’s where we left off:

var $container = $('#content');
var toFilter = '*';

$container.isotope({
	filter: toFilter,
	animationOptions: {
		duration: 750,
		easing: 'linear',
		queue: false,
	}
});

$container.attr('data-current',toFilter);

checkActive();

With this code, the “checkActive” function will fire right after the $container is isotoped, and will highlight the “All” link.

Now, we need to make the nav links actually work.

$('#nav a').click(function(){
	return false;
});

This way, when a nav link is clicked, it won’t actually redirect the user to a different page.

In order to filter the $container, we need to define a few variables.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	return false;
});		

Now, we have to check with or not the link that was just clicked is the “All” link or not.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	
	return false;
});	

Next, we need to set the “data-current” attribute of the $container to reflect what it is being filtered by.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	$container.attr('data-current',selector);
	
	return false;
});	

Now that we’ve defined what the $container is currently being filtered by, we need to actually filter the $container.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	$container.attr('data-current',selector);
	
	$container.isotope({ 
		filter: selector,
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});
	
	return false;
});	

After the $container has been filtered, we have to run the “checkActive” function to highlight the currently active link.

$('#nav a').click(function(){
	
	var title = $(this).attr('title');
	var text = $(this).text();
		
	if(text == "All"){
		var selector = title;
	}
	else {
		var selector = "." + title;
	}	
	
	$container.attr('data-current',selector);
	
	$container.isotope({ 
		filter: selector,
		animationOptions: {
			duration: 750,
			easing: 'linear',
			queue: false,
		}
	});
	
	checkActive();
	
	return false;
});	

And there you have it: upon clicking a link in the navigation, it becomes different-looking so that the user knows what is currently being displayed. Now, you may wonder why we didn’t just make the link change color upon being clicked without worrying about the “data-current” attribute and all that. The reason is that this code works much more flexibly and with many other situations. For example, what if there’s a link inside the content of the page? All you need to do is modify the $('#nav a') selector to include links inside the post, and when a link in the post is clicked that filters the content, the navigation changes to reflect that. Or, what if there’s another piece of code that needs to know what category is currently being displayed? You don’t even have to modify anthing! Just find out the “data-current” attribute of the $container, and you’re done.

In other words, this code is highly flexible and adaptible, and not just this situation specific. I hope you learned something from this tutorial. If you have any questions or comments, feel free to use the comment form below.

  • hellomarcy

    I love you. 

  • http://www.facebook.com/profile.php?id=100002753651186 Mirko Zorić

    Thanks for the great tuts. You are bookmarked for some time!

    I am interested if it is possible to filter in Isotope based on two categories. For example, my next project needs a list of shops in several countries, but also these shops are divided by online shops and normal shops.

    If I filter for online shop i would like them displayed, but i would also need them to have second category for country. If the filter is Spain, list all shops in Spain.

    Basically my question is can i have two categories assigned to item.

    p.s. Even better would be to search for online shops in Spain, if possible.

  • Delgadoatl

    dl
    this is a great tutorial, thank you very much,
    i have a question , is it possible to have a dropdown list (….)  instead of list, i have too many categories and they take a lot of space

  • Victoria

    I have a problem and I’m hoping you can let me know what to do. I am using the navigation to filter the page contents, which works fine. But I would like to put that navigation on another page – and then when clicked – it goes to the filtering page with that option being displayed? Is there any easy way to do this?

  • Anonymous

    Hello, thanks for the tutorial, but I can not change some lines of code:
    I have already allocated to the menu through css data
    li a {text-indent:-9999px; background: url (.. / images / subnav.png) 0 0;}
    li a: hover {opacity: 1;}
    li.selected to {opacity: 1;}
    li.all a {background-position: 0 0;}
    li.all a: active {background-position: 0-31px;}
    li.all.selected a {background-position: 0-31px;}
    li.web a {background-position:-78px 0;}
    li.ebay a {background-position:-156px 0;}
    and so on …

    I just do not understand what I need to change these lines of code:

    $ (‘# nav a’). each (function () {
    $ (this). css ({
    color: ‘# 595959′
    });

    if (title == currentCat) {
    $ (this). css ({
    color: ‘# 00FF00′
    });

    where instead of saying the color, I go get the settings on the file style.css

    Could you help me? thanks

    • Alexandre Smirnov

      Instead of manually defining the color for each link, you could declare a new variable which holds the CSS “color” value of each link, and use that.
      var linkColor = $(‘#nav a’).css(‘color’);
      $ (‘# nav a’). each (function () {
      $ (this). css ({
      color: linkColor
      });

      if (title == currentCat) {
      $ (this). css ({
      color: ‘# 00FF00′
      });

      }

      });

      Another option you have is to create a class, for example “.active”, and apply that whenever the link is active.

      $ (‘# nav a’). each (function () {
      $ (this). removeClass(‘active’);

      if (title == currentCat) {
      $ (this). addClass(‘active’);

      }

      });

      • Anonymous

        Hi Alexandre,
        thank you very much for your reply.

        Even if I change as you say (removeClass and addClass) I did not change the situation, the menu remains unchanged and isotope does not work, I think there is an error in the script because the script instead of using your other article (Isotope tutorial) work the animations …

        I can not understand where is the error

              $ (Document). Ready (function () {
                var $ container = $ (‘# content-portfolio’);
                tofilter var = ‘*’;

                $ Container.isotope ({
                  filter: tofilter,
                  animationOptions: {
                    duration: 750,
                    easing: ‘linear’,
                    queue: false,
                  }
                });

                $ Container.attr (‘data-current’, tofilter);

                CheckActive ();

                $ (‘# Subnav-portfolio a’). Click (function () {
                  var title = $ (this). attr (‘title’);
                  var text = $ (this). text ();
                  if (text == “All”) {
                    var selector = title;
                  }
                  else {
                    var selector = “.” + Title;
                  }

                  $ Container.attr (‘data-current’, selector);

                  $ Container.isotope ({
                    filter: selector,
                    animationOptions: {
                      duration: 750,
                      easing: ‘linear’,
                      queue: false,
                    }
                  });

                  CheckActive ();

                  return false;
                });

                CheckActive function () {

                  $ (‘# Subnav-portfolio a’). Each (function () {

                    $ (This). RemoveClass (‘active’);

                    var title = $ (this). attr (‘title’);
                      title = ‘.’ + title;

                    if (title == ‘. *’) {
                      title = ‘*’;
                    }

                    var = $ currentCat container.attr (‘data-current’);

                    if (title == currentCat) {
                      $ (This). AddClass (‘active);
                    }

                  });
                }

              });

                   
                     
                        All
                     
                     
                        Web
                     
                     
                        Ebay
                     
                   
                 
                 

        • Alexandre Smirnov

          Have you tried just copy-pasting the code from the ZIP file in the “Download Links” link? I know for a fact that that works, so maybe that will help you.

          • Anonymous

            Now it’s ok, thank’s so much, I lost to change data-filter in title…

            All
            All

  • Pingback: Anonymous

  • http://thetaoofcurtisflick.com Curtis Flick

    Awesome tut! I modified the js to make use of the addClass() and removeClass() functionality instead to allow changes to be done is css. I wonder if there’s any potential problem with that?

    • Alexandre Smirnov

      Actually, that’s an even better way to do it. Thanks!
      **
      [image: Disqus] Settings
      A new comment was posted on Design Lunatic —————————— *Curtis Flick*
      Awesome tut! I modified the js to make use of the addClass() and removeClass() functionality instead to allow changes to be done is css. I wonder if there’s any potential problem with that?

      3:17 p.m., Wednesday May 1
      * Reply to Curtis Flick * Moderate this comment by email

      Email address: *curtisflick@gmail.com* | IP address: 97.112.160.218

      Reply to this email with “Delete”, “Approve”, or “Spam”, or moderate from the *Disqus moderation panel*.

      ——————————

      You’re receiving this message because you’re signed up to receive notifications about activity on threads authored by baldeagle76. You can unsubscribe from these emails, or reduce the rate at which we send them by adjusting your notification settings .
      [image: Disqus]

  • Dylan

    This is great, thanks! I have a question though: If the user is not clicking on text, but instead images, how would I change the image on click instead of changing the font color?

  • neomale

    Hi, great tutorials you are writing keep your good job! I already use your “combination filters” and it work great.

    2 questions

    First
    Like i say i use your “combination filters” so how can i apply on my 2 filters this tutorial. I already install it and it work on my first filter but how can i apply it on my second?

    Second
    My first filter need different data-current background color for each choice. Is this possible or am i dreaming :)

    Thanks for any help
    Regards