Fancy fixed Navigation powered by jQuery

on April 20th, 2011 in Design, Tutorial

Last week I redid my work page. It was hard to navigate through the page without a second navigation. So I used the chance to tinker around with jQuery. The goal was to provide an alternative to scrolling through the content. Also, it should be much easier to navigate through the page.

In this post I explain how to create a simple page layout with fixed navigation. jQuery is used to enhance usability of the the navigation even more.This includes animated scrolling, aligning the navigation to sections and a fancy fading effect.

Step 1: Basic HTML

First of all we have to create some basic HTML layout to work with. Nothing fancy, just a sidebar and a content area like this:

<div id="wrapper">
	<div id="sidebar">
		<ul id="navigation">
			<li><a id="navfirst" class="current" href="#">First Section</a></li>
			<li><a id="navsecond" href="#">Second Section</a></li>
			<li><a id="navthird" href="#">Third Section</a></li>
			<li><a  id="navtop"href="#">Back to top</a></li>
	<div id="content">
		<div class="section" id="first">
			<!--  content goes here -->	
		<div class="section" id="second">
			<!--  content goes here -->
		<div class="section" id="third">
			<!--  content goes here -->

Step 2: Adding the CSS

Now that we have the basic layout we position the element. Float the content div to the right and fix the position of the navigation list. Don’t forget to set a width for the list and the content. Otherwise the content will float over your navigation. The added width should be equal to the parent width. Don’t forget that padding is also added to the total width.

#wrapper {
    width: 850px;
    margin: 50px auto;
    overflow: hidden;

#sidebar ul {
position: fixed;
	width: 180px;

#content {
float: right;
width: 630px;
padding: 0 20px 20px;

Step 3: Aligning the navigation

The navigation is sticky already but the distance to the top will never change. This doesn’t look good and it could possibly cause some problems. E.g. the navigation can overlap with subsequent content. To prevent this from happening we’ll use some jQuery.

// distance to the window
var navOffset 	= 15;
// navigation is aligned to #content
var minTop = $('#content').offset().top,
	maxTop = $('#content').height()+minTop-$('#navigation').height();		
