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)
progresses 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 entre0.0y el valor demax, o entre0.0y1.0si el atributomaxno está presente.max: Especifica cuánto representa el total de la tarea; es decir, el valor máximo posible para el atributovalue. Debe ser mayor que0.0. Si no se especifica, su valor por defecto es1.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
maxdebe ser mayor a0.0. - Según las definiciones de cada atributo, las siguientes expresiones son verdaderas:
0.0 <= value <= 1.0(simaxno se especifica).0.0 <= value <= max(simaxse 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
valueni enmax. valuenunca debe superar amax; de hacerlo, el comportamiento en el navegador es indefinido.- Si usas decimales, respeta el estándar: entre
0y1cuando no definesmax. - Si actualizas
valuecon 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-clase | Descripción |
|---|---|
::-webkit-progress-bar | Define el estilo del contenedor (track) de la barra en Chrome y Safari. |
::-webkit-progress-value | Define el estilo del relleno (valor actual) de la barra en Chrome y Safari. |
::-moz-progress-bar | Define 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
heighta 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 atributofor. - 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
valuecon JavaScript, actualiza tambiénaria-valuenowpara 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
valueymax. El navegador calcula el porcentaje automáticamente.
- Muestra visualmente el avance de una tarea usando los atributos
- ¿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
.valuedirectamente.
- Selecciona el elemento y modifica su propiedad
- ¿Cómo se hace una barra para un formulario multi-step?
- Asigna a
valueel número de paso actual y amaxel total de pasos.
- Asigna a
- ¿Cómo la hago accesible?
- Usa atributos ARIA:
aria-valuenow,aria-valuemin,aria-valuemax, y vincula un<label>al elemento.
- Usa atributos ARIA:
- ¿Cómo la estilizo para que se vea igual en todos los navegadores?
- Resetea con
-webkit-appearance: noney aplica estilos usando los pseudo-elementos::-webkit-progress-bar,::-webkit-progress-valuey::-moz-progress-bar.
- Resetea con
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.