Progress Bar HTML5: cómo usar el elemento <progress> con CSS y JavaScript

- Andrés Cruz - EN In english

Progress Bar HTML5: cómo usar el elemento <progress> con CSS y JavaScript

Cuando construimos interfaces que necesitan mostrar avance — sobre todo en formularios paso a paso, que es donde más lo uso — siempre opto primero por la barra de progreso nativa de HTML5: el elemento <progress>.

La progress bar en HTML5 es ligera, accesible, fácil de estilizar y no necesita librerías externas. Es una de esas soluciones que el navegador ya trae resueltas por defecto, y que muchos desarrolladores pasan por alto buscando plugins de terceros.

En este artículo te explico todo lo que debes saber para dominarla: atributos, estados, CSS, JavaScript, accesibilidad y un ejemplo completo listo para usar.

Anteriormente vimos el elemento meter HTML5.

¿Qué es una Progress Bar en HTML5 y para qué sirve?

Una progress bar es un indicador visual que muestra cuánto de una tarea se ha completado. Lo bueno del elemento <progress> es que HTML5 lo incluye como componente nativo, capaz de representar tanto progreso determinado (cuando sabemos el porcentaje exacto) como indeterminado (cuando el proceso está en marcha pero no sabemos cuánto falta).

La función del elemento o etiqueta (tag) progress es la de indicar el estado de terminación de una tarea.

La etiqueta <progress> y su propósito principal

Su sintaxis básica es la siguiente:

<progress></progress>

Como la mayoría de las etiquetas en HTML, presenta una etiqueta de apertura <progress> y otra de cierre </progress>. Por sí sola y sin atributos, la barra entra automáticamente en modo indeterminado (lo veremos más adelante).

Al ser una barra de progreso, lo más común es agregarle un valor de avance:

<progress value="50" max="100"></progress>

Esto representa que la tarea está al 50% de completarse. El atributo value indica el avance actual, mientras que max define el total requerido.

Cuándo usar barras de progreso (y cuándo no)

Son útiles para:

  • Cargas y descargas de archivos.
  • Procesos de espera del servidor.
  • Pasos de un formulario multi-step.
  • Tareas en background (importaciones, procesamiento de datos, etc.).

No tiene sentido usarla para indicar una medición de rango o una escala (por ejemplo, un nivel de batería o temperatura). Para eso existe el elemento <meter>, que semánticamente es más apropiado.

Atributos de la etiqueta (tag) progress

Aparte de los atributos globales para todas las etiquetas (class, id, etc.), y a diferencia del elemento <meter>, el elemento <progress> solo posee dos atributos específicos según la W3C:

  • value: Especifica cuánto de la tarea ha sido completada. Es un número de punto flotante que representa el valor actual. Debe estar entre 0.0 y el valor de max, o entre 0.0 y 1.0 si el atributo max no está presente.
  • max: Especifica cuánto representa el total de la tarea; es decir, el valor máximo posible para el atributo value. Debe ser mayor que 0.0. Si no se especifica, su valor por defecto es 1.0.

Estados del elemento progress

El elemento <progress> puede estar en dos estados: determinado e indeterminado. Entender la diferencia es clave para elegir cuál usar en cada situación.

Estado determinado de la Progress Bar

Para que la barra de progreso se encuentre en estado determinado, el atributo value debe estar presente. El navegador calculará el porcentaje de avance de forma automática basándose en la relación entre value y max.

<progress value="0.5"></progress>

Estado indeterminado de la Progress Bar

Para que la barra entre en estado indeterminado, simplemente no incluyas el atributo value, o remuévelo con JavaScript usando removeAttribute('value'). El navegador mostrará una animación de avance continuo sin un porcentaje definido.

Un caso práctico: imagina que tienes una barra de progreso en tu página y pierdes la conexión con el servidor. Tu código JavaScript debería detectar ese estado y remover el atributo value, indicándole al usuario que hubo un problema de comunicación o que el proceso está en espera, sin que parezca que la barra se quedó congelada.

<progress></progress>

Reglas generales de la Progress Bar (resumen)

  • Todos los atributos mencionados son números de punto flotante mayores a 0.0.
  • El atributo max debe ser mayor a 0.0.
  • Según las definiciones de cada atributo, las siguientes expresiones son verdaderas:
    • 0.0 <= value <= 1.0 (si max no se especifica).
    • 0.0 <= value <= max (si max se especifica).

Sintaxis de <progress>: atributos value y max explicados

Cómo funciona el estado determinado

Una barra es determinada cuando incluye el atributo value. El navegador dibuja la barra rellena proporcionalmente al cociente value / max.

Ejemplo al 40%:

<progress value="40" max="100"></progress>

Si no añades max, su valor por defecto es 1, y puedes usar decimales para expresar el porcentaje como fracción:

<progress value="0.4"></progress>

Cómo funciona el estado indeterminado

Si eliminas el atributo value, el navegador muestra una animación de progreso desconocido (un efecto de barrido continuo). Esto es útil cuando un proceso depende de un servidor externo y no sabes cuánto tiempo tardará.

<progress></progress>

Lo uso cuando un proceso depende de un servidor externo y no sé cuánto falta. De hecho, durante un desarrollo tuve que quitar value temporalmente para indicar que el sistema estaba esperando una respuesta… y funcionó perfecto para que el usuario entendiera que aún no había fallo.

Buenas prácticas para evitar errores comunes

  • No uses valores negativos en value ni en max.
  • value nunca debe superar a max; de hacerlo, el comportamiento en el navegador es indefinido.
  • Si usas decimales, respeta el estándar: entre 0 y 1 cuando no defines max.
  • Si actualizas value con JavaScript, valida siempre que el valor calculado esté dentro del rango permitido antes de asignarlo.

Estilos del elemento (tag) progress

El elemento <progress> es estilizable con CSS, aunque requiere pseudo-elementos específicos del navegador para personalizar su interior. A continuación, los más importantes:

Pseudo-elemento / Pseudo-claseDescripción
::-webkit-progress-barDefine el estilo del contenedor (track) de la barra en Chrome y Safari.
::-webkit-progress-valueDefine el estilo del relleno (valor actual) de la barra en Chrome y Safari.
::-moz-progress-barDefine el estilo del relleno de la barra en Firefox.

Estilizando la barra de progreso con CSS

El estilo nativo funciona, pero suele ser básico y varía bastante entre navegadores. Para personalizar correctamente, primero hay que resetear la apariencia por defecto con -webkit-appearance: none:

progress {
 -webkit-appearance: none;
 appearance: none;
 width: 100%;
 height: 20px;
}

Pseudo-elementos WebKit y Firefox

Para Chrome y Safari:

progress::-webkit-progress-bar {
 background: #eee;
 border-radius: 6px;
}
progress::-webkit-progress-value {
 background: #4caf50;
 border-radius: 6px;
}

Para Firefox:

progress::-moz-progress-bar {
 background: #4caf50;
 border-radius: 6px;
}

Colores, tamaños y estilos personalizados

Gracias a estos pseudo-elementos, puedes crear barras:

  • Redondeadas con border-radius.
  • Con degradados usando background: linear-gradient(...).
  • Con animaciones de transición suaves.
  • Ultra delgadas tipo "YouTube" (ajustando height a 3–4px).

Por ejemplo, para suavizar visualmente el avance del valor:

progress[value]::-webkit-progress-value {
 transition: width .4s ease;
}

Esa transición hace que el avance se perciba fluido en lugar de brusco, mejorando notablemente la experiencia del usuario.

Ejemplo 1: sin atributo max

Este primer ejemplo muestra el caso en que el atributo max no está presente, por lo que toma su valor por defecto de 1.0. El atributo value debe ser entonces un decimal entre 0.0 y 1.0.

Además, se usa un script para variar el valor del elemento <progress> en el tiempo y apreciar su animación y comportamiento.

<progress id="progress1" value="0" ></progress>

Para ver el código completo del experimento, haz clic aquí.

Ejemplo 2: con atributos value y max

Este ejemplo usa ambos atributos explícitamente: value para el avance actual y max para el total. Con max="100" podemos trabajar con valores enteros de 0 a 100, lo que resulta más intuitivo para representar porcentajes.

<progress id="progress2" max="100" value="0" ></progress>

Para ver el código completo del experimento, haz clic aquí.

Ejemplo 3: personalizando la barra con CSS

