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> </ul> </div> <div id="content"> <div class="section" id="first"> <!-- content goes here --> </div> <div class="section" id="second"> <!-- content goes here --> </div> <div class="section" id="third"> <!-- content goes here --> </div> </div> </div>
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 > minTop && currentScroll < maxTop ) {
// while scrolling though the content
$('#navigation').css({'top' : navOffset+'px'});
}
if( currentScroll <= minTop ) {
// adjust navigation top to content top
$('#navigation').css({'top' : minTop-currentScroll});
}
if( currentScroll >= 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) {
event.preventDefault();
scrollToID('#first', 500);
});
$('#navsecond').click(function(event) {
event.preventDefault();
scrollToID('#second', 500);
});
$('#navthird').click(function(event) {
event.preventDefault();
scrollToID('#third', 500);
});
$('#navtop').click(function(event) {
event.preventDefault();
$('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) < 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) < thirdTop && (winScroll <= 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 & if end of page is reached
if ($('body').height() <= ($(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.:
$('#navfirst').addClass('current');
$('#navsecond').removeClass('current');
$('#navthird').removeClass('current');
Conclusion
That’s it! If you have any questions or suggestions don’t hesitate to post a comment below.
Greetings,
Hey.
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 ‘www.100cupcakes.com/programs’.
Cheers,
Jamie.
May 27, 2011 –
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 –
Hi. Jep, the menu doesn’t work in IE. Not quite sure why.
July 23, 2011 –
Maybe there is someincompatibility with IE and jQuery? :-/ Because that’s the only thing I used.
July 23, 2011 –
Solved on StackOverflow
August 4, 2011 –
You’ve hit the ball out the park! Incerdbile!
August 18, 2011 –
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 –
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 –
Not quite sure what you mean. Can you be more specific? The navigation should always scroll with the page.
December 1, 2011 –
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:
http://www.veneziahotels.biz/nuovo/extra/guide-libri/
(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 –
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 –
Hi, ok so the problem is there, mmm any solution?
ehehe
I’m not really a "pro" in this type of things
Thank you!
December 29, 2011 –
Maybe take a loot at ScrollSpy
January 2, 2012 –
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 –
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 –
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 –
Of course. Just add another section.
May 21, 2012 –
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 –
Allright buddy!!! i got exactly what is want… Check out what this website is using and i made it exactly like dat… http://www.thirdculturestudios.com/
May 21, 2012 –
Thank you ver much, you just saved me a ton of nerves.
June 18, 2012 –
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 –
Hi, I am working on a site with a fixed sidebar, but it is not working in all browsers. Is http://www.thirdculturestudios.com/ only done with css? As i do not see the javascript. My site, in test mode http://www.toporange.com/farnaz is not working properly in all browsers.
October 18, 2012 –
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 –
Hi Sebastian,
Thanks for a great tutorial, which save lot of time of newly designer/developer.
Naveen
December 1, 2012 –