Heritiana Antonio Frond end Designer | Developer

Hello, I am

Heritiana Antonio

Frond end Designer | Developer

Firefox 159 : animation-timeline remplace-t-il un écouteur de scroll ?

1 min de lecture

Feuille de papier écru et fil turquoise sur une table en chêne, sans texte

Firefox 159 : animation-timeline remplace-t-il un écouteur de scroll ?

Le 27 octobre 2026, Firefox 159 active par défaut les animations pilotées par le défilement. La propriété animation-timeline peut suivre la position d’un scroll ou la traversée d’un élément dans la zone visible. Elle retire le JavaScript d’une barre de lecture et d’une entrée d’image. Elle ne retire pas un écouteur qui charge une page, écrit un pourcentage ou mesure une audience.

Cet article ne couvre que ce remplacement. Firefox 159 livre aussi, le même jour, les registres d’éléments personnalisés cloisonnés et des changements WebGL. Ce n’est pas le sujet.

Ce que Firefox 159 active vraiment

animation-timeline choisit la timeline d’une animation CSS. auto suit le temps écoulé depuis le chargement. scroll() suit la position d’un défilement. view() suit la visibilité d’un élément dans son conteneur défilant. none retire toute timeline : l’animation ne joue pas.

Les notes de version Firefox 159, canal Release, datent du 27 octobre 2026. Le passage Web Platform y ajoute animation-timeline, scroll-timeline, view-timeline, animation-range, ainsi que les interfaces ScrollTimeline et ViewTimeline de l’API Web Animations. La note MDN du même jour relie l’activation au bogue 1324602 : ce n’était plus une préférence cachée.

Les autres moteurs l’avaient déjà. Les tableaux publics relus le 30 octobre 2026 placent Chrome 115 au 18 juillet 2023, Edge 115 au 21 juillet 2023 et Safari 26 au 15 septembre 2025, sur ordinateur comme sur mobile. Firefox était le moteur manquant.

Deux limites empêchent de dire « tous les Firefox ». L’ESR du 27 octobre 2026 est Firefox 153.6.0, sur la base 153 : il n’a pas cette activation. La page MDN de animation-timeline, lue le 30 octobre, affichait encore une disponibilité limitée. La date fiable est la note Mozilla, pas un tableau en retard.

scroll() et view() ne répondent pas à la même question

scroll() mesure un défilement. scroll(root block) suit le document, dans l’axe de bloc, en pratique la verticale d’une page. scroll(nearest inline) suit le défilement horizontal du conteneur ancêtre le plus proche. scroll(self) suit le défilement de l’élément lui-même. Sans argument, la fonction prend le conteneur le plus proche et l’axe de bloc.

view() ne mesure pas « combien la page a défilé ». Elle mesure où en est un élément dans la zone visible. À 0 %, il commence à entrer. À 100 %, il a fini d’en sortir, sauf si animation-range raccourcit cet intervalle. Le sujet par défaut est l’élément qui porte l’animation.

Une barre de lecture du document appelle scroll(root). Une image qui se pose pendant qu’elle entre dans l’écran appelle view() et animation-range: entry. Mélanger les deux produit une animation qui dure tout le temps où la page défile, alors qu’on voulait un geste d’entrée.

Retirer l’écouteur d’une barre de lecture

Le script habituel divise scrollY par la hauteur défilable, puis écrit un scaleX. Pour un trait en haut de page, scroll(root block) fait le même travail sans rappel.

