Blanche
Blanche Agency

Blanche · Studio

© 2026

Les animations CSS au scroll arrivent — et elles sont sur le point de mettre à la retraite la moitié de votre codebase JavaScript
Retour au blog
Développement WebOptimisation des performancesConception de mouvement9 avril 2026·10 min de lecture

Les animations CSS au scroll arrivent — et elles sont sur le point de mettre à la retraite la moitié de votre codebase JavaScript

La spécification CSS des animations pilotées par le défilement est désormais disponible dans les principaux navigateurs — et elle déplace entièrement le parallaxe, les animations d'apparition et les indicateurs de progression hors du thread principal. Voici ce que cela signifie pour votre codebase, la taille de vos bundles et vos scores Lighthouse.

Chaque écouteur de défilement que vous avez jamais écrit est un petit acte de violence contre le thread principal.

C'est une affirmation provocatrice, mais les données de profilage la confirment. Dans un build d'agence typique, les animations pilotées par le défilement — le hero parallaxe, les révélations de cartes en cascade, la barre de progression de lecture — peuvent représenter 30 à 60 % du temps d'exécution JavaScript lors des interactions utilisateur actives. Le ScrollTrigger de GSAP est une ingénierie brillante. L'Intersection Observer a représenté une avancée significative. Mais tous deux se heurtent à une contrainte architecturale fondamentale : JavaScript vit sur le thread principal, et le thread principal est déjà saturé.

La spécification CSS des animations pilotées par le défilement change complètement la donne. Disponible depuis Chrome 115+, Edge 115+ et en cours d'adoption ailleurs, elle déplace les animations liées au défilement hors du thread principal vers le compositeur du navigateur — la même voie rapide où will-change: transform et les transitions CSS ont toujours fonctionné. Le résultat : une chorégraphie de défilement qui se moque de l'état de congestion de votre thread principal, ne coûte zéro octet de JavaScript, et s'exprime entièrement en CSS.

Voici ce que cela signifie concrètement pour vos projets.


L'impôt caché sur les performances des animations JavaScript au défilement

Avant de célébrer, il vaut la peine d'être précis sur pourquoi les animations JS au défilement ont toujours été un compromis.

Lorsque vous écrivez window.addEventListener('scroll', handler), vous enregistrez un callback qui s'exécute sur le thread principal. Chaque pixel défilé déclenche votre handler, qui lit les propriétés du DOM (forçant souvent un recalcul de mise en page), calcule de nouvelles valeurs et applique des styles — tout cela en compétition avec le parsing HTML, d'autres scripts et le garbage collection pour le même budget de 16ms par image.

Même avec passive: true et le regroupement via requestAnimationFrame, vous effectuez toujours des tâches sur le thread principal qui n'ont architecturalement pas besoin d'y être.

Le thread du compositeur est la voie rapide du navigateur. Il gère les transformations accélérées par GPU et les changements d'opacité sans toucher au thread principal. JavaScript ne peut pas s'y exécuter. CSS, oui.

L'Intersection Observer a représenté une véritable amélioration — il permettait de déclencher des animations en fonction de la position de défilement sans interrogation continue. Mais il est fondamentalement binaire : les éléments sont soit en intersection, soit ils ne le sont pas. Piloter un effet parallaxe fluide lié à un pourcentage nécessite d'y superposer du JavaScript supplémentaire, ce qui vous ramène exactement au point de départ.

C'est précisément le vide architectural que animation-timeline: scroll() a été conçu pour combler.


Comment fonctionnent réellement les animations CSS pilotées par le défilement

La spécification introduit deux nouveaux types de timelines d'animation qui remplacent la notion de temps par celle de progression du défilement.

Timelines de progression du défilement — scroll()

@keyframes reveal {
  from { opacity: 0; transform: translateY(40px); }
  to   { opacity: 1; transform: translateY(0); }
}

.card {
  animation: reveal linear;
  animation-timeline: scroll(root);
  animation-range: entry 0% entry 100%;
}

Ici, la tête de lecture de l'animation est pilotée par la position de défilement plutôt que par le temps écoulé. À mesure que l'utilisateur fait défiler de 0 % à 100 % du document, l'animation progresse de from à to. Aucun écouteur d'événement. Aucun requestAnimationFrame. Aucun JavaScript, point.

