Animer au défilement sans une ligne de JavaScript
Les animations liées au défilement se font désormais en CSS pur. Ce que cela change, ce que cela coûte, et le piège dans lequel nous sommes tombés en refaisant ce site.
Pendant quinze ans, faire apparaître un bloc quand il entre dans la fenêtre a demandé du JavaScript. D’abord un écouteur sur l’événement de défilement, ce qui donnait des pages qui saccadaient. Puis l’IntersectionObserver, plus propre, mais qui reste du code à charger, à exécuter et à maintenir. Presque personne ne l’écrivait à la main : on installait une bibliothèque de trente à cinquante kilo-octets, pour un effet de fondu.
Ce détour n’est plus nécessaire. Le CSS sait brancher une animation sur la position d’un élément dans la fenêtre plutôt que sur l’horloge.
Ce que fait la propriété
Une animation CSS ordinaire se déroule dans le temps : elle dure une seconde, puis elle est finie. animation-timeline remplace cette horloge par autre chose. Avec view(), l’avancement de l’animation ne dépend plus des secondes écoulées mais de la position de l’élément par rapport à la fenêtre : à l’entrée, l’animation est au début ; à mesure que l’élément monte, elle progresse ; le lecteur qui remonte la page la fait reculer.
@keyframes monter {
from { opacity: 0; transform: translateY(1.25rem); }
to { opacity: 1; transform: none; }
}
.bloc {
animation: monter linear both;
animation-timeline: view();
animation-range: entry 0% cover 32%;
}
C’est tout. Pas de script, pas d’observateur, pas de classe ajoutée par JavaScript. Et surtout : l’animation tourne sur le fil de composition du navigateur, pas sur le fil principal, ce qui veut dire qu’elle continue d’être fluide même quand la page fait autre chose en même temps.
La ligne qui compte le plus est la troisième. Sans animation-range, l’animation est branchée sur toute la traversée de l’écran : le bloc réapparaît en fondu inversé quand il sort par le haut, ce que tout le monde interprète comme un bogue.
Où c’est utilisable
Au 27 juillet 2026, la situation est franchement asymétrique.
Chrome et Edge livrent les animations de défilement depuis l’été 2023. Safari les a livrées dans sa version 26, sortie en septembre 2025, et WebKit en a publié un guide complet. Firefox ne les a pas encore livrées en version stable : MDN indique explicitement que la propriété n’est pas au niveau de référence commun, précisément pour cette raison.
Ce qui ne veut pas dire qu’on ne peut pas s’en servir, à une condition : que la page sans animation reste une page finie.
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
/* les animations vivent ici, et nulle part ailleurs */
}
}
L’état de repos doit être l’état visible, et l’animation ne fait que partir d’ailleurs pour y revenir. Un navigateur qui ignore le bloc affiche la page terminée. Si on écrit l’inverse, en posant opacity: 0 par défaut pour le relever ensuite, un lecteur sous Firefox se retrouve devant une page blanche. Cette faute se voit tous les jours sur des sites construits avec une bibliothèque mal configurée.
Le second garde-fou est aussi important que le premier. Une animation d’apparition non coupée sous prefers-reduced-motion provoque des nausées chez les personnes sujettes au mal des transports. Ce n’est pas une politesse, c’est un critère d’accessibilité, et il se respecte en une ligne.
Le piège dans lequel nous sommes tombés
Nous avons refait ce site avec cette technique. Le premier essai a produit une illustration à moitié dessinée, figée, qui refusait de se terminer quelle que soit la manière de faire défiler la page.
L’explication est évidente une fois trouvée. L’illustration se trouve dans l’en-tête, donc au-dessus de la ligne de flottaison. Une animation branchée sur view() sur un élément déjà visible au chargement se règle immédiatement sur l’avancement que sa position lui donne, et n’en bouge plus tant qu’on ne fait pas défiler la page. Comme l’élément est en haut, cet avancement vaut à peu près la moitié. Le dessin restait donc à moitié tracé, ce qui ressemblait à un bogue de rendu alors que c’était le comportement exactement conforme à ce que nous avions demandé.
La règle qui en sort tient en une phrase : on ne branche sur le défilement que ce qui est réellement plus bas dans la page. Ce qui est visible au chargement s’anime sur l’horloge, avec une durée et un délai, comme avant.
Ce que cela vaut
Nous avons remplacé une bibliothèque d’apparition au défilement par environ huit cents octets de CSS. Ce site charge aujourd’hui zéro fichier JavaScript, et il a plus de mouvement qu’avant.
C’est le genre d’avancée que nous cherchons : pas celle qui permet de faire une chose de plus, celle qui permet de retirer quelque chose.