ScrollGratuit

Chapter 1: Introduction

Une boîte de 280 px qui défile, une piste de 4 px collée en haut et une jauge dont le scaleX suit le défilement en CSS seul : scroll-timeline: --progressScroll y sur la boîte, animation-timeline: --progressScroll sur la jauge — mesuré scaleX = scrollTop ÷ course, au millième. Zéro JavaScript ; Firefox affiche la barre pleine dès le chargement.

CSSscroll()Progress

Mis à jour le

Chapitre 1 : Introduction

Bienvenue dans cette démonstration de barre de progression liée au scroll. La barre en haut de ce conteneur progresse en fonction de votre position de défilement.

Cet effet utilise la propriété CSS animation-timeline: scroll() qui lie une animation @keyframes directement à la position de défilement du conteneur.

Chapitre 2 : Fonctionnement

La propriété scroll-timeline crée un timeline nommé sur le conteneur scrollable. L'animation progress-bar utilise ensuite ce timeline pour animer la propriété transform: scaleX().

Le résultat est une barre de progression fluide qui représente exactement le pourcentage de contenu lu, sans aucun JavaScript.

Chapitre 3 : Applications

Idéal pour les articles de blog, les pages de documentation, les tutoriels ou tout contenu long où l'utilisateur souhaite visualiser sa progression de lecture.

Compatible avec les navigateurs modernes supportant les Scroll-Driven Animations (Chrome 115+, Edge 115+).

Chapitre 4 : Conclusion

Les animations liées au scroll ouvrent de nouvelles possibilités pour l'expérience utilisateur, le tout en CSS pur sans impact sur les performances JavaScript.

Scrollez pour voir l'effet
Survolez ou cliquez la scène pour interagir

Cet effet est gratuit — la catégorie Scroll en contient 70 au total, dont 12 gratuits. Effect.Labs regroupe 811 effets vanilla. Découvrir la catégorie →

Exemples d'usage

Clinique Saint-Louis
Salle d'attente · Orthopédie
Tablette 3
Fiche d'information · Arthroscopie du genou
Avant votre intervention
Dr Léa Morvan · Chirurgie orthopédique · Lecture : 4 min

Préparation

Restez à jeun à partir de minuit : ni nourriture, ni boisson, ni chewing-gum. Prenez votre traitement habituel avec une gorgée d'eau, sauf les anticoagulants, arrêtés selon la consigne du chirurgien.

Apportez votre carte de groupe sanguin, vos radiographies et le consentement signé. Retirez bijoux, vernis et lentilles la veille au soir.

Le jour J

Présentez-vous à l'accueil ambulatoire à l'heure indiquée sur la convocation, avec un accompagnant. L'intervention dure 30 à 45 minutes, sous anesthésie loco-régionale.

Vous resterez en salle de réveil une heure environ, puis en chambre jusqu'à la visite de l'anesthésiste.

Suites

Glace 20 minutes toutes les deux heures pendant trois jours, jambe surélevée. Les béquilles sont conseillées 48 heures ; la marche sans appui complet est possible dès le lendemain.

Le pansement est refait au troisième jour par l'infirmière ; les fils sont retirés au dixième.

Qui appeler

Douleur qui ne cède pas, fièvre supérieure à 38,5 °C, mollet dur ou gonflé : appelez sans attendre.

02 31 00 00 00Secrétariat · 8 h – 18 h
02 31 00 00 15Urgences de la clinique · 24 h/24

① Fiche d'information avant une intervention — tablette de salle d'attente d'une clinique

