On-Scroll Animated Header

A fixed header that will animate its size on scroll. The inner elements will also adjust their size with a transition.


View demo Download source

An animated header that will change its size on scroll. Once a certain amount of the page gets scrolled, the header will decrease its size and the inner elements will adjust their font-size/line height. There are example media queries for dealing with different screen sizes.


<div class="cbp-af-header">
	<div class="cbp-af-inner">
			<a href="#">Broccoli</a>
			<a href="#">Almonds</a>
			<a href="#">Pears</a>
			<a href="#">Oranges</a>


.cbp-af-header {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	background: #f6f6f6;
	z-index: 10000;
	height: 230px;
	overflow: hidden;
	-webkit-transition: height 0.3s;
	-moz-transition: height 0.3s;
	transition: height 0.3s;

.cbp-af-header .cbp-af-inner {
	width: 90%;
	max-width: 69em;
	margin: 0 auto;
	padding: 0 1.875em;

.cbp-af-header h1,
.cbp-af-header nav {
	display: inline-block;
	position: relative;

 /* We just have one-lined elements, so we'll center the elements with the line-height set to the height of the header */
.cbp-af-header h1,
.cbp-af-header nav a {
	line-height: 230px;

.cbp-af-header h1 {
	text-transform: uppercase;
	color: #333;
	letter-spacing: 4px;
	font-size: 4em;
	margin: 0;
	float: left;

.cbp-af-header nav {
	float: right;

.cbp-af-header nav a {
	color: #aaa;
	font-weight: 700;
	margin: 0 0 0 20px;
	font-size: 1.4em;

.cbp-af-header nav a:hover {
	color: #333;

/* Transitions and class for reduced height */
.cbp-af-header h1,
.cbp-af-header nav a {
	-webkit-transition: all 0.3s;
	-moz-transition: all 0.3s;
	transition: all 0.3s;

.cbp-af-header.cbp-af-header-shrink {
	height: 90px;

.cbp-af-header.cbp-af-header-shrink h1,
.cbp-af-header.cbp-af-header-shrink nav a {
	line-height: 90px;

.cbp-af-header.cbp-af-header-shrink h1 {
	font-size: 2em;

/* Example Media Queries */
@media screen and (max-width: 55em) {
	.cbp-af-header .cbp-af-inner {
		width: 100%;

	.cbp-af-header h1,
	.cbp-af-header nav {
		display: block;
		margin: 0 auto;
		text-align: center;
		float: none;

	.cbp-af-header h1,
	.cbp-af-header nav a {
		line-height: 115px;

	.cbp-af-header nav a {
		margin: 0 10px;

	.cbp-af-header.cbp-af-header-shrink h1,
	.cbp-af-header.cbp-af-header-shrink nav a {
		line-height: 45px;

	.cbp-af-header.cbp-af-header-shrink h1 {
		font-size: 2em;

	.cbp-af-header.cbp-af-header-shrink nav a {
		font-size: 1em;

@media screen and (max-width: 32.25em) {
	.cbp-af-header nav a {
		font-size: 1em;

@media screen and (max-width: 24em) {
	.cbp-af-header nav a,
	.cbp-af-header.cbp-af-header-shrink nav a {
		line-height: 1;

The JavaScript

var cbpAnimatedHeader = (function() {

	var docElem = document.documentElement,
		header = document.querySelector( '.cbp-af-header' ),
		didScroll = false,
		changeHeaderOn = 300;

	function init() {
		window.addEventListener( 'scroll', function( event ) {
			if( !didScroll ) {
				didScroll = true;
				setTimeout( scrollPage, 250 );
		}, false );

	function scrollPage() {
		var sy = scrollY();
		if ( sy >= changeHeaderOn ) {
			classie.add( header, 'cbp-af-header-shrink' );
		else {
			classie.remove( header, 'cbp-af-header-shrink' );
		didScroll = false;

	function scrollY() {
		return window.pageYOffset || docElem.scrollTop;



View demo Download source


Tagged with:

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

View all contributions by

Website: http://www.codrops.com

Related Articles

Receive our bi-weekly Collective or official newsletter right in your inbox.

Which newsletter would you like to receive?

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 69

Comments are closed.
  1. 1

    This is ALMOST the same as the header in my new design, except mine scrolls up out of view (I hate headers that block part of the reading area) and will scroll down on click of a nav button :>

    • 2

      “…I hate headers that block part of the reading area…”

      I feel the same about fixed headers. It might result into a bad UX specifically for mobile users. The idea of collapsing it out of view as you’ve mentioned solves the issue though. 🙂

    • 3

      Mee too, a new design is very very similar to the Mary Lou concept !

      Yes it’s easy to add a collapse button to this concept, but I don’t agree your fixed header hate: I think fixed header is the future of web design: always visible means that you need only one touch to navigate in any menu item (usability) somore encouragement to navigate the site (or share an article on social networks, comment etc…)!

      Also, on mobile devices in portrait orientation this fixed menu is awesome IMHO: in these cases you have an aspect ratio that’s more height than width (not 4:3 or 16:9, but something like 2:1) so if you can “stole some height” on desktops layouts you surely use this extra space without any kind of problem on portrait mobile devices…

      On the other hand, yes on wider than normal landscape modes (android devices for instance, iPads are 4:3), this can be a problem: but solution is simple: you can write media queries to transform this fixed menu in a vertical iconic sidebar (like Google+ one) when scrolled in landscape mode. I’m working on that….

      PS: an Iconic mode is needed also on very tiny width devices:
      reducing the menu item font size to keep it fitting a single line on smartphones was also my solution, but after some testing i discovered that resulting menu item is too small to be touched, so better to use a square icon to represent the menu in order to offer more touchable pixels….

    • 4

      Can you show your design? I don’t hate the fixed header but it doesn’t work well with a design I am making.

    • 5

      I agree with Stefano. I’ve seen a site that took a different approach ( when you swipe up below the fold, the nav disappears and when you swipe down a bit, it will appear – much like the Pinterest app ), but it is kind of unsettling, appearing and disappearing with swipe down and swipe up, respectively.

      I don’t know much about UX/UI but I know that the eye tends to focus on something it can grasp, something “fixed”. You know: like, how car commercials and goPro cam views are fixed on the side and are more tolerable than a shaky mess of a shot.

      Fixed headers are here to stay. Mobile apps are embracing them, why not the web? Add this to a one-page site, and I don’t have to worry about carpal tunnel surgery from too much scrolling.

  2. 6

    This is awesome! I’ve been looking for this for a long time to put on my websites new design 😀

  3. 7

    What is the purpose of didScroll? It seems to just change back and forth from true to false without affecting any other property.

    • 8

      It’s optimization sugar, see here:

      if( !didScroll ) { didScroll = true; setTimeout( scrollPage, 250 ); }

      This implement a debouncer: the onscroll event may be called hundred of times per second when you are scrolling but the toggleClass code and related css animation will be executed only once every 250 milliseconds (that’s very acceptable compromise between percepibile UI latency (near to 0!) and performance optimization

      TEORICALLY, You can also do something like

      lastScheduledTimeout=setTimeout( scrollPage, 5 );

      so teorically you get it executed only once at the end of scrolling, but what if user scrolls for a long period?
      So it’s better update UI every 250!

      great work Mary Lou! As always you provide the best balance between technical and “congitive” properties of an UX 🙂

  4. 9

    I love your pure javascript implementations <3
    thanks for the tutorial 🙂

  5. 10

    I see this type of navigation more and more often on one-page websites and I`m glad you made a tutorial out of the idea! 🙂

    • 12

      look at the function scrollPage()
      this function just add a new class .
      you can do it with any div

  6. 13

    The header occupies half the screen on an iPhone 4 and does not change its size once I scroll.

    • 14

      It actually works fine on my iPhone 4s, you just need to scroll down more, although I agree it’s not that practical and needs some modifications.

      Great tutorial over all. Thanks!

  7. 15

    Cool stuff but it doesn’t work on ipad either. What would you need to do to make it work on mobile?

  8. 16

    This effect is really elegant and awesome, I will use it on my website. Thanks you!

  9. 19

    Had a lot of fun implementing this. I was wondering though, what’s the benefits of using Classie to add and remove classes on elements, as opposed to jQuery’s addClass and removeClass functions?

    • 22

      I have the same question, I’ve been trying for a few hours to put an image in the place where the word “fixed” is and can’t make it work.

  10. 25

    Hello Mary Lou,

    Great work on all your tutorials! I’m just discovering this site’s section. I’m very much at an intermediate/beginning level (although I did studied web design/dev for 2 years). Love these basic components and elements!

    Keep it up!

  11. 26

    This is really great work, but if only it worked in IE8!

    Really enjoying your work on a whole though. Thank you!

  12. 28

    I inserted .cbp-af-header {position: relative;} for IE8
    so it is working in IE8 without animation.

  13. 29

    To those of you asking what to do if you have images in your header – your logo, for instance – I came across a decent solution. It works well, though I am fairly novice so I can’t speak to its elegance or platform compatibility. Anyway, using jquery I did the following, to make my logo disappear when the user has scrolled a set distance from the top.

    var showTopMenu = function() {
    var topMenu = $('#logo');

    if ($(window).scrollTop() < 1000) {
    topMenu.css('display', 'block');
    } else {
    topMenu.css('display', 'none');
    $(window).scroll(function(){ showTopMenu(); })


    I have 1000 as the trigger point for the image to disappear, but the trick is that you will have to coordinate that number with wherever you want your header to shrink/collapse. I did this for the other tutorial ‘On Scroll Header Effects’, which uses the waypoint plugin, but the idea is the same. P.S. It would be really cool if codrops did a tutorial involving either bullseye.js or Zurb’s Foundation navigation tool magellan.js, or else about using offsets for single-page app navigation so that fixed headers (of whatever size) don’t get in the way of your content.

    Thanks again Mary Lou et al.


    • 30

      This is cool but I’ve got a question. How do you make didscroll work? I definitely need this function. Please help, God bless.

Comments are closed.