Fluidifier le défilement : débouncer les gestionnaires d’entrée
Apprenez à débouncer vos gestionnaires d'entrée pour un défilement fluide, un meilleur INP et une expérience plus réactive.
Le défilement est l’une des interactions les plus fréquentes sur le Web : s’il saccade, l’expérience entière paraît lente, même sur une page par ailleurs rapide. Les gestionnaires d’entrée (défilement, toucher) sont souvent en cause, car un code trop lourd attaché à ces événements empêche le navigateur de produire ses images à temps. Le résultat est un défilement haché et des frames perdues.
Fluidifier le défilement améliore directement l’expérience utilisateur et participe à un bon INP (Interaction to Next Paint), la métrique de réactivité des Core Web Vitals ; pour une vue d’ensemble, voyez comment optimiser l’INP. Pour le SEO, une page réactive renvoie un signal de qualité et limite la frustration qui pousse à quitter le site. Ce tutoriel explique le mécanisme et la solution recommandée par Google.
Un défilement qui saccade ruine la perception de qualité d’un site bien plus vite qu’un chargement initial un peu lent, et c’est typiquement ce qui plombe l’INP. La faute revient presque toujours à un gestionnaire d’entrée qui modifie les styles à chaque événement. Mon premier réflexe en audit : ouvrir le profileur et regarder ce qui s’exécute pendant le scroll.
Pourquoi un gestionnaire lourd bloque le défilement
Dans le cas idéal, le navigateur déplace simplement le contenu lors du défilement, sans solliciter le fil principal où s’exécutent JavaScript, le calcul des styles et la mise en page. Le défilement reste alors parfaitement fluide.
Dès qu’un gestionnaire est attaché à un événement comme touchstart, touchmove ou touchend, le compositeur doit attendre la fin de son exécution, car le code pourrait appeler preventDefault() et empêcher le défilement. Cette attente, même brève, suffit à provoquer des à-coups. La règle de base est donc de garder ces gestionnaires aussi légers et rapides que possible, dans la logique du travail visant à optimiser les longues tâches du fil principal.
Ne pas modifier les styles dans un gestionnaire d'entrée
Les gestionnaires de défilement et de toucher s’exécutent juste avant les rappels requestAnimationFrame. Si vous y modifiez une propriété visuelle, des changements de style restent en attente au début du rappel.
Si vous lisez ensuite une propriété visuelle au début de ce même rappel, vous forcez le navigateur à recalculer la mise en page de façon synchrone : c’est une mise en page forcée, coûteuse, qui dégrade la fluidité. La bonne pratique consiste à séparer nettement la lecture et l’écriture des propriétés visuelles, plutôt que de les mélanger dans le gestionnaire d’entrée.
Débouncer avec requestAnimationFrame
La solution aux deux problèmes est la même : reporter les modifications visuelles au prochain rappel requestAnimationFrame. Concrètement, le gestionnaire se contente de stocker la valeur utile (par exemple la position de défilement), puis planifie une seule mise à jour visuelle.
Un drapeau évite de planifier plusieurs rappels pour rien. Le gestionnaire reste ainsi très léger, et tout le travail coûteux de lecture et de mise à jour s’effectue au bon moment, sans bloquer le défilement ni le toucher. Cette technique simple suffit à supprimer la plupart des saccades liées aux interactions ; pour aller au fond du sujet, apprenez à mesurer l’INP avant et après vos corrections.
| Étape | Action | Effet |
|---|---|---|
1 |
Garder le gestionnaire d’entrée minimal |
Libère le compositeur et fluidifie le défilement |
2 |
Stocker la valeur de l’événement (position de défilement) |
Conserve l’information sans traitement coûteux |
3 |
Planifier une seule mise à jour via requestAnimationFrame |
Évite les rappels redondants |
4 |
Lire et écrire les propriétés visuelles dans le rappel |
Empêche la mise en page forcée synchrone |
let lastScrollY = 0;
let scheduledAnimationFrame = false;
function onScroll() {
// Stocke la valeur de défilement pour plus tard.
lastScrollY = window.scrollY;
// Évite de planifier plusieurs rappels rAF.
if (scheduledAnimationFrame) return;
scheduledAnimationFrame = true;
requestAnimationFrame(readAndUpdatePage);
}
function readAndUpdatePage() {
// Lecture puis écriture des propriétés visuelles ici.
scheduledAnimationFrame = false;
}
window.addEventListener('scroll', onScroll);
Modifier une propriété visuelle dans un gestionnaire de défilement ou de toucher, puis lire une autre propriété dans le rappel requestAnimationFrame, déclenche une mise en page forcée synchrone très coûteuse. Cantonnez le gestionnaire au stockage de la valeur et déplacez toute lecture ou écriture visuelle dans le rappel rAF.
À faire
- garder les gestionnaires d’entrée légers
- stocker la valeur de l’événement
- reporter les mises à jour visuelles dans requestAnimationFrame
- utiliser un drapeau pour éviter les rappels en double
À éviter
- exécuter du code lourd dans un gestionnaire de défilement
- modifier les styles directement dans le gestionnaire
- mélanger lecture et écriture des propriétés visuelles
- planifier un rappel rAF à chaque événement
Points clés à retenir
- Garder les gestionnaires de défilement et de toucher minimaux
- Stocker la valeur de l'événement plutôt que la traiter sur-le-champ
- Reporter les modifications visuelles dans requestAnimationFrame
- Éviter toute mise en page forcée synchrone
- Utiliser un drapeau contre les rappels redondants
Un défilement fluide repose sur des gestionnaires d’entrée allégés et un bon ordonnancement.
Quiz : testez vos connaissances
Quiz : testez vos connaissances
-
En quoi consiste le débounce d'un gestionnaire d'entrée ?
- Reporter le travail visuel vers le prochain rappel requestAnimationFrame, plutôt que de l'exécuter à chaque événement
- Supprimer complètement le gestionnaire pour qu'aucun code ne s'exécute
- Exécuter le gestionnaire deux fois pour fiabiliser le résultat
Débouncer un gestionnaire, c’est différer son travail visuel jusqu’au prochain rappel
requestAnimationFrameau lieu de l’exécuter à chaque événement. Le gestionnaire se contente alors de stocker la valeur utile. -
Pourquoi faut-il éviter de modifier les styles directement dans un gestionnaire de défilement ?
- Parce que cela laisse des changements de style en attente et provoque une mise en page forcée synchrone si on lit ensuite une propriété visuelle
- Parce que le navigateur refuse toute modification de style pendant un défilement
- Parce que les styles modifiés dans un gestionnaire ne s'appliquent jamais
Modifier un style dans un gestionnaire laisse des changements en attente. Lire ensuite une propriété visuelle force le navigateur à recalculer la mise en page de façon synchrone, une opération coûteuse.
-
Comment éviter de planifier plusieurs rappels requestAnimationFrame inutiles lors d'un défilement ?
- En appelant requestAnimationFrame à chaque événement de défilement reçu
- En utilisant un drapeau pour ne planifier qu'une seule mise à jour visuelle et éviter les rappels en double
- En modifiant les styles immédiatement à chaque déclenchement du gestionnaire
Le gestionnaire stocke la valeur utile, puis planifie une seule mise à jour visuelle. Un drapeau évite de programmer plusieurs rappels
requestAnimationFrameen double pour la même image.
Besoin d'un accompagnement SEO ?
Vos interactions et votre défilement sont-ils aussi fluides qu'ils devraient l'être ?