Podemos personalizar el tag progress de diversas maneras: cambiando el border-radius, el background, el padding y muchas propiedades más. A continuación, un ejemplo con estilos aplicados tanto para Chrome/Safari (::-webkit-progress-bar, ::-webkit-progress-value) como para Firefox (::-moz-progress-bar):

progress {
	display:block;
	-webkit-appearance: none;
}

progress::-webkit-progress-bar {
	background: black;
	border-radius: 50px;
	padding: 2px;
}
progress::-moz-progress-bar {
	background: black;
	border-radius: 50px;
	padding: 2px;
}

progress::-webkit-progress-value {
	border-radius: 50px;
	background:orange;
}

Para ver el código completo del experimento, haz clic aquí.

Actualizar la Progress Bar con JavaScript

Cambiar value dinámicamente

Modificar el valor de una barra de progreso desde JavaScript es muy sencillo. Basta con acceder al elemento y asignarle un nuevo valor a su propiedad .value:

const bar = document.querySelector('progress');
bar.value = 70;

Para pasar al estado indeterminado desde JavaScript, simplemente remueve el atributo:

bar.removeAttribute('value');

Animar la barra de progreso

Ideal para procesos en background que incrementan el valor gradualmente:

setInterval(() => {
 if (bar.value < bar.max) bar.value++;
}, 100);

Ejemplo: barra con actualización en tiempo real

En mis formularios por pasos, actualizo la barra cuando el usuario completa una sección. Este pequeño helper centraliza la lógica:

function setStepProgress(step, totalSteps) {
 const bar = document.getElementById('form-progress');
 bar.value = step;
 bar.max = totalSteps;
}

Ese simple fragmento hace que el usuario sienta que avanza. La diferencia en la tasa de abandono de formularios es notable cuando el usuario puede ver su progreso en todo momento.

Progress Bar en formularios paso a paso (multi-step forms)

Esta es precisamente la razón por la que uso <progress> casi a diario. Cuando los formularios tienen 3, 4 o 5 pasos, mostrarle al usuario en qué punto está aumenta significativamente la tasa de finalización. La percepción de avance reduce la sensación de esfuerzo.

Cómo calcular el progreso por pasos

La lógica es sencilla: asigna a max el número total de pasos y a value el paso actual. Si tienes 4 pasos:

  • Paso 1 → value="1"
  • Paso 2 → value="2"
  • Paso 3 → value="3"
  • Paso 4 → value="4"

Y max="4".

Ejemplo práctico: barra de progreso para formulario multi-step

A continuación, un ejemplo completo que combina la barra de progreso con <label> para mostrar el paso actual, y un script JavaScript que gestiona la navegación entre pasos:

<progress id="form-progress" value="1" max="4"></progress>
<div class="step step-1">Contenido del paso 1…</div>
<div class="step step-2" style="display:none">Paso 2…</div>
<div class="step step-3" style="display:none">Paso 3…</div>
<div class="step step-4" style="display:none">Paso 4…</div>
<button id="next">Siguiente</button>

<script>
let step = 1;
document.getElementById('next').addEventListener('click', () => {
 const totalSteps = 4;
 if (step < totalSteps) {
   document.querySelector('.step-' + step).style.display = 'none';
   step++;
   document.querySelector('.step-' + step).style.display = 'block';
   setStepProgress(step, totalSteps);
 }
});
function setStepProgress(step, total) {
 const bar = document.getElementById('form-progress');
 bar.value = step;
 bar.max = total;
}
</script>

Consejos de UX basados en experiencia real

  • Mostrar el paso actual sobre el total (ej. "Paso 2 de 4") aumenta la claridad y reduce la ansiedad del usuario.
  • Las barras que avanzan suavemente (con transición CSS) generan más confianza que las que saltan de golpe.
  • Noté que cuando usé una barra sin porcentaje numérico, los usuarios avanzaban más rápido: la sensación de progreso visual es suficiente motivación.

Accesibilidad: cómo hacer una Progress Bar accesible

El elemento <progress> ya tiene semántica incorporada que los lectores de pantalla entienden. Aun así, es buena práctica reforzarlo con atributos ARIA para garantizar una experiencia accesible en todos los contextos:

<label for="task-progress">Progreso de carga:</label>
<progress id="task-progress" value="40" max="100"
 aria-valuenow="40"
 aria-valuemin="0"
 aria-valuemax="100">
 40%
