Detachable navigation using JavaScript

The navigation bar and sidebars on this site appear static at first, but as you scroll down they detach from the page and scroll with you. Keeping the navigation in view in this way makes your site more user-friendly. This page explains how to achieve this effect with just a few lines of CSS and JavaScript.

In the HTML

The code on this page assumes that your navigation is inside an element with the ID ‘navigation’ — for example:

 1
 2
 3
<div id="navigation">
  <!-- your navigation code -->
</div>

In the stylesheet

Add the following rules to your stylesheet, changing the values on lines 3, 4, and 9 as appropriate for your design:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#navigation{
  position:absolute;
  top:120px;
  left:0;
}

#navigation.fixed{
  position:fixed;
  top:16px;
}

The first block applies when the navigation is in its docked state, and positions it absolutely at the location specified on lines 3 and 4. Absolute positioning is used so that the layout of the rest of the page doesn’t change when the navigation is detached. The second block applies when the navigation is in its undocked state, and positions it at a fixed location relative to the window (in other words, it no longer scrolls with the page), at the distance from the top specified on line 9.

In the JavaScript

Add the following code to your JavaScript, changing the number on line 16 as appropriate for your design:

 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
/* Handles the page being scrolled by ensuring the navigation is always in
 * view.
 */
function handleScroll(){

  // check that this is a relatively modern browser
  if (window.XMLHttpRequest){

    // determine the distance scrolled down the page
    var offset = window.pageYOffset
               ? window.pageYOffset
               : document.documentElement.scrollTop;

    // set the appropriate class on the navigation
    document.getElementById('navigation').className =
        (offset > 104 ? 'fixed' : '');

  }

}

// add the scroll event listener
if (window.addEventListener){
  window.addEventListener('scroll', handleScroll, false);
}else{
  window.attachEvent('onscroll', handleScroll);
}

The number on line 16 determines the distance down the page at which the navigation undocks. In order for the navigation not to jump as it detaches, the value should be equal to the difference between the values specified in the stylesheet. For example, if the navigation usually resides 120 pixels from the top of the page and is displayed 16 pixels from the top of the window when it undocks, this transition should occur when the page has been scrolled by 104 pixels.

Note that older browsers do not support the value ‘fixed’ for the CSS property ‘position’, so the JavaScript code uses the presence or absence of window.XMLHttpRequest as a way of distinguishing between older and newer browsers.

Other considerations

If you link to locations within pages using anchors and fragments (for example, an element with the ID ‘anchor’ and a link pointing to #anchor), the navigation may end up partially covering the element to which you linked. To work around this, you can use negative margins and padding to make the browser think the element is further up the page than it appears to visitors. For example, style rules equivalent to the following are applied to headings on this site:

 1
 2
 3
 4
h2{
  margin-top:-64px;
  padding-top:64px;
}

Here 64 pixels is the distance of the base of the navigation from the top of the window. While the heading appears exactly the same to visitors as it would without the rules, the rules make the browser scroll down 64 pixels less far, thereby ensuring that the heading remains visible.

Where now?

Found this useful? Share it:

Recommended reading:

Professional JavaScript for Web Developers by Nicholas C. Zakas

Also in JavaScript: