Défilement JavaScript
Les événements de défilement en JavaScript permettent aux développeurs d'interagir avec le défilement d'une page web, utiles pour le chargement différé et plus.
Comprendre les événements et techniques de défilement en JavaScript
Les événements de défilement en JavaScript vous permettent de réagir à la position d'un utilisateur sur une page. C'est le fondement de fonctionnalités telles que les effets parallaxe, le déclenchement d'animations basées sur la position de défilement, la mise en œuvre du défilement infini, les boutons "retour en haut", les en-têtes persistants et les barres de progression de lecture. Ce guide explique comment lire la position de défilement actuelle, comment faire défiler par programme, comment gérer l'événement scroll efficacement, et quand utiliser plutôt le moderne IntersectionObserver.
Lire la position de défilement actuelle
Avant de réagir au défilement, vous devez généralement savoir jusqu'où la page a défilé. Les propriétés les plus fiables se trouvent sur window :
window.scrollY— distance de défilement vertical en pixels (égalementwindow.pageYOffset, un alias plus ancien).window.scrollX— distance de défilement horizontal en pixels (aliaswindow.pageXOffset).
Pour un élément déroulable individuel, utilisez plutôt element.scrollTop et element.scrollLeft. Ces propriétés sont en lecture/écriture : leur affectation fait sauter l'élément à cette position.
// How far down the whole page has the user scrolled?
console.log(window.scrollY); // e.g. 0 at the top, 420 partway down
// Total scrollable height of the document
const docHeight = document.documentElement.scrollHeight;
const winHeight = window.innerHeight;
// How close to the bottom are we (0 = top, 1 = bottom)?
const progress = window.scrollY / (docHeight - winHeight);
console.log(progress);Pour les décalages par élément et un examen plus approfondi de getBoundingClientRect, consultez Coordonnées JavaScript et Tailles de fenêtre et défilement.
Faire défiler par programme
Vous ne faites pas seulement écouter le défilement — vous pouvez aussi le déclencher. Ces méthodes acceptent une option behavior: 'smooth' pour une transition animée plutôt qu'un saut instantané :
window.scrollTo(x, y)— faire défiler vers une position absolue.window.scrollBy(dx, dy)— faire défiler d'une quantité relative depuis la position actuelle.element.scrollIntoView(options)— faire défiler pour qu'un élément spécifique soit visible.
// Jump to the very top, smoothly
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });
// Nudge down by one viewport height
window.scrollBy({ top: window.innerHeight, behavior: 'smooth' });
// Bring an element into view (e.g. after navigating to an anchor)
document.querySelector('#section-2')
.scrollIntoView({ behavior: 'smooth', block: 'start' });C'est la bonne façon de mettre en œuvre un bouton "retour en haut" ou une navigation fluide par ancres dans la page. Utilisez querySelector pour obtenir d'abord l'élément cible.
L'événement de défilement JavaScript
L'événement scroll se déclenche lorsque la vue du document ou un élément déroulable est parcouru. C'est l'un des événements les plus fréquemment utilisés pour les conceptions dynamiques et interactives.
Concepts clés
- Fréquence des événements : L'événement
scrollpeut se déclencher des dizaines de fois par seconde, donc son gestionnaire s'exécute très souvent. Effectuer des opérations lourdes (lectures de mise en page, écritures dans le DOM, appels réseau) à chaque déclenchement provoque un défilement saccadé. La solution standard est de limiter (throttle) ou différer (debounce) le gestionnaire. - Défilement de
windowvs. d'un élément : Vous pouvez écouter le défilement sur toute la fenêtre (window.addEventListener('scroll', ...)) ou sur un élément déroulable spécifique (el.addEventListener('scroll', ...)). scrollne remonte pas : Un événementscrollsur un élément ne remonte pas jusqu'au document, donc attachez le gestionnaire à l'élément qui défile réellement.
Throttle vs. Debounce
Les deux limitent la fréquence d'exécution de votre gestionnaire, mais ils se comportent différemment :
- Debounce attend que le défilement s'arrête pendant
waitms, puis s'exécute une fois. Adapté pour "faire quelque chose quand l'utilisateur a fini de défiler" (par exemple, sauvegarder la position de défilement). - Throttle s'exécute au maximum une fois toutes les
waitms pendant le défilement. Mieux adapté aux effets continus comme les barres de progression, où vous souhaitez des mises à jour régulières pendant le défilement.
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
function throttle(func, wait) {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= wait) {
last = now;
func.apply(this, args);
}
};
}
// Debounce: runs once 100ms after scrolling stops
window.addEventListener('scroll', debounce(() => {
// handle scroll logic here
}, 100));
// Throttle: runs at most every 100ms while scrolling
window.addEventListener('scroll', throttle(() => {
// update a progress bar, etc.
}, 100));Ces deux helpers basés sur setTimeout reposent sur les API de planification setTimeout / setInterval.
Exemples pratiques de gestion des événements de défilement
Exemple 1 : Afficher/masquer la navigation lors du défilement
Cet exemple montre comment masquer une barre de navigation lors du défilement vers le bas et l'afficher lors du défilement vers le haut, un schéma courant dans de nombreux sites web modernes pour maximiser l'espace d'écran disponible.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Scroll Event Navigation Example</title>
<style>
#navbar {
position: fixed;
top: 0;
width: 100%;
background-color: #333;
color: white;
text-align: center;
padding: 10px;
transition: top 0.3s;
}
body {
padding: 0;
margin: 0;
height: 1500px; /* to ensure scrolling */
font-family: Arial, sans-serif;
}
</style>
</head>
<body>
<p style="display: flex; justify-content: center; align-items: center; margin-top: 50vh;"><strong>When you scroll down, the navigation bar disappears. Scroll back up, and it reappears!</strong></p>
<div id="navbar">Navigation Bar</div>
<script>
let lastScrollTop = 0;
window.addEventListener(
"scroll",
function () {
let currentScroll = window.pageYOffset || document.documentElement.scrollTop;
if (currentScroll > lastScrollTop) {
document.getElementById("navbar").style.top = "-50px"; // Adjust based on nav height
} else {
document.getElementById("navbar").style.top = "0px";
}
lastScrollTop = currentScroll <= 0 ? 0 : currentScroll; // For Mobile or negative scrolling
},
false
);
</script>
</body>
</html>Explication :
- Le script suit la dernière position de défilement et la compare avec la position actuelle. Si la position actuelle est plus haute, cela signifie que l'utilisateur défile vers le bas, donc la barre de navigation est masquée en ajustant sa position supérieure hors de l'écran.
- Lors du défilement vers le haut, la barre de navigation réapparaît.
Exemple 2 : Déclenchement d'animation au défilement
Cet exemple montre comment déclencher des animations lorsque des éléments entrent dans le viewport lors d'un défilement.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Scroll Animation Trigger</title>
<style>
.box {
width: 100px;
height: 100px;
background: red;
opacity: 0;
transition: opacity 2s;
margin: 600px auto; /* Ensures it starts out of view */
}
</style>
</head>
<body>
<p>Keep scrolling down to see the animation!</p>
<div class="box"></div>
<script>
let hasAnimated = false;
window.addEventListener('scroll', function() {
const box = document.querySelector('.box');
const rect = box.getBoundingClientRect();
if (rect.top < window.innerHeight && !hasAnimated) {
box.style.opacity = 1; // Fade in the box when it comes into view
hasAnimated = true;
}
});
</script>
</body>
</html>Explication :
- Vérification de visibilité : Le script vérifie si le haut de l'élément
.boxse trouve dans le viewport et change son opacité à 1, déclenchant un effet de fondu. Un indicateur empêche l'animation de se redéclencher lors des événements de défilement suivants.
Exemple 3 : Effet de défilement parallaxe
Cet exemple illustre un simple effet parallaxe où l'image d'arrière-plan se déplace à une vitesse différente de celle du contenu au premier plan lorsque vous faites défiler la page.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Enhanced Parallax Scrolling</title>
<style>
body, html {
height: 100%;
margin: 0;
font-family: Arial, sans-serif;
overflow-x: hidden; /* Prevent horizontal scroll */
}
.parallax {
height: 100vh; /* Full height of the viewport */
position: relative;
background: url('https://via.placeholder.com/1920x1080') no-repeat center center;
background-size: cover;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 36px;
letter-spacing: 1px;
}
.content {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: white;
color: #333;
font-size: 24px;
padding: 0 20px;
text-align: center;
box-sizing: border-box;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="content">Scroll down to see the parallax effect!</div>
<div class="parallax">Stunning Parallax!</div>
<div class="content">Keep scrolling to see more effects.</div>
<div class="parallax"></div>
<div class="content">You have reached the end. Amazing, right?</div>
<script>
document.addEventListener('scroll', function() {
document.querySelectorAll('.parallax').forEach(function(el) {
const factor = 0.5; // Change this for more or less parallax
const offset = window.pageYOffset * factor - 300; // Adjusts the starting position of background
el.style.backgroundPositionY = offset + 'px';
});
});
</script>
</body>
</html>Explication :
- Styles CSS : La classe
.parallaxconfigure l'image d'arrière-plan pour remplir le conteneur et la centre. L'exemple repose entièrement sur JavaScript pour le positionnement, évitant le CSSbackground-attachment: fixed, qui peut causer des problèmes de performance sur les appareils mobiles. - Fonctionnalité JavaScript : Lors du défilement, le script calcule une nouvelle position verticale pour l'image d'arrière-plan à partir du décalage de défilement. En ajustant
backgroundPositionYdynamiquement, l'image se déplace à un rythme différent du contenu de la page, créant l'effet de profondeur parallaxe.
En résumé, lorsque vous faites défiler la page, les images d'arrière-plan se déplacent plus lentement que le texte, leur donnant l'apparence d'être à une profondeur différente.
L'alternative moderne : IntersectionObserver
Pour le cas courant "faire quelque chose lorsqu'un élément devient visible" (chargement différé, animations de fondu, défilement infini), IntersectionObserver est l'approche moderne recommandée. Au lieu d'exécuter votre code à chaque événement scroll et de lire manuellement les positions, le navigateur vous informe de manière asynchrone lorsqu'un élément franchit un seuil — beaucoup plus efficace et sans saccades.
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('visible'); // run once it enters view
observer.unobserve(entry.target); // stop watching it
}
});
},
{ threshold: 0.25 } // fire when 25% of the element is visible
);
document.querySelectorAll('.box').forEach((el) => observer.observe(el));Utilisez l'événement scroll quand vous avez besoin d'une lecture continue de la position de défilement (parallaxe, barres de progression). Utilisez IntersectionObserver quand vous voulez seulement savoir qu'un élément est entré ou sorti du viewport. C'est conceptuellement similaire à l'API MutationObserver.
Bloquer et restaurer le défilement
Une exigence UI courante consiste à verrouiller le défilement de la page lorsqu'une fenêtre modale ou un menu est ouvert. Vous ne pouvez pas annuler de manière fiable l'événement scroll avec preventDefault() (il se déclenche après que le défilement a eu lieu). À la place, basculez le CSS overflow :
// Lock scrolling (e.g. when opening a modal)
document.body.style.overflow = 'hidden';
// Restore it when the modal closes
document.body.style.overflow = '';Conclusion
Gérer efficacement les événements de défilement est une compétence essentielle pour les développeurs web, permettant de créer des sites web plus interactifs et optimisés en termes de performances. Que vous mettiez en œuvre des améliorations de l'interface utilisateur comme des barres de navigation dynamiques ou un effet parallaxe sur votre page, comprendre et gérer correctement le défilement en JavaScript peut considérablement améliorer l'expérience utilisateur.