Añade una barra de progreso de lectura que mida el artículo, se actualice al desplazar y no confunda el pie de página con el contenido.
Medir el artículo y no toda la página
Una barra de progreso de lectura sirve como orientación visual: muestra cuánto recorrido queda dentro de una publicación. Si calculas el porcentaje con la altura completa del documento, también entran los comentarios, las recomendaciones y el pie de página. El resultado puede quedarse a mitad cuando el lector ya terminó el tutorial. Este ejemplo toma como referencia un elemento article concreto y termina cuando su parte inferior llega al borde inferior de la ventana.
Qué porcentaje representa
El cálculo divide la distancia recorrida desde el inicio del artículo por el tramo que permite desplazamiento. No mide comprensión, tiempo dedicado ni palabras realmente leídas. Una persona puede arrastrar la página hasta el final en un segundo. Por eso conviene llamarla progreso de lectura visual y evitar usar ese valor como prueba de que alguien completó una formación. Si necesitas evaluar aprendizaje, añade una actividad o una pregunta relacionada con el contenido.
Código completo para probar en tu navegador
Copia este documento en un archivo index.html, guarda los cambios y ábrelo en el navegador. El ejemplo no requiere bibliotecas.
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Barra de progreso de lectura con JavaScript</title>
<style>
*{box-sizing:border-box}body{font:16px/1.6 system-ui,sans-serif;max-width:900px;margin:2rem auto;padding:1rem;color:#17233b}label{display:block;font-weight:700;margin-top:1rem}input,textarea,select,button{font:inherit;padding:.65rem;max-width:100%}textarea{width:100%}button{cursor:pointer}button:focus-visible,a:focus-visible{outline:3px solid #173b94;outline-offset:3px}[hidden]{display:none!important}[role=tab][aria-selected=true]{background:#173b94;color:white}[role=tab]{border:1px solid #bdcbe2;border-radius:.5rem}[role=tabpanel]{padding:1rem;border:1px solid #bdcbe2}
</style>
</head>
<body>
<div class="lectura" aria-hidden="true"><span id="avance"></span></div>
<article id="articulo">
<h1>Tu artículo</h1>
<p>Coloca aquí el contenido completo de tu publicación.</p>
</article>
<style>
.lectura{position:fixed;inset:0 0 auto;height:4px;z-index:50;background:#dce5f5}
#avance{display:block;height:100%;background:#2459e0;transform:scaleX(0);transform-origin:left}
</style>
<script>
const articulo=document.querySelector('#articulo');
const avance=document.querySelector('#avance');
let pendiente=false;
function actualizar(){
const r=articulo.getBoundingClientRect();
const distancia=Math.max(0,r.height-innerHeight);
const valor=distancia ? Math.min(1,Math.max(0,-r.top/distancia)) : (r.top<=0?1:0);
avance.style.transform='scaleX('+valor+')';
pendiente=false;
}
function solicitar(){
if(!pendiente){pendiente=true;requestAnimationFrame(actualizar);}
}
addEventListener('scroll',solicitar,{passive:true});
addEventListener('resize',solicitar);
new ResizeObserver(solicitar).observe(articulo);
solicitar();
</script>
</body>
</html>Por qué el ejemplo necesita contenido largo
El bloque de prueba incluye solamente un párrafo para que sustituyas el contenido sin copiar texto de relleno. Con un artículo más corto que la ventana no hay recorrido que repartir. El código evita dividir entre cero y muestra el estado completo una vez alcanzado su inicio. Para comprobar la animación introduce varios apartados reales o prueba el snippet en una publicación extensa. No fuerces una altura artificial en producción para que la barra parezca más interesante.
Actualizar sin multiplicar trabajo
El evento scroll puede producirse muchas veces mientras el usuario mueve la página. solicitar agrupa las peticiones pendientes y deja que requestAnimationFrame actualice la transformación en el siguiente fotograma disponible. Esto no convierte cualquier cálculo en gratuito: simplemente evita programar varias actualizaciones iguales antes de dibujar. La barra usa transform en lugar de cambiar continuamente el ancho del documento, de modo que el indicador no altera la distribución del artículo.
Imágenes que cambian la altura
Una fotografía que carga tarde, una respuesta desplegable o una fuente distinta pueden modificar el alto del contenido. ResizeObserver observa el artículo y solicita otro cálculo cuando cambian sus dimensiones. Aun así, reserva espacio para las imágenes con sus proporciones correctas. La barra corrige su medida, pero no evita por sí sola los saltos de diseño. Comprueba especialmente publicaciones con vídeos, tablas y bloques de código que se expanden después de cargar.
Posición de la barra y cabeceras fijas
El ejemplo coloca una línea de cuatro píxeles en la parte superior. Si tu cabecera ocupa ese espacio, decide si el indicador debe aparecer encima o justo debajo. Ajusta inset con la altura real de la cabecera y comprueba su comportamiento al cambiar de tamaño. El z-index no debe crecer sin control para tapar menús o diálogos. También es posible colocar el indicador dentro de la propia cabecera y mantener una jerarquía de capas más fácil de entender.
Accesibilidad sin anuncios constantes
La línea es decorativa y lleva aria-hidden. No se anuncia cada cambio de porcentaje, porque eso interrumpiría la lectura con información de escaso valor. El texto y la navegación del artículo siguen siendo la forma principal de orientarse. Un índice de apartados resulta más útil para quien busca una sección concreta. Evita una transición larga: la posición debe acompañar el desplazamiento sin retrasarse ni añadir movimiento independiente.
Pruebas y ampliaciones razonables
Abre la página en la parte superior, entra desde un enlace a una sección y vuelve al final. Reduce el ancho, gira el móvil y carga una imagen con una conexión lenta. La barra debe permanecer entre cero y uno, sin sobrepasar el borde. Si añades varias publicaciones en una misma página, decide qué artículo será la referencia y reinicializa la observación al cambiarlo. No observes todo el documento cuando solamente necesitas medir una pieza editorial.
Modificar la referencia cuando hay una introducción extensa
El indicador empieza al alcanzar el borde superior del artículo observado. Si dentro incluyes una portada muy alta o un bloque de información previo, también formará parte del recorrido. Puedes crear un contenedor específico alrededor del cuerpo editorial para medir solamente esa zona. Define esa decisión de manera consistente entre publicaciones. Un progreso que empieza después de varias pantallas en unos artículos y desde el título en otros puede resultar desconcertante. Comprueba además cualquier margen exterior: getBoundingClientRect mide la caja del elemento, no una interpretación editorial de dónde empieza la lectura.
No confundir optimización con ausencia de coste
Agrupar actualizaciones reduce trabajo redundante, pero la medición del artículo y el cambio de estilo siguen ocurriendo durante el desplazamiento. Mantén la función pequeña y evita buscar muchos nodos o reconstruir HTML dentro de ella. Si añades cálculos pesados, utiliza las herramientas de rendimiento para observar el efecto en un móvil modesto. No deduzcas fluidez solamente de un ordenador rápido. La versión propuesta observa un único artículo y actualiza una única transformación; conservar ese alcance es parte de que el snippet siga siendo fácil de entender y de mantener.
Limpieza en aplicaciones que cambian de vista
En una página tradicional los observadores y eventos desaparecen al navegar a otro documento. En una aplicación que reemplaza vistas sin recargar, debes retirar los listeners y desconectar ResizeObserver cuando el artículo deja de existir. Guarda las referencias necesarias para hacerlo. Si montas el componente varias veces sin limpieza, puedes terminar midiendo nodos antiguos y ejecutando varias actualizaciones por interacción. No basta con ocultar la barra anterior. El ciclo de vida de la aplicación debe incluir creación, actualización y retirada del comportamiento, además de la apariencia visible del indicador.
Asegurar que el indicador no sustituye el índice
La barra ofrece una referencia aproximada de posición, mientras que un índice permite saltar a una sección concreta. Si el artículo es largo, ambas funciones pueden convivir sin duplicarse. Mantén títulos descriptivos y enlaces internos estables. Una persona que llega buscando la solución de un error quizá no necesita recorrer toda la publicación. No interpretes un salto directo al final como una lectura fallida ni bloquees contenido hasta alcanzar un porcentaje. El indicador debe acompañar una navegación libre y ayudar a orientarse, sin convertirse en una condición artificial para utilizar el tutorial.
Guías relacionadas para seguir practicando
Puedes ampliar esta práctica con Entender position en CSS y Trabajar con el DOM.




