Contador
Un número que sube hasta sí mismo. La cifra del marcado es el valor final —prefijo, sufijo, decimales y todo— y el componente cuenta desde from hasta ella cuando el elemento llega al viewport; después restituye el texto servido carácter a carácter. No se calcula nada ni se inventa nada: lo único que añade JavaScript es la subida.
La fixture de abajo cuenta las medidas del propio paquete. Desplázala hasta verla y las cuatro tarjetas suben una vez; recarga con JavaScript desactivado y esos mismos cuatro números están ahí sin más.
<p class="iv-u-m-0 iv-u-mb-6">Four figures measured by <code>npm run sizes</code> and <code>npm test</code> on the
<code>0.6.0-beta.0</code> milestone (commit <code>34e69c1</code>): they are the real numbers of the package, not a
demonstration set. Each one is served complete, so the page reads the same without JavaScript, and counts up once when it
reaches the viewport.</p>
<div class="iv-stat-group">
<div class="iv-stat iv-stat--card">
<span class="iv-stat__label">Core stylesheet</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup">2.60</strong>
<span class="iv-stat__hint">KiB min + gzip, budget 8</span>
</div>
<div class="iv-stat iv-stat--card">
<span class="iv-stat__label">Full stylesheet</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup">25.64</strong>
<span class="iv-stat__hint">KiB min + gzip, budget 40</span>
</div>
<div class="iv-stat iv-stat--card">
<span class="iv-stat__label">Bundled JavaScript</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup">39.04</strong>
<span class="iv-stat__hint">KiB min + gzip, budget 48</span>
</div>
<div class="iv-stat iv-stat--card">
<span class="iv-stat__label">Unit tests</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup" data-iv-duration="1400">641</strong>
<span class="iv-stat__hint">27 files, all passing</span>
</div>
</div>
<p class="iv-u-text-sm iv-u-text-muted iv-u-mt-6">With <code>prefers-reduced-motion: reduce</code>, without an
<code>IntersectionObserver</code> or without JavaScript, nothing moves: the served figure is already the answer.</p>// data-iv-component="countup"
{
duration: 1400,
}Formatos, prefijos e idiomas
El formato sale del texto servido y del idioma del elemento. Una cifra escrita 12.480,50 € dentro de lang="es" cuenta con separadores españoles y conserva su sufijo; € 1,240.50 en inglés conserva su prefijo y su coma. decimals se deduce de lo servido, y un espacio duro impide que el símbolo de moneda salte de línea.
<p class="iv-u-m-0 iv-u-mb-6">Prefixes, suffixes and separators come from the served text and from the language of the
element: the component never invents a format. The three money figures below are <strong>made up for this
fixture</strong>; the test count is the real one of the <code>0.6.0-beta.0</code> milestone.</p>
<div class="iv-stat-group" style="--iv-stat-group-min: 16rem">
<div class="iv-stat iv-stat--card">
<span class="iv-stat__label">Invoiced (made-up figure)</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup">€ 1,240.50</strong>
<span class="iv-stat__hint">English grouping, prefix kept</span>
</div>
<div class="iv-stat iv-stat--card" lang="es">
<span class="iv-stat__label" lang="en">Invoiced, Spanish locale (made-up figure)</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup">12.480,50 €</strong>
<span class="iv-stat__hint" lang="en">Spanish grouping and decimal comma, suffix kept</span>
</div>
<div class="iv-stat iv-stat--card">
<span class="iv-stat__label">Coverage of the contract matrix</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup" data-iv-autostart="true">98 %</strong>
<span class="iv-stat__hint">Starts at <code>init</code>, not in view</span>
</div>
<div class="iv-stat iv-stat--card">
<span class="iv-stat__label">Browser tests, three engines</span>
<strong class="iv-stat__value iv-count" data-iv-component="countup" data-iv-from="900" data-iv-duration="1800" data-iv-grouping="false">1068</strong>
<span class="iv-stat__hint">From 900, ungrouped while counting</span>
</div>
</div>
<p class="iv-u-mt-6">A figure also works inside a sentence: the last full gate
passed <strong class="iv-count" data-iv-component="countup" data-iv-duration="1200" data-iv-grouping="false">1068</strong> browser tests and
skipped <strong class="iv-count" data-iv-component="countup" data-iv-duration="1200">114</strong> of them, the visual
ones outside Chromium.</p>.iv-root {
--iv-stat-group-min: 16rem;
}// data-iv-component="countup"
{
autostart: true,
from: 900,
duration: 1800,
grouping: false,
}Opciones
| Opción | Atributo | Por defecto | Efecto |
|---|---|---|---|
from | data-iv-from | 0 | Dónde empieza la subida. Una cifra que solo se mueve en sus últimos dígitos se lee antes empezando cerca. |
duration | data-iv-duration | 900 | Milisegundos de la subida, con salida suavizada para que se pose en vez de frenar. |
decimals | data-iv-decimals | -1 (automático) | Decimales que se mantienen durante la subida. -1 es el centinela de «los que traiga la cifra servida», porque la gramática de atributos no admite nulo. |
grouping | data-iv-grouping | true | Separadores de millar mientras cuenta. Desactivado, los dígitos dejan de desplazarse. |
once | data-iv-once | true | Cuenta solo la primera vez. Con false vuelve a contar en cada entrada. |
autostart | data-iv-autostart | false | Arranca en init en lugar de esperar al viewport. |
Métodos y eventos
start(), reset(), destroy(); se leen value y done. value es el número que se muestra y done significa «no queda nada que contar», que también es cierto de inmediato con movimiento reducido o sin IntersectionObserver. destroy() devuelve los nodos servidos, no solo su texto, así que el DOM queda idéntico.
| Evento | Cuándo | detail |
|---|---|---|
iv:count | empieza la subida; cancelable | from, to |
iv:counted | la cifra servida vuelve a estar en pantalla | from, to |
Donde no se cuenta, no se anuncia nada: ninguno de los dos eventos se dispara con movimiento reducido ni sin observador.
Teclado y tecnología asistiva
Una cifra es texto, no un control: no hay nada que enfocar ni nada que accionar. Deliberadamente no es una región viva —un número entrando cuarenta veces por segundo en un lector de pantalla sería inservible—, así que la tecnología asistiva lee el valor final, que es el servido y el que vuelve a estar ahí un segundo después. Dale a la cifra una etiqueta en su propio marcado (dentro de una cifra lo hace .iv-stat__label) y no dejes nunca que el número sostenga solo una afirmación.
Sin JavaScript
La página ya es correcta. El valor está en el HTML, el estilo es CSS y .iv-count solo añade font-variant-numeric: tabular-nums para que los dígitos ocupen columnas fijas y la cifra no baile mientras sube. Con prefers-reduced-motion: reduce, o allí donde falta IntersectionObserver, el componente lee la cifra y se detiene ahí.
Tokens y locales
El contador no tiene locales propios: toma la tipografía de lo que lo contenga. Dentro de una cifra son --iv-stat-size, --iv-tracking-tight y los números tabulares de .iv-count; dentro de una frase, el texto que la rodea. La única regla que impone la clase son los números tabulares, y está ahí por una razón visual, no decorativa.
Errores habituales
- Servir
0esperando que el script ponga el número real. Sin JavaScript la página sería entonces una mentira: sirve la respuesta. - Contar una cifra que nadie ha medido. Un número que sube parece autorizado: di de dónde sale o márcalo como inventado.
- Una
durationlarga en una cifra sobre el pliegue: quien lee llega antes que el número. - Separadores activos contando un número de cuatro dígitos: el separador aparece y desaparece y la línea da un salto.
- Envolver la cifra en una región viva «para hacerla accesible». La hace ilegible.