// place navigation
var currentScroll = $(window).scrollTop();
$('#navigation').css({'top' : minTop});
// align navigation after loading
if( currentScroll &gt; minTop &amp;&amp; currentScroll &lt; maxTop ) {
	// while scrolling though the content
	$('#navigation').css({'top' : navOffset+'px'});		
if( currentScroll &lt;= minTop ) {
	// adjust navigation top to content top
	$('#navigation').css({'top' : minTop-currentScroll});
if( currentScroll &gt;= maxTop ) {
	// end of content
	$('#navigation').css({'top' : maxTop-currentScroll});

This code will align the navigation to top edge of the content div and when you start scrolling it will fit the navigation to top edge as long as it is in the browser’s viewport (line 14-17). While scrolling though the site the navigation will have a certain distance to the viewport (predetermined by navOffset; line 10-13) and when the end of the content div is reached the navigation will align with the bottom of the content (line 18-21). We have to call the code after the page has loaded and when the scroll event is triggered.

Step 4: Jump to a section

Instead of a simple jump via an HTML anchor we’ll use the power of jQuery and scroll smoothly to the anchor.

//navigation click actions	
$('#navfirst').click(function(event) {
	scrollToID('#first', 500);
$('#navsecond').click(function(event) {
	scrollToID('#second', 500);
$('#navthird').click(function(event) {
	scrollToID('#third', 500);
$('#navtop').click(function(event) {
	$('html, body').animate({scrollTop:0}, 'slow'); 		

Here is the helper function for the scrolling:

function scrollToID(id, speed){
	var offSet = 15;
	var targetOffset = $(id).offset().top-offSet;
	$('html,body').animate({scrollTop:targetOffset}, speed);

Step 4: Display current position

The last thing we have to do is displaying the current position. To do this we fade out every section except the one we are currently in and color the section name in the navigation.

var fadeSpeed = 300;
// indicator for current position in the document
if(	(winScroll + navOffset) &lt; secondTop ) {
	// current section = first
	$('#navfirst').css({'color' : '#CC0000'});
	$('#navsecond').css({'color' : '#FFFFFF'});
	$('#navthird').css({'color' : '#FFFFFF'});
	// animate
	$('#navfirst').stop().stop().animate({ opacity: 1.0 }, fadeSpeed);
	$('#navsecond').stop().animate({ opacity: 0.2 }, fadeSpeed);
	$('#navthird').stop().animate({ opacity: 0.2 }, fadeSpeed);
	$('#navtop').stop().animate({ opacity: 0.2 }, fadeSpeed);		
} else if ( (winScroll + navOffset) &lt; thirdTop &amp;&amp; (winScroll &lt;= maxTop) ) {
	// current section = second
	$('#navfirst').css({'color' : '#FFFFFF'});
	$('#navsecond').css({'color' : '#CC0000'});
	$('#navthird').css({'color' : '#FFFFFF'});
	// animate
	$('#navsecond').stop().animate({ opacity: 1.0 }, fadeSpeed);
	$('#navfirst').stop().animate({ opacity: 0.2 }, fadeSpeed);
	$('#navthird').stop().animate({ opacity: 0.2 }, fadeSpeed);
	$('#navtop').stop().animate({ opacity: 0.2 }, fadeSpeed);			
} else {
	// current section = third
	$('#navfirst').css({'color' : '#FFFFFF'});
	$('#navsecond').css({'color' : '#FFFFFF'});
	$('#navthird').css({'color' : '#CC0000'});
	// animate
	$('#navthird').stop().animate({ opacity: 1.0 }, fadeSpeed);
	$('#navsecond').stop().animate({ opacity: 0.2 }, fadeSpeed);			
	$('#navfirst').stop().animate({ opacity: 0.2 }, fadeSpeed);
	$('#navtop').stop().animate({ opacity: 0.2 }, fadeSpeed);				
// current section = last section &amp; if end of page is reached
if ($('body').height() &lt;= ($(window).height() + $(window).scrollTop())) {
	// current section = design
	$('#navfirst').css({'color' : '#FFFFFF'});
	$('#navsecond').css({'color' : '#FFFFFF'});
	$('#navthird').css({'color' : '#CC0000'});
	// animate
	$('#navthird').stop().animate({ opacity: 1.0 }, fadeSpeed);
	$('#navsecond').stop().animate({ opacity: 0.2 }, fadeSpeed);			
	$('#navfirst').stop().animate({ opacity: 0.2 }, fadeSpeed);
	$('#navtop').stop().animate({ opacity: 0.2 }, fadeSpeed);			

Step 5: Final touch

This step is optional but gives the navigation a nice touch. By adding the following code the navigation items will fade in on hover.

var hoverSpeed = 200;
// on hover
$('#navigation a').hover(function(e) {
	$(this).hoverFlow(e.type, { opacity: 1.0 }, hoverSpeed);
}, function(e) {
	if( $(this).hasClass('current') || $('html,body').is(':animated') ) return false;
	$(this).hoverFlow(e.type, { opacity: 0.2 }, hoverSpeed);

Since this would also include the current section we have to filter it. This is done by the current-class, which has to be added and remove when entering or leaving a section. E.g.:



That’s it! If you have any questions or suggestions don’t hesitate to post a comment below.


Liked this? Share it!

Subscribe to the RSS Feed.


  1. Jamie


    Thanks for posting this great article on jQuery fixed navigation. I found it tremendously helpful in building a better and more dynamic page structure. Check out my site to see it in action ‘’.



    May 27, 2011 – Reply

  2. Zach Nicodemous

    This dosent appear to work with internet explorer, the fixed menu position is wrong and the links do not work. Can you fix it?

    July 22, 2011 – Reply

    • Sebastian

      Hi. Jep, the menu doesn’t work in IE. Not quite sure why.

      July 23, 2011 – Reply

    • Sebastian

      Maybe there is someincompatibility with IE and jQuery? :-/ Because that’s the only thing I used.

      July 23, 2011 – Reply

    • Sebastian

      Solved on StackOverflow

      August 4, 2011 – Reply

      • Mellie

        You’ve hit the ball out the park! Incerdbile!

        August 18, 2011 –

  3. Jez

    Great script, i’m having a bit of trouble adapting it to work with the navigation across the top, with a header that content flows behind….

    The fixed navigation is always 15px from the top regardless of where i change position of the #content, any idea how i can manually set that up so its say 200px from the top all the time and changes to an active state when the section gets from 200px from the top also?

    November 30, 2011 – Reply

    • Jez

      Ignore that i’ve figured out how to get it to sit 200px from the top and scroll to that.

      One final problem, when the page first loads and you scroll the navigation doesn’t remain fixed it scrolls with the page, is there anyway to turn this off?

      November 30, 2011 – Reply

      • Sebastian

        Not quite sure what you mean. Can you be more specific? The navigation should always scroll with the page.

        December 1, 2011 –

  4. Luca

    Hi, thank you for your script I found it very useful for one of my projects.
    But I have some problem with the current state of an anchor.

    You found the example here:
    (I used this effect in a fancybox window, but the problem don’t change)
    when I click on second list-element, the current effect goes to the third element and at this point it doesn’t change anymore.

    Please help me :(
    thank you

    December 28, 2011 – Reply

    • Sebastian

      I just took a quick look, but it seems to be a problem with the last if-statement
      ($('body').height() <= ($(window).height() + $(window).scrollTop()))

      The current-class is correclty added to the second navigation link, but gets immediately overridden.

      December 29, 2011 – Reply

      • Luca

        Hi, ok so the problem is there, mmm any solution?
        I’m not really a "pro" in this type of things :D ehehe
        Thank you! :)

        December 29, 2011 –

      • Sebastian

        Maybe take a loot at ScrollSpy :)

        January 2, 2012 –

  5. kyle

    great script. i’m having trouble getting the current nav item to function, though.

    when i start to scroll, the ‘current’ class gets added to the third nav item and never gets removed. any suggestions?

    (note: i’ve used the code directly from the original .js file)

    January 23, 2012 – Reply

  6. Ali

    This is a great tutorial, Sebastian. I was struggling to find a way to change the fixed positioning from always staying in the same location and you provided an excellent solution! Thank you sir ;-)

    February 9, 2012 – Reply

  7. Gaurav Mehra

    Is there any way to make it for more than three nav? Like on some pages i have 4 navigation on the page but on some another page i have more than 6 nav?
    Thanks in advance.

    May 21, 2012 – Reply

    • Sebastian

      Of course. Just add another section.

      May 21, 2012 – Reply

      • Gaurav Mehra

        i mean is there any way to insert a loop instead of setting the values manually… like if we have 4 nav on some page then it adapts itself to be a nav of four or if we have more than that, then it adapt itself for that…

        May 21, 2012 –

      • Gaurav Mehra

        Allright buddy!!! i got exactly what is want… Check out what this website is using and i made it exactly like dat…

        May 21, 2012 –

  8. David

    Thank you ver much, you just saved me a ton of nerves.

    June 18, 2012 – Reply

  9. kenn lau

    I know this is not designed for iphone/ipad, do you have any idea on how to get your demo to work on an iPad or iPhone? Just curious…

    July 1, 2012 – Reply

  10. Tonnetje

    Hi, I am working on a site with a fixed sidebar, but it is not working in all browsers. Is only done with css? As i do not see the javascript. My site, in test mode is not working properly in all browsers.

    October 18, 2012 – Reply

    • Sebastian

      Right now you only can do such a sidebar. In the future there will also be this. There is JavaScript on thirdculturestudios. The file is called jquery.main.js ;)

      October 20, 2012 – Reply

  11. Naveen

    Hi Sebastian,

    Thanks for a great tutorial, which save lot of time of newly designer/developer.


    December 1, 2012 – Reply

  12. Shahid

    Nice work. Useful for Good UI Design. Bookmarked it !

    July 22, 2013 – Reply

Leave a Comment