How to fix the navigation bar to the top when it reaches the position


CSS JavaScript jQuery

In this very quick tutorial I'll explain you how to easily let any item stick to the top of the page when it reaches the final position, using a simple CSS class and a very little bit of JavaScript.

There isn't much tech behind this solution. One may think about doing it JavaScript only - but whenever possible, don't! CSS is way faster than JS, because it's rendered directly by the browser, rather than interacting with the DOM.


Attention: this work is under the Creative Commons Attribution 3.0 Unported licence


CodePen live demo (CSS is written in SCSS)


So, let's go!

First of all, define our stage: we've got an element which stays somewhere in the DOM (for example, in position absolute / bottom: 0, so that it initially stays at the bottom of the page) and we want to let this element (typically a menu bar) keep visible, but staying at the top of the browser's window. You can style it as you wish, it doesn't really matter. This is my personal setup:

:::css
nav#menu {
    position: absolute;
    bottom: 0px;
    display: block;
    width: 100%;
    text-transform: uppercase;
    padding: 5px 10px;
    box-sizing: border-box;
    background-color: rgba(0, 0, 0, 0.65);
    color: white;
}

Now let's define the class which will be enabled when we'll have to fix the position of our navigation bar:

:::css
nav#menu.fixed {
    position: fixed;
    top: 0px;
    bottom: auto;
}

Position fixed will let the element stay wherever you want. Top: 0px will let the element stay at the top of the window. Bottom: auto is optional (though obligatory in this example): I've previously set it to 0px, so I have to overwrite it in order to restore its default value.

Now let's see the really simple JavaScript part (I've used jQuery, you can use ZeptoJS or pure JS if you want):

:::javascript
(function ($) {
    "use strict";

    var menuPosition = function () {
        var nav = $("nav#menu"),
            height = nav.height(),
            windowHeight = $(window).height();

        if ($(window).scrollTop() > (windowHeight - height)) {
            nav.addClass('fixed');
        } else {
            nav.removeClass('fixed');
        }
    };

    menuPosition();
    $(document).scroll(menuPosition);
}(jQuery));

First of all: I've used an anonymous function, which helps preventing the global scope to get dirty.

I've defined a function which gets the navigation bar's height and the window's one. I'm getting these information within the function because the user may resize the viewport (i.e. mobile portrait/landscape).

Then I check whether the window's scroll from the top is higher than the total window's height less the height of the window itself and, in case, I append the 'fixed' class to the navigation element. Otherwise I take it away.

Eventually I call the method once (i.e. for people going in your website pointing to an anchor below the start of the page) and bind the very same to the scroll event.

Easy enought! If you don't want to initially put the menu at the bottom of the screen, but somewhere else, you have to save the navigation bar's offset outside the function, otherwise it won't work (as it would be continuously updated, and you don't want it!).

There are no cons, really, with this method (but obviously browsers not supporting javascript!). The big pro is that the browser will render this effect very smoothly.

If you want to use plugins like scrollTo to go from a section to another, I'd suggest to add to the sections a padding-top equal or similar to the height of the navigation bar. In the first case, you'll have to set the nav bar's height manually via CSS, or set the sections' padding-top via JavaScript (hint: onResize). In the second case, you'll have to guess (and eventually adjust via media queries) the proper padding manually, but using only CSS.

That's it! I really hope you've enjoyed this simple tutorial!

- 22nd September 2014

> back