Hide header on scroll down, show on scroll up

Make your content shine by getting out of the way

When was the last time you looked at a website’s menu and thought “gosh, that is just so pretty.” Unless you’re a designer, chances are it’s never. People don’t visit your website to admire the UI. They go there for the content. They go there to get shit done.

“Good design is as little design as possible.”
Dieter Rams

Fixed headers are fairly common nowadays with big name brands like Facebook, Twitter, Google, LinkedIn, and others using this pattern. It’s easy to carelessly copy them without any thought to improving on the pattern, but perhaps we should rethink that.

More and more people are using mobile phones where screen real estate is a commodity. Even on desktops and tablets applications that get out of the way and let users focus on content feel better. There’s more room to breathe; your eyes don’t feel like squinting.

How can we improve on the fixed header pattern? Here’s a proposal: hide the header as the user scrolls down, and show it again when the user scrolls up. This is not revolutionary. Other apps and websites are already doing this, and it’s pretty sweet. Here’s how you do it.


We’re going to achieve this effect using CSS3 transitions and just a tad of JavaScript. The basic idea is this:

1. set the header to position fixed
2. on scroll down, add a class to move the header up
3. on scroll up, remove the class to show the header again

The HTML

<header></header>
<main></main>
<footer></footer>

The CSS

body {
padding-top: 40px; // same as header height
}
header {
background: #f5b335;
height: 40px;
position: fixed;
top: 0;
transition: top 0.2s ease-in-out;
width: 100%;
}
// we'll add this class using javascript
.nav-up {
top: -40px; // same as header height. use variables in LESS/SASS
}

The JavaScript

Make sure you have jQuery loaded.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

Let’s start off by saying that attaching functions to scroll events can be very expensive to performance. We’ll remedy this by checking if the user has scrolled on an interval instead of executing functions for every pixel scrolled.

var didScroll;
// on scroll, let the interval function know the user has scrolled
$(window).scroll(function(event){
didScroll = true;
});
// run hasScrolled() and reset didScroll status
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
// do stuff here...
}

On $(window).scroll, all we do is set the variable didScroll to true. The interval checks every 250ms if didScroll has changed. If it has, it runs the function and resets didScroll to false. It’s much easier for the browser to set a boolean variable than to run through a whole set of functions for every pixel scrolled.

Hiding the header

To hide the header, we’ll determine the following:

1. if they scrolled more than delta
2. if they scrolled past the header height
3. if they scrolled up or down
4. store the current scroll position in a variable

Define Your Variables

Let’s start out by defining all variables at the top.

var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $(‘header’).outerHeight();

hasScrolled()

Inside hasScrolled(), store the scroll position in a variable for easy access.

 var st = $(this).scrollTop();

Check if they scrolled more than delta.

if (Math.abs(lastScrollTop — st) <= delta)
return;

Check if they scrolled past the header and if they scrolled up or down.

// If current position > last position AND scrolled past navbar...
if (st > lastScrollTop && st > navbarHeight){
  // Scroll Down
$(‘header’).removeClass(‘nav-down’).addClass(‘nav-up’);
} else {
  // Scroll Up
// If did not scroll past the document (possible on mac)...
  if(st + $(window).height() < $(document).height()) { 
$(‘header’).removeClass(‘nav-up’).addClass(‘nav-down’);
}
}

Set lastScrollTop to the current position.

lastScrollTop = st;

That’s it. It’s as simple as that. Try it and let me know what you think.

Demo

Here’s a jsFiddle of the whole thing.

http://jsfiddle.net/mariusc23/s6mLJ/31/