Tuer la dépendance JS : comment les animations CSS pilotées par le défilement réécrivent les règles de performance frontend
Les animations CSS pilotées par le défilement sont là, et ce n'est pas qu'une curiosité — c'est un véritable changement architectural qui pourrait rendre vos bibliothèques JavaScript de scroll préférées obsolètes. Voici ce que les benchmarks, la compatibilité navigateur et les patterns réels donnent vraiment.
Les effets de défilement cachent un sale secret. Chaque couche de parallaxe, chaque barre de progression de scroll, chaque révélation au défilement que vous avez mis en production était probablement accompagné d'un payload JavaScript qui ronge silencieusement le thread principal de vos utilisateurs.
ScrollTrigger de GSAP est brillant — personne ne le conteste. Mais c'est toujours du JavaScript qui s'exécute sur le thread principal, en concurrence avec la logique de votre application, vos balises analytics et les dix-sept autres bibliothèques que votre chef de produit a absolument tenu à inclure. Le thread du compositeur du navigateur — cette partie spécialement conçue pour un rendu visuel ultra-fluide — est resté largement inactif pendant que JS accomplissait une tâche lourde pour laquelle il n'a jamais été conçu.
Ça change. L'API CSS Scroll-Driven Animations vient de déplacer toute la conversation là où elle aurait toujours dû se trouver : le pipeline de rendu natif du navigateur.
Ce que fait réellement l'API Scroll-Driven Animations
Dans son essence, l'API Scroll-Driven Animations donne à CSS (et à une fine couche de JavaScript, si nécessaire) la capacité de lier directement les timelines d'animation à la position de défilement — sans aucun écouteur d'événement scroll, sans boucle requestAnimationFrame, sans layout thrashing.
L'API introduit deux nouveaux types de timelines :
ScrollTimeline— lie la progression d'une animation à la position de défilement d'un conteneurViewTimeline— lie la progression d'une animation à la position d'un élément dans un viewport de défilement (lorsqu'il entre, traverse et sort de la zone visible)
En CSS, cela paraît trompeusement simple :
@keyframes reveal {
from { opacity: 0; transform: translateY(40px); }
to { opacity: 1; transform: translateY(0); }
}
.card {
animation: reveal linear;
animation-timeline: view();
animation-range: entry 0% entry 40%;
}
C'est tout. Pas d'IntersectionObserver. Pas d'écouteur d'événement scroll. Pas de JavaScript du tout.
La différence architecturale cruciale : les animations pilotées par le défilement s'exécutent hors du thread principal dans les navigateurs compatibles. Le compositeur de Chrome prend entièrement en charge le travail, ce qui signifie que même si votre thread principal est bloqué par une longue tâche, vos animations de scroll continuent de tourner à 60 fps (ou 120 fps sur les écrans à haute fréquence de rafraîchissement). C'est un avantage qu'aucune solution JS basée sur un polyfill ne peut combler — car JavaScript lui-même est le goulot d'étranglement.
Compatibilité navigateur actuelle
A mi-2025, Chrome et Edge offrent un support complet (Chrome 115+). Firefox a livré le support derrière un flag et travaille activement à une version stable. Safari reste à la traîne — pas encore de support, bien que l'équipe WebKit ait reconnu la spécification.
Cela signifie que vous avez besoin d'une stratégie de repli aujourd'hui, mais la trajectoire est claire. La requête @supports et un shim JS léger (le polyfill scroll-driven-animations sur npm) peuvent combler le manque sans dégrader votre expérience utilisateur.
Benchmarks de performance : CSS vs. JS en face-à-face
Soyons concrets. Quand Bramus Van Damme (Google Chrome DevRel) a présenté l'API au Chrome Dev Summit, les données de frames racontaient une histoire saisissante. Mais vous n'avez pas besoin d'un keynote de conférence — vous pouvez reproduire cela vous-même dans DevTools.
Le scénario de test
Imaginez une page avec 20 cartes animées au scroll, chacune utilisant un effet de décalage parallaxe :
Implémentation avec GSAP ScrollTrigger :
- Attache un écouteur de scroll sur
window - À chaque événement scroll, itère sur 20 éléments
- Appelle
gsap.set()par élément, déclenchant un recalcul des styles - Profil de jank typique : 4–8 ms de scripting par événement scroll, avec des frames perdus occasionnels sur du matériel Android milieu de gamme
Implémentation avec CSS Scroll-Driven Animations :
- Zéro écouteur d'événement scroll
- Zéro exécution JavaScript pendant le défilement
- Exécution sur le thread du compositeur : 0 ms de scripting constant pendant le scroll
- Budget de temps par frame : effectivement identique à une page statique
La différence n'est pas marginale. Sur un appareil de type Moto G4 (le benchmark de throttling standard), les animations CSS pilotées par le défilement peuvent maintenir 60 fps là où GSAP ScrollTrigger descend à 40–45 fps sous charge réelle.
Ce n'est pas une attaque contre GSAP — c'est un problème de physique. La gestion du scroll en JavaScript a un plancher de coût incompressible en raison du fonctionnement de la boucle d'événements. CSS s'exécutant sur le compositeur n'a pas ce plancher.
Impact Lighthouse / INP : Avec le passage à Interaction to Next Paint comme Core Web Vital, les gestionnaires de scroll sur le thread principal sont un vrai sujet de classement. Les animations CSS de scroll ne s'inscrivent tout simplement pas dans votre budget INP.
5 patterns d'implémentation réels à réutiliser dès aujourd'hui
1. Barre de progression de défilement
Le grand classique. Une fine barre en haut de la page qui se remplit au fil du défilement.
#progress-bar {
position: fixed;
top: 0; left: 0;
width: 100%; height: 4px;
background: linear-gradient(to right, #6366f1, #8b5cf6);
transform-origin: left;
animation: progress-grow linear;
animation-timeline: scroll(root block);
}
@keyframes progress-grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
Cela nécessitait auparavant un écouteur de scroll et un calcul manuel de la largeur. Maintenant, c'est huit lignes de CSS.
2. Arrière-plans en parallaxe
Utilisez view() avec un animation-range négatif pour créer l'effet de décalage parallaxe quand une section entre dans le viewport :
.hero-bg {
animation: parallax-shift linear;
animation-timeline: view();
animation-range: cover;
}
@keyframes parallax-shift {
from { transform: translateY(-20%); }
to { transform: translateY(20%); }
}
3. Révélations sticky liées au scroll
Animez du contenu en position: sticky en fonction de la progression de l'utilisateur dans une section :
.sticky-label {
animation: fade-up linear both;
animation-timeline: view();
animation-range: entry 10% entry 60%;
}
4. Galerie à défilement horizontal
L'un des patterns les plus délicats en JS devient déclaratif :
.gallery-track {
animation: slide-horizontal linear;
animation-timeline: scroll(nearest inline);
}
@keyframes slide-horizontal {
from { transform: translateX(0); }
to { transform: translateX(-66.6%); }
}
5. Entrée de cartes en cascade
Combinez ViewTimeline avec les propriétés personnalisées CSS et animation-delay pour créer des effets d'entrée en cascade sans une seule ligne de JavaScript :
.card:nth-child(1) { --delay: 0ms; }
.card:nth-child(2) { --delay: 80ms; }
.card:nth-child(3) { --delay: 160ms; }
.card {
animation: card-enter linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
animation-delay: var(--delay);
}
Accessibilité, compatibilité navigateur et cas limites à connaître
prefers-reduced-motion est non négociable
Les animations pilotées par le défilement sont du mouvement par définition. Pour les utilisateurs souffrant de troubles vestibulaires ou de sensibilités au mouvement, un défilement animé non sollicité peut provoquer un véritable inconfort physique.
Encadrez toutes vos déclarations d'animation de scroll :
@media (prefers-reduced-motion: no-preference) {
.card {
animation: reveal linear;
animation-timeline: view();
}
}
Ne réduisez pas seulement le mouvement — supprimez-le entièrement pour les utilisateurs qui ont choisi de l'éviter. Une animation plus subtile reste une animation qu'ils n'ont pas demandée.
L'écart du polyfill
Pour Safari et Firefox stable, utilisez le polyfill @scroll-driven-animations. Il se replie sur une approche ResizeObserver + écouteur de scroll, qui évidemment ne vous offre pas les avantages hors thread principal — mais assure une parité visuelle. Considérez-le comme une couche de dégradation gracieuse, pas comme une solution permanente.
Cas limites qui méritent d'être testés
- Scrollers imbriqués :
scroll()etview()ciblent par défaut le scroller ancêtre le plus proche. Soyez explicite avecscroll(root)vs.scroll(nearest)quand votre mise en page est complexe. animation-fill-mode: Utilisezbothpour garantir que les éléments démarrent dans leur étatfromavant que la plage d'animation ne soit atteinte.- Contenu dynamique : Si la hauteur de votre conteneur de scroll change après le chargement (images chargées en lazy, contenu CMS), la timeline d'animation se recalcule automatiquement — mais vérifiez que cela ne provoque pas de FOUC dans votre mise en page spécifique.
Quand les bibliothèques JavaScript de scroll restent le bon outil
Ce n'est pas un manifeste contre GSAP. Il existe encore des scénarios clairs où se tourner vers ScrollTrigger ou Lenis est la bonne décision :
- Séquences orchestrées complexes où plusieurs éléments s'animent en réponse à un seul déclencheur de scroll avec un timing interdépendant
- Scroll-jacking / défilement à inertie de type locomotive — l'API ne contrôle pas le comportement du scroll, seulement l'état de l'animation
- Parité cross-browser aujourd'hui sans stratégie de polyfill, notamment pour les audiences à forte proportion d'utilisateurs Safari (vous voyez de qui je parle : finance grand public et e-commerce de luxe)
- Sections de scroll épinglées avec des machines à états complexes qui dépassent ce que les keyframes CSS peuvent exprimer proprement
- Scrubbing de timeline lié à des entrées non-scroll (position de la souris, gyroscope, etc.)
Le cadre honnête : si votre animation peut s'exprimer comme « l'état visuel de cet élément est une fonction pure de la position de défilement », CSS gagne. Si votre animation nécessite des conditions, un séquençage d'événements ou des entrées non-scroll, JavaScript reste votre outil.
Conclusion : est-ce le début de la fin pour ScrollTrigger ?
Pas encore — mais le plafond se rapproche.
L'API CSS Scroll-Driven Animations ne remplace pas GSAP ScrollTrigger comme React a remplacé jQuery. Elle remplace un pattern d'utilisation spécifique — le retour visuel passif lié à la position — par une solution native considérablement plus performante. Et ce pattern couvre probablement 60 à 70 % des usages réels des bibliothèques de scroll en production.
Les développeurs qui tireront leur épingle du jeu au cours des deux prochaines années sont ceux qui privilégient d'abord le natif, n'ajoutent du JavaScript que là où il justifie son poids dans le bundle, et construisent des architectures d'animation qui ne prennent pas la performance en otage de décisions prises en 2019.
Shippez une barre de progression de scroll en CSS aujourd'hui. Construisez votre prochaine section parallaxe sans un seul addEventListener. Lancez la trace DevTools et regardez votre thread principal se taire pendant le défilement pour la première fois.
Puis demandez-vous si cette dépendance GSAP mérite encore sa place dans votre bundle.
Le navigateur est plus capable que ce que votre configuration de build suppose. Il est temps de le laisser faire son travail.
