Downloads

What's it all about?

Headroom.js is a lightweight, high-performance JS widget (with no dependencies!) that allows you to react to the user's scroll. The header on this site is a living example, it slides out of view when scrolling down and slides back in when scrolling up.

Why use it?

Fixed headers are a popular approach for keeping the primary navigation in close proximity to the user. This can reduce the effort required for a user to quickly navigate a site, but they are not without problems…

Large screens are usually landscape-oriented, meaning less vertical than horizontal space. A fixed header can therefore occupy a significant portion of the content area. Small screens are typically used in a portrait orientation. Whilst this results in more vertical space, because of the overall height of the screen a meaningfully-sized header can still be quite imposing.

Headroom.js allows you to bring elements into view when appropriate, and give focus to your content the rest of the time.

How does it work?

At it's most basic headroom.js simply adds and removes CSS classes from an element in response to a scroll event:

<!-- initially -->
<header class="headroom">

<!-- scrolling down -->
<header class="headroom headroom--unpinned">

<!-- scrolling up -->
<header class="headroom headroom--pinned">

Relying on CSS classes affords headroom.js incredible flexibility. The choice of what to do when scrolling up or down is now entirely yours - anything you can do with CSS you can do in response to the user's scroll.

Usage

Using headroom.js is really simple. It has a pure JS API, plus an optional jQuery/Zepto plugin and AngularJS directive.

With plain JS

Include the headroom.js script in your page, and then:

// grab an element
var myElement = document.querySelector("header");
// construct an instance of Headroom, passing the element
var headroom  = new Headroom(myElement);
// initialise
headroom.init(); 

With jQuery/Zepto

Include the headroom.js and jQuery.headroom.js scripts in your page, and then:

// simple as this!
// NOTE: init() is implicitly called with the plugin
$("#header").headroom();

The plugin also offers a data-* API if you prefer a declarative approach.

<!-- selects $("[data-headroom]") -->
<header data-headroom>

Note: Zepto's additional data module is required for compatibility.

With AngularJS

Include the headroom.js and angular.headroom.js scripts in your page and require the headroom module in your AngularJS application module. Then:

<header headroom></header>
<!-- or -->
<headroom></headroom>
<!-- or with options -->
<headroom tolerance='0' offset='0' classes="{pinned:'headroom--pinned',unpinned:'headroom--unpinned',initial:'headroom'}"></headroom>

Options

Headroom.js can also accept an options object to alter the way it behaves. You can see the default options by inspecting Headroom.options. The structure of an options object is as follows:

{
    // vertical offset in px before element is first unpinned
    offset : 0,
    // scroll tolerance in px before state changes
    tolerance : 0,
    // or you can specify tolerance individually for up/down scroll
    tolerance : {
        up : 5,
        down : 0
    },
    // css classes to apply
    classes : {
        // when element is initialised
        initial : "headroom",
        // when scrolling up
        pinned : "headroom--pinned",
        // when scrolling down
        unpinned : "headroom--unpinned",
        // when above offset
        top : "headroom--top",
        // when below offset
        notTop : "headroom--not-top"
    },
    // callback when pinned, `this` is headroom object
    onPin : function() {},
    // callback when unpinned, `this` is headroom object
    onUnpin : function() {},
    // callback when above offset, `this` is headroom object
    onTop : function() {},
    // callback when below offset, `this` is headroom object
    onNotTop : function() {},
}

CSS

Recall that headroom.js works by adding and removing CSS classes in reaction to the user's scroll. This means you will need some CSS to achieve the effect you want. For example, you could hide the header on scroll down, and reveal it again on scroll up. The most basic CSS for this would be:

.headroom--pinned {
    display: block;
}
.headroom--unpinned {
    display: none;
}

Whilst this is functional, it's a bit of a jarring effect. We could do better with some CSS transitions to smoothly move the header in and out of view:

/**
 * Note: I have omitted any vendor-prefixes for clarity.
 * Adding them is left as an exercise for the reader.
 */
.headroom {
    transition: transform 200ms linear;
}
.headroom--pinned {
    transform: translateY(0%);
}
.headroom--unpinned {
    transform: translateY(-100%);
}

Notice that we're transitioning the transform property. The reason to transition this is because transforms are much cheap to animate compared to top, bottom etc. Another benefit is that translation percentage values are relative to the dimensions of the element, whereas top etc. percentage values are relative to the dimensions of the viewport. This means you don't need to know the height of the element in advance, -100% will always slide the element entirely out of view.

The CSS above is enough to get you started, but feel free to try something entirely different. Let you imagination run wild. But not too wild, your users won't appreciate that.

Examples

Head over to the headroom.js playroom if you want see some example uses. There you can tweak all of headroom's options and try out various CSS effects in an interactive demo.

Browser support

Headroom.js is dependent on the following browser APIs:

All of these APIs are capable of being polyfilled, so headroom.js can work with less-capable browsers if desired. Check the linked resources above to determine if you must polyfill to achieve your desired level of browser support.

Changelog

v0.6.0

v0.5.0

v0.4.0

v0.3.11

License

Licensed under the MIT License.

Share this on: