DataGratuit

Animated Counter

Un grand chiffre en dégradé qui compte de 0 jusqu'à sa valeur quand il arrive à l'écran, une seule fois, au format de la langue de la page.

JSNumbers

Mis à jour le

8 547 Utilisateurs actifs
Survolez ou cliquez la scène pour interagir

Cet effet est gratuit — la catégorie Data en contient 28 au total, dont 1 gratuits. Effect.Labs regroupe 840 effets vanilla. Découvrir la catégorie →

Exemples d'usage

Nos actions Rapport 2026 Faire un don

Rapport d'activité 2026

Une année aux côtés de 640 familles

Trois points de distribution, une camionnette frigorifique et des bénévoles chaque semaine : voici ce que vos dons ont rendu possible.

Faites défiler pour voir l'année en chiffres

42bénévoles réguliers

3points de distribution

11 tde produits frais

8 547 repas distribués cette année

Merci aux 1 900 donateurs qui ont rendu cette année possible.

① Repas distribués dans l'année — bandeau du rapport d'une banque alimentaire

QuandLe rapport annuel commence par un titre et un texte d'introduction ; plus bas, un bandeau vert annonce les repas distribués. En faisant défiler la page, le chiffre arrive à l'écran et grimpe jusqu'à 8 547.
PourquoiUn bilan se parcourt de haut en bas : le chiffre qui compte au moment où l'on arrive dessus marque la fin de l'introduction et donne du poids au résultat principal, sans attirer l'œil trop tôt.
RéglagesRacine en bandeau de 180 px : --ctup-bg:#123b2a, --ctup-from:#fde68a, --ctup-to:#f59e0b, --ctup-size:4.2rem, --ctup-height:180px, data-target="8547". La page défile dans la scène : c'est ce défilement qui déclenche le comptage.

Pétition locale

Sécuriser le carrefour des Tilleuls

Un passage piéton éclairé devant l'arrêt de bus, demandé par les riverains.

② Signatures d'une pétition de quartier — le chiffre dans le message de remerciement

QuandLe riverain remplit son prénom et sa rue, clique « Je signe » ; le formulaire laisse la place à un remerciement où le nombre de signatures monte jusqu'à 1 204, avec l'objectif rappelé dessous.
PourquoiAprès un geste civique, voir le total bouger confirme que la signature a compté et montre qu'on n'est pas seul ; le chiffre reste petit et ne vole pas la vedette au message.
RéglagesFond transparent (--ctup-bg:transparent), --ctup-height:0px, --ctup-size:2.6rem, dégradé #4f46e5→#9333ea, libellé gris --ctup-muted:#64748b, aligné à gauche par le CSS de la scène. Le panneau est caché (hidden) jusqu'au clic : le compteur part quand il apparaît.
Pasquelin Jeudi 12 mars
LMMJVSD

Depuis lundi : 23,1 km parcourus

Sorties du jour

8 h

Le long du canal2,1 km · 27 min

12 h

Pause de midi1,8 km · 22 min

18 h

Tour du parc2,5 km · 31 min

③ Distance marchée aujourd'hui — onglet d'une appli de marche

QuandL'appli s'ouvre sur la semaine ; un toucher sur l'onglet « Aujourd'hui » montre la distance du jour, qui compte jusqu'à 6,4 km avec sa décimale, au-dessus de l'objectif de 8 km.
PourquoiDans un suivi d'activité, le chiffre du jour est la récompense de l'effort : le voir monter quand on ouvre l'onglet rend la statistique plus vivante qu'un nombre posé.
Réglagesdata-target="6.4" (une décimale, affichée « 6,4 » en français), --ctup-bg:transparent, --ctup-size:4.4rem, dégradé #5eead4→#38bdf8. Le panneau du jour est caché au départ ; l'afficher suffit à lancer le comptage.

Comment ça marche

Le HTML contient déjà la valeur finale : <span class="ctup-value" data-target="8547">8 547</span>. Le script cherche chaque .ctup-value[data-target] placé dans une racine .fx-0223-root, remet l'affichage à 0, puis attend que le chiffre soit visible à moitié (IntersectionObserver, seuil 0,5). À ce moment il compte jusqu'à data-target en 2 secondes avec un ralenti en fin de course (ease-out cubique), et ne recommence plus.

Le nombre de décimales vient de data-target lui-même : 6.4 affiche une décimale, 4.85 en affiche deux, 8547 aucune. Le format suit l'attribut lang le plus proche (celui de <html> en général) grâce à Intl.NumberFormat : « 8 547 » et « 6,4 » sur une page en français, « 8,547 » et « 6.4 » en anglais. Les chiffres ont la même largeur (tabular-nums), le bloc ne tremble donc pas pendant le comptage.

Chaque chiffre est réglé à part : plusieurs compteurs dans une racine, plusieurs racines dans la page, chacun part quand il devient visible. Le script ne déclare rien sur window. Un chiffre affiché plus tard (onglet, panneau replié, hidden retiré) compte au moment où il apparaît.

Accessibilité

  • Lecteurs d'écran : le chiffre qui défile porte aria-hidden="true" et le script ajoute juste après un texte masqué visuellement (.ctup-sr) avec la valeur finale. On entend « 8 547 Utilisateurs actifs », jamais une valeur intermédiaire ni un « 0 ».
  • Mouvement réduit : avec prefers-reduced-motion: reduce, la valeur finale est posée tout de suite, sans comptage.
  • Contraste : le dégradé indigo→rose sur le fond rgb(26, 26, 36) reste lisible ; sur un fond clair, changez --ctup-from, --ctup-to et --ctup-muted pour garder un contraste suffisant.
  • Rien à manipuler : le compteur n'a ni clic ni focus, il se lit comme un texte.

Compatibilité navigateur

JavaScript sans dépendance (environ 2 Ko) et variables CSS. Mesuré le 08/11/2026 dans Chromium 151, Firefox 153 et WebKit 26.5 (Playwright) : comptage à l'apparition, compteur placé plus bas qui attend le défilement, deux copies, 390 px, mouvement réduit, format français et anglais, aucune erreur. Versions tirées de @mdn/browser-compat-data : IntersectionObserver fixe le minimum.

Chrome 51+✓ Complet (mesuré)
Firefox 55+✓ Complet (mesuré)
Safari 12.1+✓ Complet (mesuré dans WebKit)
Edge 79+✓ Complet (moteur Chromium)
iOS Safari 12.2+✓ Non vérifié sur appareil réel
Android Chrome 51+✓ Complet (moteur Chromium)

Sans IntersectionObserver, la valeur finale s'affiche directement. Sans JavaScript, on lit le texte écrit dans le HTML (8 547) : gardez-le identique à data-target.

Le code

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

HTML
<div class="fx-0223-root">
  <div class="ctup-box">
    <span class="ctup-value" data-target="8547">8 547</span>
    <span class="ctup-label">Utilisateurs actifs</span>
  </div>
</div>
CSS
.fx-0223-root,
.fx-0223-root *,
.fx-0223-root *::before,
.fx-0223-root *::after {
  box-sizing: border-box
}

.fx-0223-root {
  --ctup-bg: rgb(26, 26, 36);
  --ctup-from: #6366f1;
  --ctup-to: #d946ef;
  --ctup-muted: rgba(255, 255, 255, .6);
  --ctup-size: 3rem;
  --ctup-height: 250px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--ctup-height);
  overflow: hidden;
  position: relative;
  background: var(--ctup-bg);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.ctup-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.ctup-value {
  font-size: var(--ctup-size);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  background: linear-gradient(135deg, var(--ctup-from), var(--ctup-to));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.ctup-label {
  font-size: 0.875rem;
  color: var(--ctup-muted);
  text-transform: uppercase;
  letter-spacing: 2px;
}

/* Valeur finale pour les lecteurs d'écran (le chiffre qui défile est masqué pour eux) */
.ctup-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
JavaScript (fx-0223)
(function () {
  'use strict';
  // Animated Counter : le chiffre compte de 0 jusqu'à data-target quand il est à moitié visible, une seule fois.
  var calm = window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)') : { matches: false };

  // Langue de la page (lang le plus proche) : 8 547 en français, 8,547 en anglais
  function pageLang(el) {
    var host = el.closest('[lang]');
    return (host && host.lang) || navigator.language || 'fr';
  }

  function init(el) {
    if (el.hasAttribute('data-ctup-ready')) return;
    el.setAttribute('data-ctup-ready', '');
    var raw = (el.getAttribute('data-target') || '0').trim();
    var target = parseFloat(raw) || 0;
    var decimals = raw.indexOf('.') > -1 ? raw.split('.')[1].length : 0;
    var duration = parseFloat(el.getAttribute('data-duration')) || 2000;
    var fmt = new Intl.NumberFormat(pageLang(el), {
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals
    });

    // Les lecteurs d'écran lisent la valeur finale, jamais les étapes du comptage
    var sr = document.createElement('span');
    sr.className = 'ctup-sr';
    sr.textContent = fmt.format(target);
    el.parentNode.insertBefore(sr, el.nextSibling);
    el.setAttribute('aria-hidden', 'true');

    if (calm.matches || !('IntersectionObserver' in window)) {
      el.textContent = fmt.format(target);
      return;
    }
    el.textContent = fmt.format(0);

    function count() {
      if (calm.matches) {
        el.textContent = fmt.format(target);
        return;
      }
      var start = performance.now();
      requestAnimationFrame(function step(t) {
        var p = Math.min((t - start) / duration, 1);
        var v = target * (1 - Math.pow(1 - p, 3)); // ease-out cubique
        el.textContent = fmt.format(decimals ? v : Math.floor(v));
        if (p < 1) requestAnimationFrame(step);
        else el.textContent = fmt.format(target);
      });
    }

    var obs = new IntersectionObserver(function (entries) {
      if (!entries[0].isIntersecting) return;
      obs.disconnect();
      count();
    }, { threshold: 0.5 });
    obs.observe(el);
  }

  document.querySelectorAll('.fx-0223-root .ctup-value[data-target]').forEach(init);
})();

Personnaliser

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

Option / propriétéDéfautEffet
Valeur (HTML — data-target sur .ctup-value) 8547 Nombre atteint en fin de comptage. Écrivez la décimale avec un point (12.5) : le nombre de chiffres après le point fixe les décimales affichées.
Durée (HTML — data-duration sur .ctup-value) 2000 (millisecondes) Durée du comptage, par exemple data-duration="1200" pour un chiffre secondaire.
Libellé (HTML — texte de .ctup-label) Utilisateurs actifs Texte sous le chiffre, en majuscules espacées par le CSS. Il est lu après la valeur par les lecteurs d'écran.
Couleurs du chiffre (CSS — --ctup-from et --ctup-to) #6366f1 → #d946ef Les deux teintes du dégradé appliqué au texte du chiffre.
Fond et libellé (CSS — --ctup-bg et --ctup-muted) rgb(26, 26, 36) · blanc à 60 % Sur une page claire : --ctup-bg:transparent; --ctup-muted:#475569.
Taille du chiffre (CSS — --ctup-size) 3rem Grand bandeau : 4 à 5rem ; dans une carte : 2 à 2.5rem.
Hauteur du bloc (CSS — --ctup-height) 250px Hauteur minimale de la racine ; 0px pour qu'elle prenne seulement la place du chiffre et du libellé.
Langue du format (HTML — attribut lang) celui de la page, sinon la langue du navigateur Pour forcer un format, posez lang="en" (ou autre) sur la racine ou un parent.

FAQ

Le compteur peut-il repartir à chaque passage à l'écran ?

Non, il compte une seule fois : l'observateur se débranche après le premier passage. C'est voulu pour une page qu'on parcourt dans les deux sens. Pour un compteur qui change de valeur, voyez Stat Cards : changer son data-target relance le comptage.

Comment afficher « 12,5 % » ou « 3 200 € » ?

Mettez data-target="12.5" et écrivez l'unité dans le libellé (« % de clients satisfaits »), ou à côté du span dans un élément à vous. Le script ne touche que le texte de .ctup-value : tout ce qui l'entoure reste à votre main.

Mon chiffre est dans un onglet caché : part-il trop tôt ?

Non. Un élément en display: none n'est jamais « visible » pour IntersectionObserver : le comptage attend que l'onglet soit ouvert et que le chiffre soit à moitié à l'écran.