Triggering Navigation with Scrolling in JQuery
Scrolling as your sites main source of navigation is all the rage. With the amount of one page sites out there I thought it would be helpful to show how to trigger your navigation to changed based on how far you’ve scrolled down.
What we’re building
We’ll be creating a simple 1 page site. Actually we’ll just be stealing the code from the previous post on Smooth Scrolling in Jquery, and adding in the navigation triggering bits.
Steal the Previous Code
We’re just going to steal the HTML and CSS from the previous post Smooth Scrolling in Jquery. There is nothing special, it’s just a navigation and a bunch of sections with a header and some text in them. The headers have unique ids so we can reference them with the jQuery. We’re more or less going to get rid of the jQuery and start a new.
Here is what we’re starting off with:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | <!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Smooth Scrolling</title> <style type="text/css"> .container{ width:300px; margin:0 auto; } .section{ margin-top:60px; } .navigation{ position: fixed; background:white; padding:20px 20px; width:100%; margin-top:0px; top:0px; } </style> </head> <body> <div class="container"> <div class="navigation"> <a href="#html">HTML</a> <a href="#javascript">JavaScript</a> <a href="#jquery">jQuery</a> <a href="#php">PHP</a> <a href="#css">CSS</a> </div> <div class="section"> <h1 id="html">HTML</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="javascript">JavaScript</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="jquery">jQuery</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="php">PHP</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="css">CSS</h1> <p><!--Your HTML Content Goes HERE --></p> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script> <script> // JavaScript Will go Here </script> </body> </html> |
The New CSS
In new found code aquired by a five finger discount needs some styling. Right now the navigation is plain and you can’t tell when an item is selected so we’re just going to add an .active class and perhaps beautify the list a bit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /* Regular state of naviation */ a:link, a:hover, a:visited{ text-decoration:none; color: #000; padding:3px; } /* Active state of navigation */ .active:link, .active:hover, .active:visited { color: #fff; background: #000060; } /* Make the font of the list a little nicer to look at. */ *{ font-family: sans-serif; color: #666; } |
The JQuery
The first thing we need to know is how far each section is from the top. So we’re going to write a function that we can pass in a navigation item and it will tell us how far that section is from the top. Because we have our navigation at the top, we’ll have to make sure that the section triggers the change just before it reaches the navigation. We’ll just subtract the height of the nav from the distance from the top.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //Get Sections top position function getTargetTop(elem){ //gets the id of the section header //from the navigation's href e.g. ("#html") var id = elem.attr("href"); //Height of the navigation var offset = 60; //Gets the distance from the top and //subtracts the height of the nav. return $(id).offset().top - offset; } |
Now that we can pull where each section is, we can now setup our navigation to scroll to a section when clicked.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //Smooth scroll when user click link that starts with # $('a[href^="#"]').click(function(event) { //gets the distance from the top of the //section refenced in the href. var target = getTargetTop($(this)); //scrolls to that section. $('html, body').animate({scrollTop:target}, 500); //prevent the browser from jumping down to section. event.preventDefault(); }); |
That takes care of the nav, but now comes the meat and potatoes. The scrolling now has to trigger the navigation to change. We’ll create a function that goes through every section and sees if it’s at the top yet. It’ll except 1 parameter which specifies how far the user has scrolled.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //Pulling sections from main nav. var sections = $('a[href^="#"]'); // Go through each section to see if it's at the top. // if it is add an active class function checkSectionSelected(scrolledTo){ //How close the top has to be to the section. var threshold = 100; var i; for (i = 0; i < sections.length; i++) { //get next nav item var section = $(sections[i]); //get the distance from top var target = getTargetTop(section); //Check if section is at the top of the page. if (scrolledTo > target - threshold && scrolledTo < target + threshold) { //remove all selected elements sections.removeClass("active"); //add current selected element. section.addClass("active"); } }; } |
The last thing we need to do is call the function when someone scrolls and when the page is first loaded.
1 2 3 4 5 6 | //Check if page is already scrolled to a section. checkSectionSelected($(window).scrollTop()); $(window).scroll(function(e){ checkSectionSelected($(window).scrollTop()) }); |
That’s it!
Now you have yourself a pretty sweet scrolling site. You can also use this same principle to animate items on your page. Too fun.
Here is all the code all together:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | <!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Smooth Scrolling</title> <style type="text/css"> .container{ width:300px; margin:0 auto; } .section{ margin-top:60px; } .navigation{ position: fixed; background:white; padding:20px 20px; width:100%; margin-top:0px; top:0px; } a:link, a:hover, a:visited{ text-decoration:none; color: #000; padding:3px; } .active:link, .active:hover, .active:visited { color: #fff; background: #000060; } *{ font-family: sans-serif; color: #666; } </style> </head> <body> <div class="container"> <div class="navigation"> <a href="#html">HTML</a> <a href="#javascript">JavaScript</a> <a href="#jquery">jQuery</a> <a href="#php">PHP</a> <a href="#css">CSS</a> </div> <div class="section"> <h1 id="html">HTML</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="javascript">JavaScript</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="jquery">jQuery</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="php">PHP</h1> <p><!--Your HTML Content Goes HERE --></p> </div> <div class="section"> <h1 id="css">CSS</h1> <p><!--Your HTML Content Goes HERE --></p> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script> <script> $(document).ready(function() { //Get Sections top position function getTargetTop(elem){ //gets the id of the section header //from the navigation's href e.g. ("#html") var id = elem.attr("href"); //Height of the navigation var offset = 60; //Gets the distance from the top and //subtracts the height of the nav. return $(id).offset().top - offset; } //Smooth scroll when user click link that starts with # $('a[href^="#"]').click(function(event) { //gets the distance from the top of the //section refenced in the href. var target = getTargetTop($(this)); //scrolls to that section. $('html, body').animate({scrollTop:target}, 500); //prevent the browser from jumping down to section. event.preventDefault(); }); //Pulling sections from main nav. var sections = $('a[href^="#"]'); // Go through each section to see if it's at the top. // if it is add an active class function checkSectionSelected(scrolledTo){ //How close the top has to be to the section. var threshold = 100; var i; for (i = 0; i < sections.length; i++) { //get next nav item var section = $(sections[i]); //get the distance from top var target = getTargetTop(section); //Check if section is at the top of the page. if (scrolledTo > target - threshold && scrolledTo < target + threshold) { //remove all selected elements sections.removeClass("active"); //add current selected element. section.addClass("active"); } }; } //Check if page is already scrolled to a section. checkSectionSelected($(window).scrollTop()); $(window).scroll(function(e){ checkSectionSelected($(window).scrollTop()) }); }); </script> </body> </html> |

