Sticky Header after scrolling down
I saw this sticky header on this website: http://dunked.com/ (no longer active, view archived site)
When you scroll down the sticky header comes down from the top.
I looked at the code, but it looks really complicated. I only understand this: The normal header was cloned with JS and when you scroll down the page it animates from top.
Solution 1:
Here's a start. Basically, we copy the header on load, and then check (using .scrollTop()
or window.scrollY
) to see when the user scrolls beyond a point (e.g. 200pixels). Then we simply toggle a class (in this case .down
) which moves the original into view.
Lastly all we need to do is apply a transition: top 0.2s ease-in
to our clone, so that when it's in the .down
state it slides into view. Dunked does it better, but with a little playing around it's easy to configure
CSS
header {
position: relative;
width: 100%;
height: 60px;
}
header.clone {
position: fixed;
top: -65px;
left: 0;
right: 0;
z-index: 999;
transition: 0.2s top cubic-bezier(.3,.73,.3,.74);
}
body.down header.clone {
top: 0;
}
either Vanilla JS (polyfill as required)
var sticky = {
sticky_after: 200,
init: function() {
this.header = document.getElementsByTagName("header")[0];
this.clone = this.header.cloneNode(true);
this.clone.classList.add("clone");
this.header.insertBefore(this.clone);
this.scroll();
this.events();
},
scroll: function() {
if(window.scrollY > this.sticky_after) {
document.body.classList.add("down");
}
else {
document.body.classList.remove("down");
}
},
events: function() {
window.addEventListener("scroll", this.scroll.bind(this));
}
};
document.addEventListener("DOMContentLoaded", sticky.init.bind(sticky));
or jQuery
$(document).ready(function() {
var $header = $("header"),
$clone = $header.before($header.clone().addClass("clone"));
$(window).on("scroll", function() {
var fromTop = $("body").scrollTop();
$('body').toggleClass("down", (fromTop > 200));
});
});
Newer Reflections
Whilst the above answers the OP's original question of "How does Dunked achieve this effect?", I wouldn't recommend this approach. For starters, copying the entire top navigation could be pretty costly, and there's no real reason why we can't use the original (with a little bit of work).
Furthermore, Paul Irish and others, have written about how animating with translate()
is better than animating with top
. Not only is it more performant, but it also means that you don't need to know the exact height of your element. The above solution would be modified with the following (See JSFiddle):
header.clone {
position: fixed;
top: 0;
left: 0;
right: 0;
transform: translateY(-100%);
transition: 0.2s transform cubic-bezier(.3,.73,.3,.74);
}
body.down header.clone {
transform: translateY(0);
}
The only drawback with using transforms is, that whilst browser support is pretty good, you'll probably want to add vendor prefixed versions to maximize compatibility.
Solution 2:
Here is a JS fiddle http://jsfiddle.net/ke9kW/1/
As the others say, set the header to fixed, and start it with display: none
then jQuery
$(window).scroll(function () {
if ( $(this).scrollTop() > 200 && !$('header').hasClass('open') ) {
$('header').addClass('open');
$('header').slideDown();
} else if ( $(this).scrollTop() <= 200 ) {
$('header').removeClass('open');
$('header').slideUp();
}
});
where 200 is the height in pixels you'd like it to move down at. The addition of the open class is to allow us to run an elseif instead of just else, so some of the code doesn't unnecessarily run on every scrollevent, save a lil bit of memory