QuandTablette verrouillée en salle d'attente : chapitres « Préparation », « Le jour J », « Suites », « Qui appeler », la barre en tête rassure sur la longueur restante.
PourquoiLa jauge n'est pas dans la fiche : elle est collée au bord bas de l'en-tête blanc de la tablette, qui ne défile pas, et lit pourtant la boîte de texte qui défile dessous. La boîte déclare la timeline, le cadre de la scène porte timeline-scope: --progressScroll, et la jauge, logée dans l'en-tête à côté de la boîte, la trouve par son nom. Avec scroll(nearest) (fx-0555), une jauge ne voit que ses ancêtres : posée dans l'en-tête, elle ne lirait pas la fiche ; il faudrait la remettre dans la boîte, sous l'en-tête.
RéglagesThème clair, en-tête fixe de 58 px portant la piste vendue à son bas (position: absolute; bottom par-dessus le sticky), jauge #0f766e → #14b8a6, boîte calée dessous ; la jauge est sœur de la boîte grâce à timeline-scope: --progressScroll sur le cadre de la scène. Texte de 13 px, deux cartes téléphone en fin de fiche. Départ à 22 %, avance seule à 48 px/s jusqu'au premier geste — un artifice de démonstration.
Manuel de prise en main v2.3 · généré depuis docs/start.md

Quatre chapitres, dans l'ordre du signal : de la prise à l'enregistrement.

01Entrées

Chaque tranche accepte un micro XLR ou une ligne jack 6,35 mm. Enclenchez 48 V pour un micro statique, PAD pour une source chaude, puis montez le GAIN jusqu'à ce que le crête-mètre frôle −18 dBFS.

GAIN 0 → 60 dB · 48V · PAD −20 dB · HPF 80 Hz

02Bus

Les faders alimentent le mix principal L/R ou l'un des quatre bus de sous-groupe. Assignez batterie et chœurs à un bus pour les piloter d'un seul fader.

MAIN L/R · BUS 1-2 · BUS 3-4 · SOLO PFL/AFL

03Effets

Deux moteurs internes (réverbération, délai) sont alimentés par les départs AUX 5 et AUX 6. Le retour d'effet arrive sur les tranches 15-16, sans consommer d'entrée.

AUX 5 → REV hall 2,4 s · AUX 6 → DLY 3/8 · RTN 15-16

04Enregistrement

L'interface USB renvoie les 16 tranches en multipiste à 24 bits / 48 kHz. Armez les pistes dans votre station audio et lancez l'enregistrement depuis la console avec REC.

USB 18 × 18 · 24 bit / 48 kHz · REC · PLAY · STOP

② Manuel de prise en main d'une console de mixage — documentation en ligne d'un fabricant audio

QuandManuel généré depuis Markdown : chapitres « Entrées », « Bus », « Effets », « Enregistrement » dans un cadre de lecture, barre de progression dans la barre de titre du manuel.
PourquoiLa jauge vit dans la barre de titre du manuel, à côté du nom du guide et de la version, et lit par le nom de la timeline le cadre de texte qui défile dessous : ce qu'elle montre, c'est l'avancée dans le chapitre ouvert, depuis un élément du gabarit qui n'est pas dans le texte ; fx-0555 (scroll(nearest)) lie la jauge à son ancêtre défilant le plus proche et l'obligerait à vivre dans le cadre du texte, sous la barre de titre.
RéglagesThème sombre en deux colonnes : sommaire de 132 px, barre de titre de 44 px portant la piste vendue à son bas, jauge dans le dégradé du code vendu, timeline-scope sur la scène, boîte calée sous le titre (top: 44px; bottom: 0). h3 numérotés, un bloc de réglages en chasse fixe sous chaque chapitre. Départ à 30 %, avance à 44 px/s jusqu'au premier geste.
Bibliotheca · Latin 1re année
Édition bilingue, texte en regard
Sénèque, Lettres à Lucilius, I, 1-3
Texte latin
Epistula I

§ 1

Ita fac, mi Lucili: vindica te tibi, et tempus quod adhuc aut auferebatur aut subripiebatur aut excidebat collige et serva. Persuade tibi hoc sic esse ut scribo: quaedam tempora eripiuntur nobis, quaedam subducuntur, quaedam effluunt. Turpissima tamen est iactura quae per neglegentiam fit. Et si volueris attendere, magna pars vitae elabitur male agentibus, maxima nihil agentibus, tota vita aliud agentibus.

§ 2

Quem mihi dabis qui aliquod pretium tempori ponat, qui diem aestimet, qui intellegat se cotidie mori? In hoc enim fallimur, quod mortem prospicimus: magna pars eius iam praeterit; quidquid aetatis retro est mors tenet. Fac ergo, mi Lucili, quod facere te scribis, omnes horas complectere; sic fiet ut minus ex crastino pendeas, si hodierno manum inieceris.

§ 3

Dum differtur vita transcurrit. Omnia, Lucili, aliena sunt, tempus tantum nostrum est; in huius rei unius fugacis ac lubricae possessionem natura nos misit, ex qua expellit quicumque vult. Tanta autem stultitia mortalium est ut quae minima et vilissima sunt, certe reparabilia, imputari sibi cum impetravere patiantur, nemo se iudicet quicquam debere qui tempus accepit, cum interim hoc unum est quod ne gratus quidem potest reddere.

Traduction
Lettre I

§ 1

Fais ainsi, mon cher Lucilius : revendique-toi pour toi-même, et le temps qui jusqu'ici t'était enlevé, dérobé ou qui t'échappait, rassemble-le et garde-le. Persuade-toi qu'il en est comme je l'écris : certains moments nous sont arrachés, d'autres soustraits, d'autres s'écoulent. La perte la plus honteuse pourtant est celle qui vient de la négligence. Et si tu veux bien y prêter attention, une grande part de la vie s'échappe à mal faire, la plus grande à ne rien faire, la vie entière à faire autre chose.

§ 2

Qui me montreras-tu qui mette un prix au temps, qui estime la valeur d'un jour, qui comprenne qu'il meurt chaque jour ? Car voici notre erreur : nous regardons la mort devant nous, alors qu'une grande part en est déjà passée ; tout ce qui est derrière nous appartient à la mort. Fais donc, mon cher Lucilius, ce que tu m'écris faire : embrasse toutes tes heures ; ainsi tu dépendras moins de demain si tu mets la main sur aujourd'hui.

§ 3

Pendant qu'on la remet, la vie passe. Tout, Lucilius, nous est étranger ; seul le temps est à nous. La nature nous a mis en possession de ce seul bien, fuyant et glissant, dont nous chasse qui le veut. Et telle est la sottise des mortels qu'ils acceptent qu'on leur compte les choses les plus infimes et les plus viles, du moins remplaçables, quand ils les ont obtenues, tandis que nul ne se juge redevable de rien pour avoir reçu du temps, la seule chose pourtant que même un homme reconnaissant ne peut rendre.

③ Lettre de Sénèque en édition bilingue, latin et traduction en regard — plateforme de latin d'une université

QuandPage de lecture en deux colonnes : le texte latin à gauche, la traduction à droite, chaque colonne défile pour elle-même ; dans l'en-tête de chaque colonne, à côté de son intitulé, une petite jauge dit où en est cette colonne.
PourquoiDeux boîtes, deux jauges, chacune hors de sa boîte dans l'en-tête de sa colonne : timeline-scope: --progressScroll posé sur chaque colonne, la jauge se lie par le nom à la boîte de sa colonne et à elle seule (mesuré : latin à 25 % → 0,25, traduction à 75 % → 0,75). Le lecteur voit d'un coup d'œil si le latin et la traduction sont au même point de la lettre. fx-0555 (scroll(nearest)) lie la jauge à un ancêtre défilant : elle devrait vivre dans la boîte ; fx-0575 cible des ids, une seule instance par page.
RéglagesThème papier clair, bandeau de 48 px, deux colonnes de 270 px en grille, en-tête de colonne de 34 px portant l'intitulé et la piste vendue rendue inline (position: static, 96 px de large, coins arrondis), jauge bordeaux → or (#8b2e2e → #c9973a), boîte calée dessous (top: 34px; bottom: 0, 278 px de haut). timeline-scope: --progressScroll sur chaque colonne, pas sur la scène : mesuré, posé sur l'ancêtre commun des deux boîtes, les deux jauges restent à 0 — un nom déclaré deux fois dans un même scope rend la timeline inactive. Georgia 12,5 px, trois h3 « § 1 » à « § 3 » + trois p par colonne ; le latin fait 750 px de contenu (course 472 px), la traduction 847 px (course 569 px). Latin à 16 %, avance à 38 px/s ; traduction à 38 %, 50 px/s — deux vitesses pour que les jauges divergent ; le premier geste sur une boîte arrête la sienne.

Comment ça marche

Le cadre .demo-preview (flex centré, 100% × 280px, overflow: hidden, position: relative, fond rgb(10, 10, 15), texte blanc, sans-serif) contient la boîte .progress-scroll-container : 100% × 100%, overflow-y: auto, overflow-x: hidden, et la ligne qui fait l'effet, scroll-timeline: --progressScroll y — une timeline de défilement nommée, dont la progression va de 0 en haut de la boîte à 1 sur son dernier pixel défilable. Dans la boîte, la piste .slr-progress-bar-track (position: sticky; top: 0, 4px de haut, blanc à 10 %, z-index: 5) porte la jauge .slr-progress-bar-fill : dégradé à 90° #6366f1 → #d946ef → #f59e0b, transform-origin: left, transform: scaleX(0), animation: progressGrow linear both et animation-timeline: --progressScroll. Dessous, .progress-content (padding 16px 12px) : quatre h3 de 14,4 px en #a78bfa, sept p de 12,8 px en blanc à 70 %. Hors de la boîte, span.slr-scroll-hint « Scrollez pour voir l'effet », absolu à 8 px du bas du cadre, 11,2 px, blanc à 40 %, rebondit de 0 à −4 px toutes les 2 s. Le champ JavaScript est vide.

@keyframes progressGrow va de scaleX(0) à scaleX(1). Avec animation-timeline, le temps de l'animation n'est plus l'horloge mais la position de défilement (durée calculée auto) ; linear rend la largeur exactement proportionnelle, both tient les deux extrémités. Mesuré dans Chromium 151, page vierge, fond blanc comme sombre : scrollTop 0 / 31 / 61 / 92 / 122 px → scaleX 0 / 0,254 / 0,5 / 0,754 / 1, soit scrollTop ÷ course au millième ; WebKit 26.5 donne les mêmes valeurs, et la piste reste à 0 px du haut de la boîte à toutes les positions. La course dépend de la largeur : à 1 264 px de large, les quatre chapitres n'occupent que 402 px, la course fait 122 px et un seul cran de molette de 120 px porte la jauge à 0,984 ; à 374 px de large, le texte fait 669 px, la course 389 px, et les crans donnent 0,308, 0,617, 0,925 puis 1. La jauge mesure la course de la boîte, pas un temps de lecture : un texte court dans une colonne large se « lit » en un cran.

Face à scroll(nearest) (Progress Bar, fx-0555), la différence est la résolution. Une timeline anonyme lie l'élément animé à son ancêtre défilant le plus proche : la jauge doit vivre dans la boîte. Une timeline nommée se résout par son nom : la jauge trouve --progressScroll sur n'importe quel ancêtre, et avec timeline-scope: --progressScroll posé sur un ancêtre commun, elle peut être sœur de la boîte — dans un en-tête fixe, une barre de titre. Mesuré, piste sortie de la boîte et placée avant elle : mêmes valeurs 0 / 0,254 / 0,5 / 0,754 / 1 dans Chromium 151 et WebKit 26.5. Deux copies collées sur la même page restent indépendantes (mesuré : seconde boîte à 60 % → 0,599, la première à 0) : chaque boîte déclare sa timeline, chaque jauge se lie à la plus proche, ni id ni script. Préfixe slr- incomplet (progress-scroll-container, progress-content, @keyframes progressGrow / hintBounce sans préfixe) : vérifiez qu'une feuille existante ne les déclare pas déjà.