La fonction scroll() accepte deux arguments optionnels : une référence au conteneur de défilement (root, nearest ou un conteneur nommé) et un axe (block, inline, x, y).

Timelines de progression de la vue — view()

.section {
  animation: fade-in linear both;
  animation-timeline: view();
  animation-range: entry 10% cover 40%;
}

view() lie l'animation à la position d'un élément au sein d'un conteneur de défilement — considérez-le comme le frère plus expressif de l'Intersection Observer. La propriété animation-range vous offre une précision chirurgicale : entry, exit, cover et contain sont tous des mots-clés de plage valides, et vous pouvez y superposer des décalages en pourcentage pour affiner exactement les fenêtres de déclenchement.

Timelines nommées pour l'orchestration multi-couches

Pour piloter plusieurs éléments enfants à partir de la progression de défilement d'un seul parent — le scénario classique du parallaxe — vous pouvez déclarer une timeline nommée sur le conteneur :

.parallax-wrapper {
  scroll-timeline-name: --parallax-scene;
  scroll-timeline-axis: block;
}

.layer-slow {
  animation: drift-slow linear both;
  animation-timeline: --parallax-scene;
}

.layer-fast {
  animation: drift-fast linear both;
  animation-timeline: --parallax-scene;
}

C'est l'équivalent CSS de l'option scrub de GSAP — et cela s'exécute entièrement hors du thread principal.


Benchmarks : CSS vs. JS sur des interactions de défilement réelles

Voici des chiffres concrets issus de sessions de profilage dans Chrome DevTools.

Scénario de test : Une landing page marketing avec 8 sections, chacune contenant une révélation en cascade de 4 cartes plus une barre de progression de lecture fixe. Testé sur un appareil Android milieu de gamme.

MétriqueGSAP ScrollTriggerCSS Scroll-Driven
Exécution JS par événement de défilement~2,4ms0ms
Blocage du thread principal pendant le défilement18–22ms<1ms
Promotions de couches compositeurManuelle (will-change)Automatique
Images perdues lors d'un défilement rapide6–120–1
Impact sur la taille du bundle+67Ko (GSAP + ST)0Ko

Ce coût d'exécution JS de 2,4ms semble anodin isolément. Mais à 60fps, l'intégralité de votre budget par image est de 16ms. Une page à fort défilement avec plusieurs handlers empile ces coûts rapidement — ce qui se manifeste exactement comme des saccades sur les appareils d'entrée de gamme. L'approche CSS ne réduit pas simplement ce coût. Elle le supprime entièrement du budget du thread principal.


Modèles d'implémentation pour les cas d'usage courants en agence

1. Indicateur de progression de lecture

La vitrine canonique — une barre de progression qui se remplit au fil de la lecture :

