Gestion des événements de défilement sans nuire aux performances

Les événements de défilement se déclenchent des dizaines de fois par seconde. Sans une gestion appropriée, ils vont plomber les performances de votre site, vider les batteries des appareils mobiles et créer des expériences utilisateur saccadées. Voici comment optimiser les gestionnaires de défilement en utilisant la limitation de fréquence, l’anti-rebond et les écouteurs passifs.
Points clés à retenir
- La limitation de fréquence (throttling) limite l’exécution des fonctions à des intervalles fixes pour des mises à jour cohérentes
- L’anti-rebond (debouncing) attend que le défilement s’arrête avant d’exécuter des opérations coûteuses
- Les écouteurs passifs permettent des optimisations immédiates du navigateur
- L’Intersection Observer élimine les événements de défilement pour la détection de visibilité
Le problème : Pourquoi les événements de défilement bruts détruisent les performances
Chaque mouvement de défilement déclenche plusieurs événements—souvent plus de 60 par seconde. Lorsque vous attachez des calculs lourds à ces événements, vous demandez au navigateur de :
- Bloquer le thread principal de manière répétée
- Empêcher un défilement fluide
- Augmenter considérablement l’utilisation du processeur
- Vider la batterie sur les appareils mobiles
// NE FAITES PAS CECI - se déclenche constamment
window.addEventListener('scroll', () => {
calculateExpensiveAnimation();
updateNavigationState();
checkElementVisibility();
});
Solution 1 : Limitation de fréquence pour des mises à jour cohérentes
La limitation de fréquence limite l’exécution des fonctions à un intervalle fixe. Parfait pour les animations basées sur le défilement ou les indicateurs de progression qui nécessitent des mises à jour régulières.
function throttle(func, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
return func.apply(this, args);
}
};
}
// Se déclenche au maximum toutes les 100ms
window.addEventListener('scroll', throttle(() => {
updateScrollProgress();
}, 100));
Quand utiliser la limitation de fréquence :
- Barres de progression de défilement
- Effets de parallaxe
- Mises à jour d’état de navigation
- Suivi de position en temps réel
Solution 2 : Anti-rebond pour les valeurs finales
L’anti-rebond attend que le défilement s’arrête avant d’exécuter. Idéal pour les opérations coûteuses qui n’ont besoin que de la position finale de défilement.
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
// Se déclenche 200ms après l'arrêt du défilement
window.addEventListener('scroll', debounce(() => {
saveScrollPosition();
loadMoreContent();
}, 200));
Quand utiliser l’anti-rebond :
- Déclencheurs de défilement infini
- Suivi analytique
- Sauvegarde de la position de défilement
- Calculs DOM lourds
Discover how at OpenReplay.com.
Solution 3 : Écouteurs passifs pour des performances instantanées
Les écouteurs passifs indiquent au navigateur que vous n’appellerez pas preventDefault()
, permettant des optimisations de défilement immédiates.
// Le navigateur peut optimiser le défilement immédiatement
window.addEventListener('scroll', handleScroll, { passive: true });
Ce simple indicateur améliore les performances de défilement en permettant au navigateur d’ignorer la vérification de si vous allez empêcher le comportement par défaut. Les navigateurs mobiles bénéficient particulièrement de cette optimisation.
Combinaison de techniques pour des performances maximales
Pour des interactions de défilement complexes, combinez plusieurs approches :
// Gestionnaire avec limitation de fréquence et écouteur passif
const optimizedScroll = throttle(() => {
requestAnimationFrame(() => {
updateUI();
});
}, 16); // ~60fps
window.addEventListener('scroll', optimizedScroll, { passive: true });
Alternative moderne : Intersection Observer
Pour la détection de visibilité, évitez complètement les événements de défilement :
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
lazyLoadImage(entry.target);
}
});
});
observer.observe(document.querySelector('.lazy-image'));
L’Intersection Observer gère la détection de visibilité sans aucun écouteur de défilement, offrant des performances supérieures pour le chargement paresseux et les animations déclenchées par le défilement.
Guide de décision rapide
Technique | Cas d’usage | Fréquence de mise à jour |
---|---|---|
Throttle | Barres de progression, parallaxe | Intervalles fixes |
Debounce | Sauvegarder l’état, charger du contenu | Après arrêt du défilement |
Passif | Tout gestionnaire de défilement | Toujours (quand possible) |
Intersection Observer | Détection de visibilité | Aucun événement de défilement |
Conseils d’implémentation
- Utilisez toujours des écouteurs passifs sauf si vous avez besoin de
preventDefault()
- Commencez avec des délais de limitation de 16ms pour les animations à 60fps
- Utilisez des délais d’anti-rebond de 200-300ms pour les actions déclenchées par l’utilisateur
- Considérez Lodash pour des implémentations éprouvées
- Profilez avec Chrome DevTools pour mesurer les gains de performance réels
Conclusion
Les gestionnaires de défilement non optimisés sont des tueurs de performances. La limitation de fréquence vous donne des mises à jour contrôlées pour les animations, l’anti-rebond gère efficacement les valeurs finales, et les écouteurs passifs fournissent des optimisations instantanées du navigateur. Pour la détection de visibilité, évitez complètement les événements de défilement avec l’Intersection Observer. Choisissez la bonne technique pour votre cas d’usage, et vos utilisateurs vous remercieront avec leur autonomie de batterie.
FAQ
La limitation de fréquence exécute votre fonction à intervalles réguliers pendant le défilement, comme toutes les 100ms. L'anti-rebond attend que le défilement s'arrête complètement, puis s'exécute une fois. Utilisez la limitation de fréquence pour les mises à jour continues et l'anti-rebond pour les valeurs finales.
Non, les écouteurs passifs indiquent explicitement au navigateur que vous n'appellerez pas preventDefault. Si vous devez empêcher le comportement de défilement par défaut, définissez passive à false, mais cela impacte les performances. Considérez d'abord des approches alternatives.
Utilisez l'Intersection Observer pour toute logique basée sur la visibilité comme le chargement paresseux, les déclencheurs de défilement infini, ou les animations au défilement. Il est plus performant que les événements de défilement et gère automatiquement les calculs de viewport sans vérification manuelle de position.
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.