Accessibilité

  • prefers-reduced-motion absent du code : mesuré sous émulation, la jauge suit toujours le défilement — acceptable, elle ne bouge que par le geste du lecteur (WCAG 2.3.3 vise le mouvement autonome). L'indice, lui, continue de rebondir de 4 px toutes les 2 s (animation mesurée running) : ajoutez @media (prefers-reduced-motion: reduce) { .slr-scroll-hint { animation: none } }.
  • Clavier : Chromium 151 et Firefox 153 donnent le focus à la boîte par Tab sans tabindex (mesuré : activeElement = .progress-scroll-container) ; flèche bas avance de 40 px (Chromium) ou 51 px (Firefox), Page suivante de 285 px, Fin va au bout. WebKit 26.5 ne focalise pas la boîte (focus resté sur body, flèches sans effet) : ajoutez tabindex="0", role="region", un aria-label et un style :focus-visible.
  • Contraste (seuil 4,5:1) : le paragraphe en blanc à 70 % sur #0a0a0f rend rgb(182, 182, 183), 9,75:1 ; le h3 #a78bfa 7,26:1 ; l'indice en blanc à 40 % 3,77:1 à 11,2 px — sous le seuil, et en français en dur : aria-hidden="true" ou suppression. La piste vide (blanc à 10 %) n'est qu'à 1,25:1 du fond, à peine visible avant que la jauge grandisse : montez-la à 20-25 %. La jauge contre la piste tient 3,55:1 au pire (#6366f1), au-dessus des 3:1 d'un élément non textuel.
  • Lecteurs d'écran et repli : la jauge est un div vide, rien n'est annoncé, et une animation CSS ne peut pas écrire aria-valuenow — traitez-la comme décorative (aria-hidden="true" sur la piste) : la position de lecture est déjà connue de l'assistance par la boîte défilante elle-même. Les h3 sont du contenu : prenez le niveau qui suit votre plan. Sans animation-timeline (Firefox), rien n'est caché : mesuré, les 11 blocs de texte sont visibles et la boîte défile.

Compatibilité navigateur

CSS seul : scroll-timeline (nommée), animation-timeline, position: sticky, overflow-y, un dégradé, deux @keyframes. Zéro dépendance, zéro JavaScript. Animations pilotées par le défilement : Chrome et Edge 115+, Safari et iOS 26+ (mesuré dans WebKit 26.5, valeurs identiques à Chromium) ; timeline-scope, pour sortir la jauge de la boîte : Chrome 116+, Safari 26. Firefox : aucune version. Mesuré dans Firefox 153 : CSS.supports('animation-timeline: scroll()') répond faux, la déclaration est ignorée, animation: progressGrow linear both redevient une animation d'horloge de 0 s dont both applique l'image-clé finale aussitôt — la barre est pleine dès le chargement (scaleX 1, 1 264 px sur 1 264) et le reste à toutes les positions ; le texte est lisible et la boîte défile. Rien n'est caché, la barre ne renseigne simplement pas.

Chrome 115+✓ Complet
Firefox✓ Aucune version : barre pleine et figée, texte lisible
Safari 26+✓ Complet (mesuré dans WebKit 26.5)
Edge 115+✓ Complet
Mobile iOS 26+✓ Complet (défilement tactile de la boîte)
Android Chrome 115+✓ Complet

Le code vendu n'a pas de repli : dans Firefox, Chrome avant 115 et Safari avant 26, la barre est pleine dès le chargement et n'évolue plus, le texte reste lisible et la boîte défile. Pour une piste vide plutôt qu'une barre à 100 %, ajoutez @supports not (animation-timeline: scroll()) { .slr-progress-bar-fill { animation: none } } — mesuré dans Firefox 153 : scaleX(0) à toutes les positions, sans effet dans Chromium. Pour une progression réelle partout, il faut le JavaScript d'Introduction (fx-0575).

Le code

Copiez les trois blocs dans votre page. Aucune dépendance.

HTML
<div class="progress-scroll-container">
    <div class="slr-progress-bar-track">
      <div class="slr-progress-bar-fill"></div>
    </div>
    <div class="progress-content">
      <h3>Chapitre 1 : Introduction</h3>
      <p>Bienvenue dans cette démonstration de barre de progression liée au scroll. La barre en haut de ce conteneur progresse en fonction de votre position de défilement.</p>
      <p>Cet effet utilise la propriété CSS animation-timeline: scroll() qui lie une animation @keyframes directement à la position de défilement du conteneur.</p>
      <h3>Chapitre 2 : Fonctionnement</h3>
      <p>La propriété scroll-timeline crée un timeline nommé sur le conteneur scrollable. L'animation progress-bar utilise ensuite ce timeline pour animer la propriété transform: scaleX().</p>
      <p>Le résultat est une barre de progression fluide qui représente exactement le pourcentage de contenu lu, sans aucun JavaScript.</p>
      <h3>Chapitre 3 : Applications</h3>
      <p>Idéal pour les articles de blog, les pages de documentation, les tutoriels ou tout contenu long où l'utilisateur souhaite visualiser sa progression de lecture.</p>
      <p>Compatible avec les navigateurs modernes supportant les Scroll-Driven Animations (Chrome 115+, Edge 115+).</p>
      <h3>Chapitre 4 : Conclusion</h3>
      <p>Les animations liées au scroll ouvrent de nouvelles possibilités pour l'expérience utilisateur, le tout en CSS pur sans impact sur les performances JavaScript.</p>
    </div>
  </div>
  <span class="slr-scroll-hint">Scrollez pour voir l'effet</span>
CSS
.slr-scroll-hint {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.7rem;
  color: rgba(255, 255, 255, 0.4);
  pointer-events: none;
  z-index: 10;
  animation: hintBounce 2s ease-in-out infinite;
}

.progress-scroll-container {
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  position: relative;
  scroll-timeline: --progressScroll y;
}

.slr-progress-bar-track {
  position: sticky;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, 0.1);
  z-index: 5;
}

.slr-progress-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #6366f1, #d946ef, #f59e0b);
  transform-origin: left;
  transform: scaleX(0);
  animation: progressGrow linear both;
  animation-timeline: --progressScroll;
}

.progress-content {
  padding: 16px 12px;
}

.progress-content p {
  font-size: 0.8rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.7);
  margin-bottom: 12px;
}

.progress-content h3 {
  font-size: 0.9rem;
  color: #a78bfa;
  margin-bottom: 8px;
}

@keyframes hintBounce {

  0%,
  100% {
    transform: translateX(-50%) translateY(0);
  }

  50% {
    transform: translateX(-50%) translateY(-4px);
  }
}

@keyframes progressGrow {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}
JavaScript (fx-0565)

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
Nom et axe de la timeline (CSS — scroll-timeline: --progressScroll y, animation-timeline: --progressScroll) --progressScroll, axe y Les deux déclarations doivent porter le même nom ; renommez-le librement. x lie la jauge à un défilement horizontal. Plusieurs copies n'ont pas besoin de noms différents : mesuré, chaque jauge se lie à sa propre boîte.
Emplacement de la jauge (CSS — timeline-scope, à ajouter) piste sticky en haut de la boîte, dans la boîte Pour la sortir de la boîte (en-tête fixe, barre de titre), posez timeline-scope: --progressScroll sur un ancêtre commun — mesuré identique (0 → 1) dans Chromium 151 et WebKit 26.5. Sans lui, une jauge hors de la boîte ne trouve pas la timeline et reste à scaleX(0).
Plage de course (CSS — animation-range, à ajouter sur .slr-progress-bar-fill) absent (0 → 100 % de la course) animation-range: 0 50% remplit la jauge à mi-course (mesuré : 0,499 à 25 %, 1 dès 50 %) ; 20% 100% la laisse vide sur le premier cinquième — pour ignorer une introduction ou un pied de page.
Hauteur de la boîte (CSS — .demo-preview { height: 280px }, boîte à 100%) 280 px Course = hauteur du contenu − hauteur de la boîte, relue par le navigateur : rien d'autre à changer. Le texte livré donne 122 px de course à 1 264 px de large, 389 px à 374 px. Pour une page entière, déclarez la timeline sur html.
Épaisseur, couleurs et courbe (CSS — .slr-progress-bar-track, .slr-progress-bar-fill) 4 px, piste blanc à 10 %, jauge #6366f1 → #d946ef → #f59e0b, linear Le dégradé est dessiné sur toute la largeur puis révélé par scaleX, pas étiré : l'ambre n'apparaît qu'aux abords de 100 %. La piste à 10 % n'est qu'à 1,25:1 du fond. Gardez linear pour une jauge proportionnelle ; ease-out la ferait courir devant le lecteur.
Contenu (HTML + CSS — .progress-content h3, p) 4 h3 de 14,4 px #a78bfa, 7 p de 12,8 px blanc à 70 % Un texte de démonstration : remplacez-le par le vôtre, la jauge lit la boîte, pas le balisage. Plus le contenu est long ou la colonne étroite, plus la jauge avance lentement.
Indice « Scrollez pour voir l'effet » (HTML + CSS — .slr-scroll-hint) 8 px du bas du cadre, rebond de 4 px toutes les 2 s Français en dur, absolu par rapport à .demo-preview (sans ce cadre il tombe au bas de la page). Supprimez le span et la @keyframes hintBounce ; sinon aria-hidden="true".

FAQ

Quelle différence avec Introduction (fx-0575), qui affiche la même barre de lecture ?

Même anatomie — boîte de 280 px, piste de 4 px collée en haut, chapitres h3 + p — mais deux moteurs. fx-0575 calcule en JavaScript : un écouteur scroll écrit scrollTop ÷ (scrollHeight − clientHeight) dans la largeur de la jauge, avec des ids (#progress-scroll, #progress-fill) qui limitent le code à une instance par page ; il fonctionne dans Firefox 61+ et son pourcentage est un nombre que la page peut réutiliser. fx-0565 n'a pas une ligne de script : scroll-timeline nommée, scaleX calculé par le navigateur sans écouteur, autant de copies que vous voulez, jauge sortable de la boîte via timeline-scope — mais Firefox l'affiche pleine. Prenez fx-0565 quand le JavaScript est interdit ou absent (kiosque, générateur statique, CMS verrouillé) et que votre public est sur Chrome, Edge ou Safari ; fx-0575 quand il vous faut Firefox ou le nombre.

Pourquoi une timeline nommée plutôt que scroll(nearest), comme Progress Bar (fx-0555) ?

scroll(nearest) est anonyme : l'élément animé se lie à son ancêtre défilant le plus proche, donc la jauge doit être dans la boîte, et un élément intermédiaire qui défile l'accrocherait au mauvais conteneur. La timeline nommée est explicite : la boîte la déclare, la jauge la demande par son nom, la résolution remonte les ancêtres — ou, avec timeline-scope: --progressScroll sur un ancêtre commun, s'étend à tout son sous-arbre : la jauge peut alors être sœur de la boîte, dans un en-tête fixe ou une barre de titre. Mesuré, piste placée avant la boîte : valeurs identiques à la version dans la boîte — c'est le montage des trois scènes de cette page, la troisième avec deux colonnes et deux jauges.

Dans Firefox, la barre est pleine dès l'ouverture : le code est-il cassé ?

Non : sans animation-timeline, animation: progressGrow linear both redevient une animation d'horloge de 0 s et both applique l'image-clé finale scaleX(1) dès le premier rendu (mesuré dans Firefox 153 : jauge pleine, figée, texte et défilement intacts ; Chrome avant 115 et Safari avant 26 font pareil). Si vous préférez une piste vide à une barre qui ment, ajoutez @supports not (animation-timeline: scroll()) { .slr-progress-bar-fill { animation: none } } — mesuré dans Firefox : scaleX(0) partout, aucun changement dans Chromium. Pour une vraie progression sous Firefox, il faut le JavaScript de fx-0575.