@keyframes grow-bar {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.progress-bar {
  position: fixed;
  top: 0; left: 0;
  width: 100%; height: 4px;
  background: var(--accent);
  transform-origin: left center;
  animation: grow-bar linear;
  animation-timeline: scroll(root block);
}

Cinq lignes de CSS. Auparavant, c'était un écouteur de défilement, un calcul de scrollHeight et une mutation de style à chaque image.

2. Couches parallaxe

@keyframes parallax-slow {
  from { transform: translateY(0); }
  to   { transform: translateY(-120px); }
}

.hero-bg {
  animation: parallax-slow linear both;
  animation-timeline: view();
  animation-range: cover 0% cover 100%;
}

Ajustez la magnitude du translateY par couche pour contrôler la profondeur perçue. Empilez trois ou quatre éléments à des vitesses différentes et vous obtenez un véritable parallaxe — sans aucun JavaScript.

3. Révélations de sections en cascade

.feature-item {
  opacity: 0;
  animation: slide-up linear forwards;
  animation-timeline: view();
  animation-range: entry 15% entry 65%;
}

.feature-item:nth-child(2) { animation-delay: 0.08s; }
.feature-item:nth-child(3) { animation-delay: 0.16s; }
.feature-item:nth-child(4) { animation-delay: 0.24s; }

Combinez les timelines view() avec animation-delay pour une chorégraphie en cascade. Pour les listes générées dynamiquement, une touche de style inline définissant une propriété personnalisée --stagger-index et un délai calc() permet de rester évolutif sans toucher à JavaScript.


Support navigateur, fallbacks et amélioration progressive

Soyons honnêtes sur le paysage actuel : ce n'est pas une spécification à déployer partout aujourd'hui en fin 2024. Voici la réalité :

  • Chrome 115+ / Edge 115+ : Support complet
  • ⚠️ Firefox : Derrière un flag, support stable attendu prochainement
  • Safari : Pas encore supporté à partir de Safari 17

Pour les agences qui livrent des projets en production, l'amélioration progressive est non négociable. Voici le modèle :

/* État de base — entièrement visible, sans dépendance à l'animation */
.card {
  opacity: 1;
  transform: none;
}

/* Expérience enrichie conditionnée par le support de la fonctionnalité */
@supports (animation-timeline: scroll()) {
  .card {
    opacity: 0;
    animation: reveal linear both;
    animation-timeline: view();
    animation-range: entry 10% entry 60%;
  }
}

La requête @supports isole proprement la couche enrichie. Les navigateurs non supportés voient l'état de base — contenu entièrement visible, mise en page intacte, zéro expérience cassée.

Ne déployez pas le polyfill universellement. Un polyfill pour les animations pilotées par le défilement existe et fonctionne bien, mais le charger pour les utilisateurs Chrome qui n'en ont pas besoin efface les gains de performances que vous recherchez. Utilisez CSS.supports('animation-timeline', 'scroll()') en JavaScript pour le charger conditionnellement uniquement là où c'est nécessaire.


Migrer depuis ScrollTrigger : une checklist pratique

Si votre équipe dispose d'une implémentation GSAP ScrollTrigger existante, voici un chemin de migration réaliste :

  1. Auditez par type d'animation. Séparez les animations liées au scrub (parallaxe, barres de progression) des animations déclenchées à l'entrée (révélations, compteurs). Les premières se mappent directement aux timelines CSS de défilement. Les secondes peuvent utiliser des timelines view() ou se rabattre sur l'Intersection Observer pour le déclenchement de classes.

  2. Identifiez les animations dépendantes du JS. Si une animation repose sur des valeurs calculées à l'exécution — hauteurs de contenu dynamiques, dimensions de la fenêtre, vélocité de l'utilisateur — gardez-la en JavaScript. Les timelines CSS de défilement excellent dans le mouvement défini à la conception, pas dans les décalages calculés à l'exécution.

  3. Migrez un composant à la fois. Commencez par la barre de progression de lecture. C'est un gain rapide garanti. Livrez-la, profilez-la, vérifiez le fallback, gagnez en confiance avant une réécriture globale.

  4. Chargez GSAP conditionnellement. Une fois suffisamment de composants migrés, encapsulez votre import GSAP : chargez-le uniquement quand !CSS.supports('animation-timeline', 'scroll()'). Votre bundle pour navigateurs modernes rétrécit immédiatement.

  5. Profilez avant et après. Capturez une trace de défilement dans le panneau Performance de Chrome avant et après la migration. La chute de l'exécution JS sur le thread principal est saisissante et constitue des données convaincantes lorsque vous justifiez la refactorisation auprès d'un responsable technique ou d'un client.


Est-il temps de déprécier vos bibliothèques de défilement ?

Pas entièrement — et pas en une seule fois. Le ScrollTrigger de GSAP conserve l'avantage pour les chorégraphies multi-éléments très séquencées où la logique JavaScript effectue déjà le gros du travail. La morphologie SVG complexe synchronisée avec le défilement, les expériences narratives à défilement contrôlé ou les animations qui répondent à la vélocité de l'utilisateur sont des cas légitimes où JavaScript reste l'outil approprié.

Mais pour les 80 % des animations de défilement que les agences livrent sur chaque projet — révélations de cartes, couches parallaxe, indicateurs de progression, transitions de sections — les animations CSS natives pilotées par le défilement sont désormais le choix supérieur sur les navigateurs compatibles. Plus rapides. Plus simples. Zéro coût de bundle.

La décision avisée en ce moment est une migration délibérée et progressive : les animations CSS au défilement comme choix par défaut pour les navigateurs modernes, des fallbacks légers pour les autres, et un abandon progressif des dépendances aux bibliothèques de défilement à mesure que Safari rattrapera son retard.

La spécification est là. Les gains de performances sont réels et mesurables. La question n'a jamais été de savoir si l'adopter — seulement à quelle vitesse votre équipe peut avancer.

Commencez avec un seul composant. Livrez-le ce sprint. Votre thread principal va enfin pouvoir se reposer.