Header sticky avec changement de statut au scroll

by oilvier

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script>
<header class="header">
	logo
</header>
<main>
	<p><img src="//placehold.it/1200x500/c6e170/FFFFFF" alt=""></p>
	<p><img src="//placehold.it/1200x500/92c46d/FFFFFF" alt=""></p>
	<p><img src="//placehold.it/1200x500/297d7d/FFFFFF" alt=""></p>
	
</main>

SCSS

body {height:1500px; background-color:beige;}
img {max-width: 100%; height: auto;}

.header {position:relative; padding:20px; background-color:#c6e170; color:white; z-index:10;}

/* ==========================================================================
   ## Header fixe
   ========================================================================== */

/**
 * Élément "fantôme" généré en JS qui prendra la place du header une fois qu'il sera fixé 
 * Cela évite d'appliquer un padding sur l'élément principal
 */
.header-placeholder {background-color:#c6e170;
	.js & {display:none;}
}

.header {
	/* On ajoute la classe via JavaScript */
	&.is-sticky,
	&.is-sticky-first {position:fixed; top:0; left:0; right:0; padding:15px 20px; background-color:white; color:black; transform:translate3d(0,0,0); box-shadow:0 0 5px rgba(0,0,0,.25); transition:background 0.15s ease-out, color 0.15s ease-out;

		/* On affiche l'élément fantôme pour éviter un saut de la scrollbar suite à la disparition du flux de notre header */
		& + .header-placeholder {display:block;}
	}   
}

JavaScript

/*===================================
=            Header fixe            =
===================================*/

var scrolling 		= false,
	headerHeight 	= $('.header').outerHeight();

// On utilise requestAnimationFrame pour améliorer les performances
function requestStickyHeader() {
	if(!scrolling) {
		requestAnimationFrame(stickyHeader);
		scrolling = true;
	}
}

function stickyHeader() {
	var scrollTopPosition 	= $(window).scrollTop(),
		$header 			= $(".header"),
		headerPosition 		= $header.outerHeight();

	// On détecte si l'utilisateur a dépassé le haut du header à déplacer
	if (scrollTopPosition > headerPosition ) {
		// On ajoute la classe qui permet de coller le header
		$header.addClass('is-sticky');

		// Si la page a été ouverte avec une position de scroll avancée, on retirer la classe associée
		if ($header.hasClass('is-sticky-first')) {
			$header.removeClass('is-sticky-first');
		}

	} else if (scrollTopPosition < (headerPosition / 2) ) {
		// Une fois que l'utilisateur est retourné en haut de l'écran, on annule le comportement
		$header.removeClass('is-sticky');
	}

	if($('.header-placeholder').length) {
		// On attribue la hauteur du header sur l'élément qui prend sa place
		$('.header-placeholder').css('height', headerHeight);
	}

	// On remet à 0 pour appeler les prochains requestAnimationFrame
	scrolling = false;

} 

/**
 * Au chargement, on vérifie la position de la page
 * Si besoin, on ajoute une classe spécifique pour afficher le header
 * ! Ce n'est pas la même classe que pour le scroll classique !
 */
if($(window).scrollTop() > headerHeight) {
	$('.header').addClass('is-sticky-first');
}

if(!$('.header-placeholder').length) {
	// On ajoute aussi un élément "fantôme" pour prendre le même espace que le header qui sort du flux
	$('<div class="header-placeholder"></div>').insertAfter('.header').css('height', headerHeight);
}

// On lance notre fonction au load, resize et scroll
// Load : pour que le header apparaisse si on rafraichit au...