Dans ce tutoriel nous allons voir comment créer un effet de parallaxe en JavaScript au défilement de la page. L'objectif est de faire en sorte que différents éléments de la page défilent plus ou moins vite que le scroll pour donner un effet de perspective / profondeur.
Quelle approche ?
Pour créer cet effet l'idée est d'appliquer une translation sur l'élément en fonction du niveau de défilement de l'utilisateur. Pour calculer la translation à appliquer on va calculer la position de l'élément par rapport au centre de l'écran.
On a 2 possibilités pour faire ce calcul :
- Utiliser le
getBoundingClientRect()
qui permet d'obtenir les informations sur la taille et la position de l'élément par rapport à l'écran. - Le
offsetTop
qui permet d'obtenir la position de l'élément par rapport au conteneur positionné le plus proche.
L'offsetTop a l'avantage de ne pas être affecté par les transformations ce qui peut simplifier le calcul. L'autre avantage est que l'offsetTop peut être calculé et sauvegardé en amont (si la structure de votre page ne change pas). On fera juste attention à calculer cet offsetTop
récursivement pour avoir la position par rapport au haut de la page.
/**
* Calcul la position de l'élément par rapport au haut de la page
* @param {HTMLElement} element
* @return {number}
*/
function offsetTop(element, acc = 0) {
if (element.offsetParent) {
return offsetTop(element.offsetParent, acc + element.offsetTop);
}
return acc + element.offsetTop;
}
On peut ensuite utiliser cette valeur pour calculer la différence par rapport au centre de l'écran.
const elementY = offsetTop(this.element) + this.element.offsetHeight / 2;
const screenY = window.scrollY + window.innerHeight / 2;
const diffY = this.elementY - screenY;
Enfin il faudra appliquer cette différence sur le translateY pour freiner ou accélérer la sensation de défilement.
element.style.setProperty("transform", `translateY(${diffY * -1 * ratio}px)`);
On répétera ce calcul lors du défilement de l'utilisateur.
Optimisation
On fera attention à optimiser les performances de notre animation afin d'éviter de ralentir le défilement.
- On englobe notre transformation dans un
window.requestAnimationFrame
afin de ne pas faire de calcul quand le navigateur ne dessine pas. - On utilise l'IntersectionObserver pour détecter quand l'élément devient visible à l'écran et ne lancer le comportement qu'à ce moment-là.