</progress>

Tips rápidos de accesibilidad:

  • Usa siempre una etiqueta <label> vinculada al elemento mediante el atributo for.
  • Añade texto alternativo dentro del elemento (por ejemplo, "40%") para navegadores muy antiguos o contextos sin soporte.
  • Mantén buen contraste entre el color de la barra y el fondo del track.
  • Cuando actualices value con JavaScript, actualiza también aria-valuenow para mantener sincronizados los lectores de pantalla.

Compatibilidad entre navegadores

  • Chrome, Firefox, Edge y Safari soportan <progress> de forma nativa.
  • Las diferencias visuales existen entre navegadores, pero puedes nivelarlas completamente con los pseudo-elementos CSS descritos anteriormente.
  • En móviles funciona bien de manera nativa, pero conviene darle más altura (al menos 12–16px) para que sea más visible y cómoda de interactuar en pantallas táctiles.

Ejemplo completo: Progress Bar HTML5 animada con JavaScript y CSS

En este ejemplo completo vemos cómo combinar HTML, CSS y JavaScript para crear una barra de progreso animada que simula un proceso de carga usando requestAnimationFrame:

<label for="demo-progress">Progreso:</label>
<progress id="demo-progress" value="30" max="100"></progress>

<script>
function simulate() {
 const bar = document.getElementById('demo-progress');
 if (bar.value < bar.max) {
   bar.value += 1;
   requestAnimationFrame(simulate);
 }
}
simulate();
</script>

<style>
progress {
 width: 100%;
 height: 20px;
 -webkit-appearance: none;
 appearance: none;
 border-radius: 8px;
}
progress::-webkit-progress-bar {
 background: #eee;
 border-radius: 8px;
}
progress::-webkit-progress-value {
 background: #ff8a00;
 border-radius: 8px;
 transition: width .3s ease;
}
progress::-moz-progress-bar {
 background: #ff8a00;
 border-radius: 8px;
}
</style>

Nótese el uso de requestAnimationFrame en lugar de setInterval: es más eficiente porque el navegador lo sincroniza con el ciclo de repintado, evitando actualizaciones innecesarias cuando la pestaña está en segundo plano.

Preguntas frecuentes sobre la Progress Bar HTML5

  • ¿Cómo funciona la etiqueta <progress>?
    • Muestra visualmente el avance de una tarea usando los atributos value y max. El navegador calcula el porcentaje automáticamente.
  • ¿Qué pasa si no pongo value?
    • La barra entra en modo indeterminado, mostrando un movimiento continuo sin porcentaje definido.
  • ¿Cómo actualizo la barra con JavaScript?
    • Selecciona el elemento y modifica su propiedad .value directamente.
  • ¿Cómo se hace una barra para un formulario multi-step?
    • Asigna a value el número de paso actual y a max el total de pasos.
  • ¿Cómo la hago accesible?
    • Usa atributos ARIA: aria-valuenow, aria-valuemin, aria-valuemax, y vincula un <label> al elemento.
  • ¿Cómo la estilizo para que se vea igual en todos los navegadores?
    • Resetea con -webkit-appearance: none y aplica estilos usando los pseudo-elementos ::-webkit-progress-bar, ::-webkit-progress-value y ::-moz-progress-bar.

Conclusiones

La progress bar HTML5 es una de esas herramientas que el navegador ya trae listas para usar y que, bien aplicadas, tienen un impacto real en la experiencia del usuario. No hace falta una librería externa para mostrar avance: con el elemento <progress>, dos atributos (value y max), algo de CSS y unas pocas líneas de JavaScript tienes todo lo que necesitas.

Úsala en cargas de archivos, procesos en background o formularios multi-step, y notarás cómo los usuarios se sienten más orientados y menos propensos a abandonar el flujo.

Siguiente paso: cómo usar el elemento dialog en HTML5.

Aprende a crear una progress bar en HTML5 con el elemento . Atributos value y max, estados determinado e indeterminado, estilos CSS cross-browser y ejemplos con JavaScript, incluidos formularios multi-step.


Únete a la comunidad de desarrolladores que han decidido dejar de picar código y empezar a construir productos reales. Recibe mis mejores trucos de arquitectura cada semana:

Acepto recibir anuncios de interes sobre este Blog.