Regardez en haut de votre écran pendant que vous lisez : une fine barre vermillon avance au rythme de votre lecture. Elle ne contient pas une ligne de JavaScript. C'est le premier exemple de ce tutoriel, et il résume ce qui a changé : des effets qui demandaient hier une librairie et des écouteurs de défilement tiennent aujourd'hui en quelques lignes de CSS.
Le dernier verrou saute ce mois-ci. D'après les données de compatibilité de MDN, les animations pilotées par le défilement fonctionnent dans Chrome et Edge depuis la version 115, dans Safari depuis la version 26, et arrivent dans Firefox 159, attendu le 27 octobre 2026. Pour la première fois, on peut les utiliser en considérant qu'elles marcheront chez presque tout le monde.
Avant le code : une animation doit expliquer quelque chose
Le motion design est l'endroit où un site passe le plus facilement de « soigné » à « fatigant ». Avant d'écrire la moindre ligne, on se fixe quatre règles :
- Chaque animation explique : une continuité (cette vignette devient cette page), un ordre de grandeur (cette barre est trois fois plus longue), un changement d'état (votre demande est partie). Si elle n'explique rien, on la retire.
- Rien ne retarde le contenu : le titre et le haut de page ne sont jamais masqués en attendant une animation.
- Courte et discrète : entre 150 et 400 millisecondes pour une interaction, des déplacements de quelques pixels.
- Le mouvement est une option : les personnes qui ont demandé moins d'animations à leur système doivent recevoir une page immobile et complète.
1. Une barre de progression de lecture
L'effet de base des animations liées au défilement. Une timeline de défilement, scroll(), remplace la durée en secondes : l'animation avance quand la page défile, et recule quand elle remonte.
.progress {
position: fixed;
top: 0; left: 0; right: 0;
height: 3px;
background: #E8481F;
transform-origin: 0 50%;
animation: grow linear both;
animation-timeline: scroll(root block);
}
@keyframes grow {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
Un piège à connaître : animation-timeline doit être écrit après le raccourci animation, qui le remet à zéro sinon. C'est l'erreur la plus fréquente quand « rien ne se passe ».
2. Révéler les contenus au défilement
Deuxième timeline : view(). Elle suit la position d'un élément dans la fenêtre, de son entrée par le bas à sa sortie par le haut. La propriété animation-range choisit le segment de ce trajet sur lequel l'animation se joue.
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.card {
animation: rise linear both;
animation-timeline: view();
animation-range: entry 0% entry 40%;
}
}
}
@keyframes rise {
from { opacity: .2; translate: 0 18px; }
to { opacity: 1; translate: 0 0; }
}
Trois choix comptent ici. entry 0% entry 40% signifie : de l'instant où la carte touche le bas de l'écran jusqu'à ce qu'elle soit entrée aux deux cinquièmes ; l'effet est fini bien avant qu'on la lise. L'opacité part de 0,2 et non de 0 : si l'animation ne se joue pas, le contenu reste lisible. Et tout est encadré par @supports et prefers-reduced-motion : sans support ou sans envie de mouvement, la carte est simplement là.
Pour décaler les cartes d'une grille, on décale leur plage plutôt que d'ajouter des délais : .card:nth-child(2) { animation-range: entry 6% entry 46%; }.
3. Des transitions entre les pages, sans application JavaScript
Les View Transitions animent le passage d'une page à l'autre. Sur un site classique, où chaque lien charge une nouvelle page, il suffit que les deux pages contiennent cette règle :
@view-transition {
navigation: auto;
}
Le navigateur capture l'ancienne et la nouvelle page, puis enchaîne les deux par un fondu. Pour qu'un élément se transforme d'une page à l'autre, par exemple une vignette qui devient l'image principale de la page suivante, on donne le même nom aux deux éléments :
/* Sur la liste */
.thumb-projet-a { view-transition-name: projet-a; }
/* Sur la page du projet */
.hero-projet-a { view-transition-name: projet-a; }
Un nom doit être unique dans la page : sur une liste, on le génère à partir de l'identifiant de chaque élément. Côté navigateurs, ces transitions entre pages fonctionnent dans Chrome depuis la version 126 et dans Safari depuis la version 18.2 ; Firefox prend en charge les transitions à l'intérieur d'une même page depuis la version 144, mais pas encore entre deux pages. Ailleurs, la navigation reste instantanée, comme avant : rien ne casse.
4. Ouvrir une FAQ en douceur
Animer l'ouverture d'un <details> vers sa hauteur réelle était impossible en CSS, parce qu'on ne pouvait pas animer vers height: auto. Deux nouveautés règlent le problème : le pseudo-élément ::details-content, qui cible le contenu repliable, et interpolate-size, qui autorise l'animation vers auto.
:root { interpolate-size: allow-keywords; }
details::details-content {
block-size: 0;
overflow: clip;
transition: block-size .25s ease-out,
content-visibility .25s allow-discrete;
}
details[open]::details-content {
block-size: auto;
}
::details-content fonctionne dans Chrome, Firefox et Safari, mais interpolate-size n'existe pour l'instant que dans Chrome. Ailleurs, la FAQ s'ouvre instantanément, exactement comme sans ce code. C'est le principe qui rend ces techniques sûres : chaque couche s'ajoute sans rien retirer.
5. Animer une apparition avec @starting-style
Un élément qui passe de display: none à visible, comme un menu ou une fenêtre de dialogue, apparaissait jusqu'ici d'un coup : une transition CSS n'a pas d'état de départ quand l'élément n'existait pas encore à l'écran. @starting-style fournit cet état de départ, et allow-discrete permet d'animer display lui-même.
.panel {
opacity: 1;
transition: opacity .2s, display .2s allow-discrete;
}
@starting-style {
.panel { opacity: 0; }
}
.panel[hidden] {
display: none;
opacity: 0;
}
C'est la technique la mieux prise en charge des cinq : Chrome 117, Firefox 129, Safari 17.5. MDN la classe « Baseline » depuis août 2024.
L'accessibilité n'est pas une option
Certaines personnes, notamment celles qui souffrent de troubles vestibulaires, ressentent des vertiges ou des nausées face aux mouvements à l'écran. Elles peuvent demander à leur système de réduire les animations, et le site le lit avec prefers-reduced-motion. Les critères d'accessibilité du W3C (WCAG 2.3.3) demandent d'ailleurs que les animations déclenchées par une interaction puissent être désactivées.
Le plus sûr est d'inverser la logique : n'activer le mouvement que pour ceux qui ne l'ont pas refusé, comme dans les exemples ci-dessus avec no-preference. Pour les transitions de page, une ligne suffit :
@media (prefers-reduced-motion: reduce) {
@view-transition { navigation: none; }
}
Ce que font de vrais sites
Ces techniques ne sont plus des démos. Le blog Chrome for Developers a publié des études de cas d'entreprises qui les ont mises en production :
- Tokopedia (e-commerce) utilise les animations liées au défilement pour sa barre de navigation et l'apparition de ses fiches produits. Selon l'entreprise, le code a diminué de jusqu'à 80 % par rapport à sa version JavaScript, et l'utilisation moyenne du processeur pendant le défilement est passée d'environ 50 % à 2 % (étude de cas).
- redBus (réservation de bus) anime ses changements de page dans le tunnel de réservation, avec un glissement dans le sens de la navigation ; CyberAgent fait grandir l'image d'un article de la liste jusqu'à la page de lecture, sur mobile uniquement, l'effet étant jugé trop chargé sur ordinateur (étude de cas).
Pour s'entraîner, le site scroll-driven-animations.style, tenu par Bramus, ingénieur chez Google, rassemble des démos commentées : barre de progression, carrousel, en-tête qui rétrécit, cartes qui s'empilent. Chaque démo existe en version CSS et en version JavaScript.
Ce qu'on a appris en l'appliquant à notre propre site
Nous avons refait le motion de waikuu.com avec exactement ces techniques, sans librairie. La frise de notre méthode se trace au défilement, les barres du comparatif de prix se remplissent à l'échelle avant que les montants n'apparaissent, la vignette d'une réalisation s'agrandit jusqu'à la page du projet, et nos FAQ s'ouvrent en douceur.
Une erreur nous a appris quelque chose. Sur mobile, la dernière étape de la frise restait grise alors que la frise était entièrement à l'écran. Nos plages étaient calculées sur cover, c'est-à-dire sur toute la traversée de l'écran : l'animation ne se terminait qu'une fois la frise remontée sous l'en-tête. En la recalant sur entry, l'entrée de la frise dans l'écran, tout est tracé au moment où on la regarde. La leçon vaut pour tous les effets de ce type : testez sur un vrai format mobile, où les proportions entre l'élément et l'écran n'ont rien à voir avec celles d'un ordinateur.
Le bon motion design ne se remarque pas. On se souvient seulement que le site était clair.
Pour aller plus loin sur ce qui fait qu'une interface convertit, lisez notre dossier design UX et conversion. Et si votre site mérite des animations qui servent vraiment vos visiteurs, parlons-en.