Sticky Header after scrolling down
Asked Answered
D

13

30

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.

Dekow answered 22/8, 2013 at 13:54 Comment(3)
Sorry, here is the link: jsfiddle.net/XyVAGDekow
@jibsales updated to include vanilla JS solution :)Gader
This is my simple article helps you to create it. kvcodes.com/2017/03/jquery-simple-sticky-header-on-scrollDrambuie
G
62

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.

Gader answered 22/8, 2013 at 14:7 Comment(4)
In Firefox it works good but in chrome not. But thank you - it helped me a lot.Dekow
@user2416687 Ah, looks like some quirk of having a Fiddle use an iFrame - I've changed to use window (see this question)Gader
Oh, and - anytime, I tried to break it down to explain what was going on :)Gader
use "position: sticky; top: 0;" done. Set top property as desired. this answer needs an update FYIPomerleau
M
12

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

Monkery answered 22/8, 2013 at 14:4 Comment(1)
Ah, I can see that the same header is re-used on the example, this works for one header inline and one for drop down (handy if you wanted a simpler,smaller strip after scroll) but you get the idea!Monkery
S
2

Here's is quite a list of jQuery plugins that will help achieve similar effect: http://jquery-plugins.net/tag/sticky-scroll

Salyers answered 21/8, 2014 at 13:18 Comment(1)
scrollToFixed() is a really good one in that list. does exactly waht I want. a header that stays in place untill I scroll past it them its stuck to the top of the page. very useful!Licko
L
1

I used jQuery .scroll() function to track the event of the toolbar scroll value using scrollTop. I then used a conditional to determine if it was greater than the value on what I wanted to replace. In the below example it was "Results". If the value was true then the results-label added a class 'fixedSimilarLabel' and the new styles were then taken into account.

    $('.toolbar').scroll(function (e) {
//console.info(e.currentTarget.scrollTop);
    if (e.currentTarget.scrollTop >= 130) {
        $('.results-label').addClass('fixedSimilarLabel');
    }
    else {      
        $('.results-label').removeClass('fixedSimilarLabel');
    }
});

http://codepen.io/franklynroth/pen/pjEzeK

Lollapalooza answered 25/9, 2015 at 16:12 Comment(0)
G
1

css:

header.sticky {
  font-size: 24px;
  line-height: 48px;
  height: 48px;
  background: #efc47D;
  text-align: left;
  padding-left: 20px;
}

JS:

$(window).scroll(function() {
 if ($(this).scrollTop() > 100){  
    $('header').addClass("sticky");
  }
  else{
    $('header').removeClass("sticky");
  }
});
Gainsay answered 2/3, 2016 at 11:20 Comment(1)
I believe you meant 'fixed', because that is not how sticky works.Castanets
A
1

I suggest to use sticky js it's have best option ever i have seen. nothing to do just ad this js on you

 https://raw.githubusercontent.com/garand/sticky/master/jquery.sticky.js

and use below code :

<script>
  $(document).ready(function(){
    $("#sticker").sticky({topSpacing:0});
  });
</script>

Its git repo: https://github.com/garand/sticky

Amylopectin answered 28/3, 2017 at 10:5 Comment(0)
N
1

Here's a simple solution without jQuery only Vanilla JS.

In the example, we just use "header" class that you can change to anything else you want. Basically, it makes a clone of the existing header and shows it down below as a fixed header.

The solution is fast since the animation is done with CSS transitions and no additional JS animation overhead.

You can tweak the animation styles to have your own transition. Animation "slidein" is used for showing the fixed header on scroll down, and "slideout" when you want it to disappear when you scroll up to the top.

(function() {

  //CONFIGURATION
  var headerClassName = 'header'; //Class of your header element
  var stickyAfter = 150; //Show fixed header after this Y offset in px
  
  var header = document.getElementsByClassName(headerClassName)[0];
  var clone = header.cloneNode(true); 
  clone.classList.add('clone'); 
  header.parentElement.appendChild(clone);
  
  var initializeHeader = function() {
    document
    .getElementsByClassName(headerClassName + ' clone')[0]
    .classList.add('initialized');
    return true;
  }
  
  window.onscroll = function() {
    var cl = document.body.classList;
    window.pageYOffset > stickyAfter ? 
      initializeHeader() && cl.add('sticky') : 
      cl.remove('sticky');
  } 

})();
/* GENERAL STYLES */
body {
  min-height: 2000px;
}
.header {
  background: green;
  padding: 7px 20px;
  color: #fff;
  position: relative;
  min-width: 100%;
}

/* STICKY HEADER STYLES */
@keyframes slidein {
  from {
    position: fixed;
    top: -50px;
    opacity: 0;
  }
  to {
    position: fixed;
    top: 0;
    opacity: 1;
  }
}
@keyframes slideout {
  from {
    position: fixed;
    top: 0;
    opacity: 1;
  }
  to {
    position: fixed;
    top: -50px;
    opacity: 0;
  }
}
.header.clone.initialized {
  -webkit-animation: slideout .3s forwards; /* for less modern browsers */
   animation: slideout .3s forwards;
}
body.sticky .header.clone {
  -webkit-animation: slidein .3s forwards; /* for less modern browsers */
   animation: slidein .3s forwards;
}
<div class="header">
  <p>This is demo header</p>
</div>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc mollis augue vel massa dictum gravida. Ut vitae elit ligula. In vitae sagittis lacus. Curabitur vel magna eget mauris vestibulum vestibulum id eget dui. Morbi tempus laoreet gravida. Curabitur vel volutpat lacus. Morbi dictum iaculis nibh. Praesent cursus tempor placerat. Sed posuere dui et diam elementum luctus. Nulla aliquet vestibulum justo.</p>

