Maquetación Web Dinámica / Animaciones CSS: de sencillas a profesionales
Scroll-driven animations: el scroll como línea de tiempo
Hasta ahora todas tus animaciones corren contra el reloj: arrancan, duran sus milisegundos, terminan. Esta lección cambia el motor: la animación avanza y RETROCEDE con el scroll del usuario — barra de progreso de lectura, imágenes que se revelan al entrar en pantalla — y lo que hasta 2023 exigía JavaScript y eventos de scroll, hoy son dos propiedades CSS.
El tiempo ya no es tiempo
scroll(): la barra de progreso de lectura
El ejemplo canónico — la barrita que mide cuánto llevas leído — son seis líneas:
Tres detalles donde se junta TODO el curso: crece con scaleX y no con
width (regla de oro), desde la izquierda gracias a transform-origin
(módulo 10), y con curva linear — obligatoria aquí conceptualmente: el
progreso debe ser proporcional al scroll, sin "frenados" artificiales.
scroll(root) significa "la manivela es el scroll del documento"; con
scroll(nearest) sería la del ancestro con scroll más cercano.
<div class="lector">
<div class="barra"></div>
<article>
<h3>El páramo que respira</h3>
<p>Los frailejones crecen un centímetro por año, y algunos ejemplares del páramo de Sumapaz superan los dos metros: llevan ahí más de dos siglos.</p>
<p>Cada hoja aterciopelada atrapa la niebla y la convierte en agua que baja, gota a gota, hasta los acuíferos que abastecen a Bogotá.</p>
<p>Por eso los científicos los llaman "las fábricas de agua": un solo frailejón adulto puede aportar miles de litros al año.</p>
<p>Desplázate dentro de esta caja y mira la barra violeta de arriba: no corre contra el reloj — la conduces tú.</p>
<p>Sube y baja: la barra retrocede contigo. Ese vaivén es la firma de una animación conducida por scroll.</p>
</article>
</div>
<p class="nota">Si la barra no se mueve, tu navegador aún no soporta animation-timeline (ver nota de soporte abajo) — el artículo se lee igual: mejora progresiva.</p>body { font-family: system-ui; padding: 20px; background: #f8fafc; }
.lector { position: relative; max-width: 420px; height: 230px; overflow-y: auto; background: white; border: 1px solid #e2e8f0; border-radius: 12px; }
.barra { position: sticky; top: 0; height: 4px; background: #6d28d9; transform-origin: left center; animation: crecer linear; animation-timeline: scroll(nearest); }
@keyframes crecer { from { transform: scaleX(0); } to { transform: scaleX(1); } }
article { padding: 6px 20px 20px; }
article h3 { color: #1e293b; font-size: 16px; }
article p { color: #475569; font-size: 14px; line-height: 1.7; }
.nota { font-size: 13px; color: #64748b; margin-top: 14px; max-width: 52ch; }view(): reaccionar a ENTRAR en pantalla
scroll() mide el scroll global; view() mide algo más útil aún: la
posición DEL PROPIO ELEMENTO dentro del viewport. La animación corre
mientras el elemento cruza la pantalla — el famoso "reveal on scroll":
Sin animation-range, la animación se repartiría por TODO el trayecto
(el elemento no terminaría de aparecer hasta salir por arriba). El rango
la concentra donde tiene sentido: entry 0% (asoma el borde inferior)
hasta cover 40% (lleva recorrido el 40% del viewport) — aparece
completo apenas está bien visible, como esperas de un reveal. Y de regalo
sobre la versión JavaScript: al hacer scroll inverso, el efecto se
deshace solo.
Tu reveal con view() funciona, pero las imágenes terminan de aparecer justo cuando ya van saliendo por el borde superior — el usuario nunca las ve completas dentro de pantalla. ¿Qué falta?
Soporte: la nota honesta completa
Hablemos claro, porque esta es la API más nueva del curso:
animation-timeline funciona en Chrome y Edge desde 2023, y en el resto
de navegadores está en camino (Safari lo tiene en versiones recientes;
Firefox aún detrás de bandera al escribir esto — verifica en
caniuse.com/css-scroll-timeline,
que para eso te entrenó el módulo 1). ¿Eso lo hace inusable? No — lo hace
candidato PERFECTO a mejora progresiva, y ese es el patrón
profesional:
- La página debe funcionar y verse completa SIN la animación (donde no hay soporte, la barra simplemente no aparece llena o el elemento se ve estático y visible — nunca contenido oculto).
- Cuidado mortal: si tu reveal parte de
opacity: 0EN LA REGLA BASE del elemento, en Firefox ese contenido queda invisible para siempre. Conanimation-timeline, el estado inicial vive en elfromde los keyframes — donde no hay soporte, no se aplica y el elemento se ve normal. La misma lógica delbackwardsvsopacity: 0del quiz de stagger: el estado especial vive en la ANIMACIÓN, no en el elemento. - Si el efecto es imprescindible hoy en todos los navegadores, la herramienta es JavaScript (IntersectionObserver, módulo 14 — o GSAP ScrollTrigger, módulo 16). Saber elegir la herramienta según el requisito ES el criterio senior.
Mini-reto
Ponle a "El Observador" su barra de progreso de lectura (fixed, scaleX,
scroll(root)) y un reveal a las imágenes de los artículos con
view() + animation-range. Después ábrelo en un navegador sin soporte
si tienes alguno a mano — o simúlalo comentando la línea
animation-timeline — y verifica el punto 2: ¿se ve TODO el contenido?
Esa verificación de dos minutos es la diferencia entre mejora progresiva
y página rota.
Qué sigue
El scroll ya anima DENTRO de la página. El siguiente salto es animar ENTRE páginas: que navegar de la portada al artículo no sea un parpadeo en blanco sino una transición fluida tipo app nativa. View Transitions API — y otra vez, sin JavaScript.