Sticky sidebar

Nous allons voir comment créer un menu latéral qui nous suit au scroll sur le coté.
Le scroll ne prendra effet qu'une fois le header passé et prendra fin une fois arrivé au footer.
Dans un premier temps créons le gabarit général.

<header>HEADER</header>
<main>
	<div class="global">
		<section class="content">
			Beaucoup de texte...
		</section>
		<aside class="sidebar">
			<ul>
				<li>Lien 1</li>
				<li>Lien 2</li>
				<li>Lien 3</li>
				<li>Lien 4</li>
				<li>Lien 5</li>
			</ul>
		</aside>
	</div>
</main>	
<footer>FOOTER</footer>
HTML
header, footer{
	display: flex;
	justify-content: center;
	align-items: center;
	padding: 50px;
	font-size: 30px;
	color: #fff;
	font-weight: bold;
}
header{background: BlueViolet;}
footer{
	height: 600px;
	background: DarkOrchid;
}
.global{
	display: flex;
	width: 980px;
	margin-left: auto;
	margin-right: auto;
}
.content{
	width: 600px;
	margin-right: 80px;
	padding: 50px;
	background: AliceBlue;
}
.sidebar{
	display: flex;
	width: 300px;
	background: LightYellow;
}
.sidebar ul{
	padding: 50px;
}
CSS

L'objectif va être de rendre la liste sticky.
Nous auront trois états:
- l'état où la liste est ferrée en haut de son conteneur
- l'état où la liste suit le scroll
- l'état où la liste est ferrée en bas de son conteneur

Par defaut nous mettons la classe top sur le ul

.sidebar ul{
	top:0;
	padding: 50px;
}
.sidebar ul.top{
	align-self: flex-start;
}
.sidebar ul.bottom{
	align-self: flex-end;
}
.sidebar ul.fixed{
	position: fixed;
}
CSS

Désormais il faut changer les classes au moment opportun via du Js

const asidePosition = document.querySelector('.sidebar').getBoundingClientRect()
const asideTopPosition = asidePosition.top + document.body.scrollTop
const asideBottomPosition = asidePosition.bottom + document.body.scrollTop

const stickyList = document.querySelector('.sidebar ul')
const stickyListHeight = stickyList.offsetHeight

const activateScroll = () => {
	/*Activation de la position fixe en scrollant de haut en bas*/
	if(window.pageYOffset > asideTopPosition && stickyList.classList.contains('top')){
		stickyList.classList.remove('top')
		stickyList.classList.add('fixed')
	/*Désactivation de la position fixe en scrollant de bas en haut*/
	}else if(window.pageYOffset < asideTopPosition && stickyList.classList.contains('fixed')){
		stickyList.classList.remove('fixed')
		stickyList.classList.add('top')
	/*Désactivation de la position fixe en scrollant de haut en bas*/
	}else if(window.pageYOffset > (asideBottomPosition - stickyListHeight) && stickyList.classList.contains('fixed')){
		stickyList.classList.remove('fixed')
		stickyList.classList.add('bottom')
		/*Activation de la position fixe en scrollant de bas en haut*/
	}else if(window.pageYOffset < (asideBottomPosition - stickyListHeight) && stickyList.classList.contains('bottom')){
		stickyList.classList.remove('bottom')
		stickyList.classList.add('fixed')
	}
}

activateScroll()
window.addEventListener('scroll', () => {
	this.requestAnimationFrame(activateScroll)
})
Javascript

Nous avons donc réalisé une sticky sidebar fonctionnelle.
Nous avons cependant un problème pour tout ce qui concerne les mobiles et tablettes sous ios.
En effet le comportement du scroll sur ces supports est différents, l'eventListener ne se déclenchant qu'à la fin du scroll, ce qui ne nous donne pas une animation fluide de la sidebar, le changement de classe ne se faisant pas forcément au moment opportun.

La solution, position sticky.

En effet, cette position que nous avons emulée ci dessus existe nativement. Elle n'est cependant pas encore implémentée sur edge et est uniquement présente sur Chrome depuis la version 56. Elle est par contre implémentée sur ios safari depuis la version 6!
Pour ce faire nous allons associer la position sticky à @supports.
Seuls les navigateurs disposant d'une compatibilité avec position sticky utiliseront ainsi cette règle css.

@supports(position: sticky){
	.sidebar ul{position: sticky;}
	.sidebar ul.fixed{position: sticky;}
}
CSS

Et voilà nous avons désormais une sidebar sticky avec une bonne compatibilité pour peu qu'on passe le css sur autoprefixer et le js sur babel.
Ci dessous le code css final

body{
	font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
}
header, footer{
	display: flex;
	justify-content: center;
	align-items: center;
	padding: 50px;
	font-size: 30px;
	color: #fff;
	font-weight: bold;
}
header{background: BlueViolet;}
footer{
	height: 600px;
	background: DarkOrchid;
}
.global{
	display: flex;
	width: 980px;
	margin-left: auto;
	margin-right: auto;
}
.content{
	width: 600px;
	margin-right: 80px;
	padding: 50px;
	background: AliceBlue;
}
.sidebar{
	display: flex;
	align-items: flex-start;
	width: 300px;
	background: LightYellow;
}
.sidebar ul{
	top:0;
	padding: 50px;
}
.sidebar ul.top{
	align-self: flex-start;
}
.sidebar ul.bottom{
	align-self: flex-end;
}
.sidebar ul.fixed{
	position: fixed;
}
@supports(position: sticky){
	.sidebar ul{position: sticky;}
	.sidebar ul.fixed{position: sticky;}
}
CSS

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *