Etiqueta progress en HTML: avance e indeterminación
La etiqueta <progress> representa el avance de una tarea: puede indicar cuánto se ha completado o un estado indeterminado cuando no se conoce el trabajo restante. Úsala para lecciones completadas, una instalación o una carga cuyo avance puedas obtener. La barra comunica ese estado; no realiza la tarea ni calcula su progreso por sí sola.
Ejemplo mínimo: tres lecciones de cinco
<label for="avance">Lecciones completadas: 3 de 5</label>
<progress id="avance" value="3" max="5">3 de 5</progress>
El avance es 3 ÷ 5 = 0,6, es decir, el 60 %. El navegador representa la proporción con una barra y la etiqueta deja visible la cantidad. for="avance" asocia el nombre con el elemento de id="avance". El porcentaje no aparece escrito automáticamente.
Para probarlo, sustituye el contenido de <body> del documento completo del caso práctico por este fragmento. Cambia value a 4 y ambos textos a «4 de 5»: la barra pasa al 80 %. Si retiras las etiquetas de apertura y cierre de <progress> y conservas su texto, permanece la cantidad escrita, pero desaparecen la barra y la semántica de avance.
Sintaxis y contexto válido
<progress> lleva apertura y cierre; ninguna de las dos etiquetas puede omitirse. Se utiliza donde se admite contenido de frase, por ejemplo dentro de un párrafo. Su interior admite texto y elementos de frase, pero ningún <progress> descendiente. No pongas un <div> ni otro indicador dentro. Estas reglas se definen en el HTML Living Standard.
No necesita estar en un formulario, no es un campo editable y no envía por sí mismo un valor. Añade una etiqueta visible que identifique la tarea: el texto interior sirve de alternativa para navegadores antiguos, pero no proporciona el nombre accesible ni suele aparecer junto a la barra.
Progreso determinado e indeterminado
En una tarea de cinco fases conocidas, value="0" max="5" significa cero fases completadas. Es progreso determinado, aunque la barra esté vacía.
Si una operación sigue en curso y todavía no puedes medir cuánto falta, omite value:
<label for="preparacion">Preparación: duración desconocida</label>
<progress id="preparacion">En preparación</progress>
<p>La preparación continúa; todavía no hay un porcentaje disponible.</p>
El navegador puede mostrar un indicador animado, según su presentación. Este fragmento solo ilustra el estado indeterminado: no inicia una preparación real. No inventes un porcentaje a partir del tiempo transcurrido si no conoces el trabajo total.
Para pasar a ese estado desde JavaScript, utiliza barra.removeAttribute("value"). Para volver a un avance conocido, define el máximo adecuado y asigna barra.value = 2, por ejemplo. Escribir value="0" o dejar value="" no produce indeterminación: el atributo sigue presente. La referencia de progress en MDN explica esta diferencia.
Atributos y propiedades
Los atributos específicos son dos:
value: trabajo completado, como número entre 0 ymax. Su ausencia indica progreso indeterminado.max: trabajo total; debe ser un número mayor que 0. Si se omite, su valor predeterminado es 1, no 100.
No existe un atributo específico min: el mínimo es siempre 0. Usa números sin unidades ni %, y punto para decimales. Así, value="0.6" sin max expresa el 60 %; value="60" max="100" expresa la misma proporción. Mantén los valores dentro del rango aunque el navegador ajuste entradas inválidas.
id, class y lang son atributos globales. Una propiedad CSS como width cambia la anchura visual. En JavaScript, las propiedades DOM .value y .max modifican los valores; .position permite consultar la fracción completada y devuelve −1 en estado indeterminado. .value devuelve 0 también en ese estado: por sí sola no permite distinguirlo del comienzo de una tarea. Consulta la interfaz HTMLProgressElement.
Caso práctico: completar cinco fases con JavaScript
Guarda el siguiente código como fases.html, en UTF-8, y ábrelo en el navegador. Incluye todo lo necesario; no requiere CSS, archivos adicionales ni servidor. Cada activación del botón simula una fase terminada. No sube archivos ni mide una descarga real.
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cinco fases de una demostración</title>
</head>
<body>
<h1>Completar cinco fases</h1>
<p>Demostración local: cada pulsación completa una fase ficticia.</p>
<p>
<label for="fases-avance">Fases de la demostración</label>
<progress id="fases-avance" value="0" max="5"
aria-describedby="fases-detalle">0 de 5</progress>
</p>
<p id="fases-detalle">0 de 5 fases completadas (0 %).</p>
<button id="fases-completar" type="button" disabled>
Completar una fase
</button>
<p id="fases-aviso" role="status"></p>
<noscript>
<p>El botón necesita JavaScript. La demostración permanece en 0 de 5.
Para probar otro valor, edita value y los textos del archivo.</p>
</noscript>
<h2>Un estado indeterminado de muestra</h2>
<label for="fases-espera">Preparación: duración desconocida</label>
<progress id="fases-espera">En preparación</progress>
<p>Esta barra ilustra una tarea sin porcentaje conocido;
no hay ninguna operación remota en curso.</p>
<script>
const barra = document.getElementById("fases-avance");
const detalle = document.getElementById("fases-detalle");
const boton = document.getElementById("fases-completar");
const aviso = document.getElementById("fases-aviso");
boton.disabled = false;
boton.addEventListener("click", () => {
barra.value = Math.min(barra.value + 1, barra.max);
const porcentaje = Math.round(100 * barra.value / barra.max);
barra.textContent = `${barra.value} de ${barra.max}`;
detalle.textContent =
`${barra.value} de ${barra.max} fases completadas (${porcentaje} %).`;
if (barra.value === barra.max) {
boton.disabled = true;
aviso.textContent = "Demostración terminada: las cinco fases están completas.";
}
});
</script>
</body>
</html>
Prueba el ejemplo paso a paso:
- Pulsa
Tabhasta el botón y actívalo conEnteroEspacio. Cada activación aumenta una fase y actualiza el texto: 20 %, 40 %, 60 %, 80 % y 100 %. - En la quinta fase, la barra queda completa, aparece el aviso final y el botón se deshabilita. Recarga para comenzar de nuevo.
- Retira
valuedel segundo indicador si lo habías añadido: vuelve al estado indeterminado. Añadevalue="0"para compararlo con una barra determinada vacía. - Desactiva JavaScript y recarga. El primer avance permanece en 0 de 5, el botón está deshabilitado y aparece la explicación alternativa; el segundo indicador mantiene su estado indeterminado.
Cambiar .value no sincroniza automáticamente los textos: el script actualiza tanto el mensaje visible como el contenido alternativo de la barra. En una aplicación real, sustituye el incremento ficticio por información de la operación que estés siguiendo.
Accesibilidad y mensajes de estado
Utiliza una <label> asociada y conserva la cantidad visible fuera del indicador. No añadas role="progressbar" ni aria-valuenow para recrear la semántica que ya aporta <progress>. El indicador no es un control para introducir datos y no necesita una parada de Tab.
En el ejemplo, el contador visible no es una región viva. Solo el aviso final usa role="status", cuyo anuncio es cortés según WAI-ARIA. Esto evita solicitar un anuncio adicional por cada fase. Para operaciones con actualizaciones muy frecuentes, comunica hitos útiles en vez de anunciar cada cambio. El anuncio concreto depende del navegador y del lector de pantalla; revisa nombre, valores y mensajes con las herramientas y tecnologías de asistencia que vayas a utilizar.
Errores frecuentes y etiquetas relacionadas
¿Cómo hago progreso indeterminado? Omite o retira value; cero significa un avance conocido que todavía no ha comenzado.
¿Progress y meter son equivalentes? No. <meter> representa una medición dentro de un rango, como 60 GB de disco usado. <progress> representa la parte completada de una tarea, como tres de cinco fases.
Si la barra parece llena demasiado pronto, comprueba max: su predeterminado es 1. Revisa después el rango y que los números no lleven porcentajes o comas decimales. Si no cambia, verifica que el evento se ejecuta y que el script selecciona el ID correcto. Un nombre ausente exige comprobar la coincidencia entre for e id y evitar IDs duplicados.
<button> activa la acción del ejemplo; <output> puede expresar un resultado calculado, pero no sustituye la semántica de avance. Una barra animada tampoco demuestra que exista una descarga: necesitas datos de esa operación.
Compatibilidad y fuentes
Consultado el 3 de octubre de 2026: <progress> y la interfaz utilizada tienen soporte amplio en navegadores actuales, según la compatibilidad del elemento en MDN y la referencia de HTMLProgressElement enlazada antes. La forma y la animación pueden variar; los textos mantienen comprensible el estado. El HTML Living Standard fija el significado y las restricciones de autoría, independientemente del aspecto de la barra.