75

I wonder how to make a sticky header shrink(with animation) when you scroll down the page and goes back to normal state when the page is scrolled up to the top. Here are two examples to clearify:

http://themenectar.com/demo/salient/

http://www.kriesi.at/themes/enfold/

I get the part to make it fixed, but how should I do to shrink my header when the user scrolls down?

Thanks a ton

user2362529
  • 755
  • 1
  • 6
  • 7

6 Answers6

107

This should be what you are looking for using jQuery.

$(function(){
  $('#header_nav').data('size','big');
});

$(window).scroll(function(){
  if($(document).scrollTop() > 0)
{
    if($('#header_nav').data('size') == 'big')
    {
        $('#header_nav').data('size','small');
        $('#header_nav').stop().animate({
            height:'40px'
        },600);
    }
}
else
  {
    if($('#header_nav').data('size') == 'small')
      {
        $('#header_nav').data('size','big');
        $('#header_nav').stop().animate({
            height:'100px'
        },600);
      }  
  }
});

Demonstration: http://jsfiddle.net/jezzipin/JJ8Jc/

jezzipin
  • 4,110
  • 14
  • 50
  • 94
  • Your solution is almost perfect, but I wanted to addClass() instead of adjusting the height BUT without losing the animation. Possible? – eozzy Jul 23 '13 at 19:34
  • 1
    Does anyone knows why this works every browser except Safari for iOS? cc @jezzipin – Programmeur Apr 08 '14 at 04:53
  • 4
    I'm afraid I'm not sure. Now that Safari is only available on the Mac I do not have the capacity to test this on Safari (as I hate Macs and avoid them at all costs) so I'm afraid I won't be able to come up with a solution for you. – jezzipin Apr 08 '14 at 13:14
  • It would be more efficient to just add/remove a class and do the size transition with a CSS transformation. – Teetrinker Mar 20 '15 at 13:23
  • 1
    As I mention below on Sinky's answer, using CSS limits your browser support meaning that the effect will not occur on IE8 and IE9. If you want full browser support then you will need to use this method over CSS. – jezzipin Mar 23 '15 at 13:05
88

Here a CSS animation fork of jezzipin's Solution, to seperate code from styling.

JS:

$(window).on("scroll touchmove", function () {
  $('#header_nav').toggleClass('tiny', $(document).scrollTop() > 0);
});

CSS:

.header {
  width:100%;
  height:100px;
  background: #26b;
  color: #fff;
  position:fixed;
  top:0;
  left:0;
  transition: height 500ms, background 500ms;
}
.header.tiny {
  height:40px;
  background: #aaa;
}

http://jsfiddle.net/sinky/S8Fnq/

On scroll/touchmove the css class "tiny" is set to "#header_nav" if "$(document).scrollTop()" is greater than 0.

CSS transition attribute animates the "height" and "background" attribute nicely.

Sinky
  • 1,059
  • 7
  • 13
  • Nice work. Bare in mind that for user of IE9 and IE8 the transition will not kick in as this property is unsupported in these browsers. Apart from that, it's a great solution as it good for anyone wanting to cut down the amount of dom manipulation in their code. http://caniuse.com/#search=transition – jezzipin Dec 04 '13 at 14:29
  • 6
    @Sinky You could do the class toggle in one line `$('#header_nav').toggleClass('tiny', $(document).scrollTop() > 0);` – Eric Jan 13 '14 at 20:14
  • 2
    Should be the accepted answer. By far the cleanest solution. – Jeffrey Roosendaal Oct 11 '16 at 08:42
  • 2
    A bit old, but one should add a `$(window).trigger("scroll")` if page is not displayed at top initially. – rabudde May 11 '18 at 19:40
5

http://callmenick.com/2014/02/18/create-an-animated-resizing-header-on-scroll/

This link has a great tutorial with source code that you can play with, showing how to make elements within the header smaller as well as the header itself.

lg365
  • 493
  • 8
  • 11
3

Based on twitter scroll trouble (http://ejohn.org/blog/learning-from-twitter/).

Here is my solution, throttling the js scroll event (usefull for mobile devices)

JS:

$(function() {
    var $document, didScroll, offset;
    offset = $('.menu').position().top;
    $document = $(document);
    didScroll = false;
    $(window).on('scroll touchmove', function() {
      return didScroll = true;
    });
    return setInterval(function() {
      if (didScroll) {
        $('.menu').toggleClass('fixed', $document.scrollTop() > offset);
        return didScroll = false;
      }
    }, 250);
  });

CSS:

.menu {
  background: pink;
  top: 5px;
}

.fixed {
  width: 100%;
  position: fixed;
  top: 0;
}

HTML:

<div class="menu">MENU FIXED ON TOP</div>

http://codepen.io/anon/pen/BgqHw

Luc Boissaye
  • 935
  • 8
  • 14
  • Very helpful link and improved solution taking into account performance issues with running code on every scroll event...thanks! You cached the $(document) element, but you could also cache the $('.menu) el so the code doesn't retrieve it every time. – nabrown Feb 10 '15 at 15:22
0

I did an upgraded version of jezzipin's answer (and I'm animating padding top instead of height but you still get the point.

 /**
 * ResizeHeaderOnScroll
 *
 * @constructor
 */
var ResizeHeaderOnScroll = function()
{
    this.protocol           = window.location.protocol;
    this.domain             = window.location.host;
};

ResizeHeaderOnScroll.prototype.init    = function()
{
    if($(document).scrollTop() > 0)
    {
        $('header').data('size','big');
    } else {
        $('header').data('size','small');
    }

    ResizeHeaderOnScroll.prototype.checkScrolling();

    $(window).scroll(function(){
        ResizeHeaderOnScroll.prototype.checkScrolling();
    });
};

ResizeHeaderOnScroll.prototype.checkScrolling    = function()
{
    if($(document).scrollTop() > 0)
    {
        if($('header').data('size') == 'big')
        {
            $('header').data('size','small');
            $('header').stop().animate({
                paddingTop:'1em',
                paddingBottom:'1em'
            },200);
        }
    }
    else
      {
        if($('header').data('size') == 'small')
        {
            $('header').data('size','big');
            $('header').stop().animate({
                paddingTop:'3em'
            },200);
        }  
      }
}

$(document).ready(function(){
    var resizeHeaderOnScroll = new ResizeHeaderOnScroll();
    resizeHeaderOnScroll.init()
})
Collin
  • 1
  • 4
0

I took Jezzipin's answer and made it so that if you are scrolled when you refresh the page, the correct size applies. Also removed some stuff that isn't necessarily needed.

function sizer() {
    if($(document).scrollTop() > 0) {
        $('#header_nav').stop().animate({
            height:'40px'
        },600);
    } else {
        $('#header_nav').stop().animate({
            height:'100px'
        },600);
    }
}

$(window).scroll(function(){
    sizer();
});

sizer();
Tabetha Moe
  • 480
  • 4
  • 14