Home > CSS, Front End Development, How to, HTML, Javascript > Triggering Navigation with Scrolling in JQuery

Triggering Navigation with Scrolling in JQuery

January 24th, 2012


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.

Navigation Trigger Scrolling

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>



Top