<p>Integer cursus tellus nec sodales lobortis. Donec dictum pharetra ligula, at lobortis lorem pellentesque non. Nullam volutpat nisi id laoreet condimentum. Morbi vel erat vitae elit sodales iaculis ac ut libero. Cras eget neque at libero feugiat interdum. Praesent eget erat mauris. Maecenas convallis aliquet risus non tempus.</p>

<p>Sed convallis elit a dignissim vestibulum. Quisque pharetra, leo eu eleifend pretium, dolor enim viverra elit, quis aliquet dui lacus sit amet dolor. Quisque sit amet sapien tellus. Nam tristique placerat dui, placerat fringilla magna varius nec. Ut id arcu metus. Aenean eu mollis massa. Vestibulum cursus egestas turpis, a tempor metus mattis eu. Donec fringilla quam non fermentum fringilla.</p>

<p>Nam et lorem leo. Donec libero tortor, laoreet quis maximus at, faucibus fermentum ligula. Curabitur facilisis quam in posuere suscipit. Ut sagittis mauris ullamcorper, feugiat sem sed, egestas lorem. Curabitur ut urna laoreet, commodo dolor id, blandit arcu. Aliquam vitae odio magna. Curabitur eu mi dolor. Praesent tellus lectus, mattis eu nunc ac, sagittis tincidunt nulla.</p>

<p>Morbi augue erat, consectetur non pulvinar et, auctor id mi. Vestibulum a ornare diam, nec dignissim neque. Aliquam sodales orci vitae lorem rhoncus, cursus fermentum nisl hendrerit. Aliquam erat volutpat. Mauris fermentum cursus arcu, in imperdiet lacus ultrices ut. Vivamus ligula nulla, mollis a consequat id, varius sed odio. Proin sed fringilla nunc, at dignissim ipsum. Etiam dictum tortor turpis, ac ornare purus semper non. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec a urna vitae metus vestibulum tincidunt sed gravida metus. Vivamus auctor sed leo eget lacinia. Nulla quis bibendum erat. Nunc dapibus lobortis odio, vel porttitor dui elementum at. Ut neque libero, rutrum vel cursus id, rhoncus vitae felis.</p>
Nickienicklaus answered 30/7, 2021 at 9:36 Comment(0)
B
0

a similar solution using jquery would be:

$(window).scroll(function () {
  $('.header').css('position','fixed');
});

This turns the header into a fixed position element immediately on scroll

Bean answered 22/8, 2013 at 13:59 Comment(0)
M
0

Add debouncing, for efficiency http://davidwalsh.name/javascript-debounce-function

Musket answered 19/3, 2014 at 21:59 Comment(2)
This really ought to be a comment and not a valid answer by any stretch.Demott
Fair - but the debounce is relevant to best practice when solving the issue. +1 from meCoadjutress
P
0

This was not working for me in Firefox.

We added a conditional based on whether the code places the overflow at the html level. See Animate scrollTop not working in firefox.

  var $header = $("#header #menu-wrap-left"),
  $clone = $header.before($header.clone().addClass("clone"));

  $(window).on("scroll", function() {
    var fromTop = Array(); 
    fromTop["body"] = $("body").scrollTop();
    fromTop["html"] = $("body,html").scrollTop();

if (fromTop["body"]) 
    $('body').toggleClass("down", (fromTop["body"] > 650));

if (fromTop["html"]) 
    $('body,html').toggleClass("down", (fromTop["html"] > 650));

  });
Phyte answered 6/9, 2016 at 20:54 Comment(0)
K
0

window bottom scroll to top scroll using jquery.

 <script> 

 var lastScroll = 0;

 $(document).ready(function($) {

 $(window).scroll(function(){

 setTimeout(function() { 
    var scroll = $(window).scrollTop();
    if (scroll > lastScroll) {

        $("header").removeClass("menu-sticky");

    } 
    if (scroll == 0) {
    $("header").removeClass("menu-sticky");

    }
    else if (scroll < lastScroll - 5) {


        $("header").addClass("menu-sticky");

    }
    lastScroll = scroll;
    },0);
    });
   });
 </script>
Kozlowski answered 11/7, 2017 at 12:25 Comment(0)
A
0

In Modern javascript it will be better to use observers to acheive the same.

CSS

sticky{
  position: fixed;
  top: 0;
}

JS

const header = document.querySelector(".js-header");

function markSticky() {
  categoriesNav.classList.add('sticky')
}

function markUnsticky() {
  categoriesNav.classList.remove('sticky')
}

const observer = new IntersectionObserver(function (entries) {
  entries.forEach(function (entry) {
    if (entry.isIntersecting) {
      markUnsticky()
    } else {
      markSticky()
    }
  })
})
Anisometric answered 13/9, 2022 at 13:2 Comment(0)
B
0

Here is my working code example. It's also eliminated jerking of sticky header!!

<script>
    window.onscroll = function() {
        showDesktopMenu()
    };

    function showDesktopMenu() {
        let header = document.querySelector('#header'); //main header div
        let navbar = document.querySelector('.desktop-navbar'); // child div of main header div
        let body = document.querySelector('body'); // document body
        if (window.pageYOffset > header.getBoundingClientRect().height) {
            navbar.classList.add('sticky-custom');
            body.style['padding-top'] = navbar.getBoundingClientRect().height + "px";
        } else {
            body.style['padding-top'] = "0px";
            navbar.classList.remove('sticky-custom');
        }
    }
</script>
<style>
    .sticky-custom {
        position: fixed;
        z-index: 9999;
        width: 100%;
        top: 0;
    }
</style>
Beghard answered 25/8, 2023 at 6:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.