.reading-bar {
  position: fixed;
  z-index: 2;
  inset-inline: 0;
  top: 0;
  height: 0.25rem;
  background: #1d4e4a;
  transform-origin: left center;
  animation: reading-bar-fill linear 1ms both;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

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

@supports not (animation-timeline: scroll()) {
  .reading-bar { display: none; }
}

Le trait est décoratif. La barre de défilement du navigateur expose déjà la position aux outils d’assistance. On cache donc ce trait avec aria-hidden="true", sans rôle progressbar : un rôle de progression exigerait une valeur mise à jour, ce que CSS ne fait pas.

MDN demande encore une durée explicite : une durée nulle peut empêcher Firefox d’appliquer l’animation. 1ms tient dans le raccourci. animation-duration: auto, déclaré après, étend l’animation sur toute la timeline là où le mot-clé est reconnu. S’il est ignoré, la milliseconde reste. Ces durées ne sont pas une horloge. La position dans la page décide de l’avancement. Une durée en millisecondes peut toutefois, sur view(), tasser l’effet vers la fin.

On anime transform ou opacity. width, height, top et left recalculent la mise en page à chaque étape. transform-origin: left center vise une page de gauche à droite : left ne suit pas le sens d’écriture.

Laisser une image entrer, sans masquer un lien

Une carte qui contient un lien ne doit pas partir de opacity: 0. L’opacité nulle ne sort pas le lien de l’ordre du clavier : on peut tabuler vers un contrôle invisible. On anime l’image, pas la carte, et on se contente d’une translation courte.

.card img {
  animation: card-rise linear 1ms both;
  animation-duration: auto;
  animation-timeline: view();
  animation-range: entry;
}

@keyframes card-rise {
  from { transform: translateY(1rem); }
  to { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .card img {
    animation: none;
    transform: none;
  }
}

animation-range: entry équivaut à entry 0% puis entry 100% : le geste ne dure que l’entrée, pas toute la traversée. both dans le raccourci applique l’image de départ avant la plage et fige l’arrivée après. Sans ce mode, l’image reprend son style dès la fin de entry et le geste saute. Une image déjà visible au chargement a en général fini son entrée : both la laisse en place. prefers-reduced-motion: reduce coupe ce déplacement. La barre de lecture, fixe et informative, peut rester.

Le raccourci animation annule la timeline

C’est le piège qui fait croire que Firefox « ne supporte pas ». animation-timeline fait partie du raccourci animation en valeur de réinitialisation seulement. On ne peut pas y glisser scroll(). Écrire le raccourci après la timeline remet animation-timeline à auto, donc au temps. L’animation redevient une animation d’une milliseconde, invisible.

/* La deuxième ligne efface la première. */
.reading-bar {
  animation-timeline: scroll(root block);
  animation: reading-bar-fill linear 1ms both;
}

L’ordre sûr est l’inverse : animation, puis animation-duration s’il faut ajouter auto, puis animation-timeline, puis animation-range. Les propriétés longues ne remettent pas la timeline à auto. Seul le raccourci le fait. Un mixin Sass qui réécrit animation après coup annule le même travail.

Un nom de timeline ne traverse pas les frères

Un nom déclaré avec scroll-timeline-name ou view-timeline-name n’est visible que sur l’élément qui le porte et sur ses descendants. Un indicateur placé à côté d’une galerie horizontale, et non dedans, ne voit pas --galerie. L’animation n’est alors associée à aucune timeline. Elle ne joue pas, sans message dans la console.

.galerie-bloc {
  timeline-scope: --galerie;
}

.galerie {
  overflow-x: auto;
  scroll-timeline-name: --galerie;
  scroll-timeline-axis: inline;
}

.indicateur {
  animation: reading-bar-fill linear 1ms both;
  animation-duration: auto;
  animation-timeline: --galerie;
}

timeline-scope sur l’ancêtre commun rend le nom visible pour l’indicateur. S’il est déjà dans .galerie, ce remontage est inutile. À spécificité égale, deux timelines de même nom : la dernière dans la cascade l’emporte.

L’écouteur qu’il faut garder

animation-timeline ne produit pas une valeur lisible par le script. Il n’écrit pas « 42 % » dans la page, ne charge pas la suite d’une liste, n’envoie pas de mesure d’audience, ne déplace pas une caméra WebGL et ne décide pas du focus. Ces tâches restent sur scroll, avec passive: true si l’écouteur ne bloque pas le défilement, ou sur IntersectionObserver quand la question est l’entrée d’un élément, pas son animation.

Quand la source du défilement n’est connue qu’en JavaScript, Firefox 159 expose quand même ScrollTimeline. On attache la timeline à l’animation, on n’écoute pas l’événement :

element.animate(
  [{ transform: "scaleX(0)" }, { transform: "scaleX(1)" }],
  {
    fill: "both",
    timeline: new ScrollTimeline({
      source: document.documentElement,
      axis: "block"
    })
  }
);

Ce code suppose que ScrollTimeline existe. Sur l’ESR 153, le constructeur est absent : il faut tester typeof ScrollTimeline avant de l’appeler, et garder le repli CSS @supports pour le trait décoratif.

Questions fréquentes

Firefox ESR 153 a-t-il animation-timeline ?

Non, pas au 30 octobre 2026. L’ESR courant est la 153.6.0, sur la base Firefox 153. L’activation est celle du canal Release 159. Mettre à jour « vers le dernier ESR » le même jour ne livre pas scroll().

Peut-on supprimer tous les écouteurs de scroll ?

On peut supprimer celui qui ne sert qu’à peindre une barre ou à faire entrer une image. On garde celui qui déclenche un chargement, une mesure, un texte ou un canvas. La timeline CSS ne renvoie pas de nombre au script.

Pourquoi la timeline semble ignorée ?

Le raccourci animation a été écrit après animation-timeline, le nom n’est pas visible hors de ses descendants, ou la durée est nulle. Vérifier l’ordre des déclarations, puis timeline-scope si l’élément animé n’est pas dans le conteneur nommé.

Faut-il entry, cover ou contain ?

entry couvre l’entrée dans la zone visible. cover va du premier pixel visible jusqu’au dernier pixel sorti. contain va du moment où l’élément est entièrement visible jusqu’au moment où il cesse de l’être. Pour un geste d’arrivée, entry suffit. cover ferait bouger l’image pendant toute sa traversée.

Le mot-clé auto est-il obligatoire ?

Non. 1ms dans le raccourci est le repli documenté par MDN pour Firefox. animation-duration: auto ensuite est une amélioration : reconnu, il aligne l’animation sur toute la timeline ; ignoré, il ne casse pas la milliseconde déjà posée.

Le badge MDN « disponibilité limitée » contredit-il Firefox 159 ?

Il décrit le délai des tableaux. Le 30 octobre 2026, MDN montrait encore ce badge, alors que les notes du 27 octobre activent la fonction sur le canal Release. On teste dans Firefox 159 et on garde @supports pour l’ESR.

Passer du geste au langage

Le geste tient en une timeline et en un ordre de déclarations. Pour reprendre, à côté, les sélecteurs, les transformations et les médias qui portent ce code, les parcours HTML, CSS, Sass et JavaScript sont sur la page Apprentissage. Les notes de ce genre restent dans la catégorie article. Pour faire relire une feuille déjà en production, le formulaire de la page Me contacter suffit.

Voir Egalement

My Blog

Bureau au petit matin, ordinateur fermé, téléphone retourné et enveloppe, sans texte

Claude Duet envoie-t-il un message sans votre accord ?

9 min de lecture Le 21 octobre 2026, Anthropic a ouvert l’aperçu de Claude Duet. L’agent peut vous écrire et préparer des brouillons sans nouveau message. L’envoi, le paiement, la signature et la suppression attendent un accord. Depuis la France, cet aperçu n’est pas accessible. Read more