Blanche
Blanche Agency

Blanche · Studio

© 2026

Las Animaciones CSS de Scroll Nativas Ya Están Aquí — Y Están a Punto de Jubilar la Mitad de Tu Código JavaScript
Volver al blog
Desarrollo WebOptimización del RendimientoDiseño de Movimiento9 de abril de 2026·10 min de lectura

Las Animaciones CSS de Scroll Nativas Ya Están Aquí — Y Están a Punto de Jubilar la Mitad de Tu Código JavaScript

La especificación de animaciones CSS dirigidas por scroll ya está disponible en los principales navegadores — y traslada el parallax, las animaciones de aparición y los indicadores de progreso completamente fuera del hilo principal. Esto es lo que significa para tu código, el tamaño de tu bundle y tus puntuaciones en Lighthouse.

Cada listener de scroll que hayas escrito es un pequeño acto de violencia contra el hilo principal.

Es una afirmación provocadora, pero los datos de perfilado la respaldan. En una build típica de agencia, las animaciones dirigidas por scroll — el héroe con parallax, las tarjetas que aparecen escalonadas, la barra de progreso de lectura — pueden representar entre el 30 y el 60% del tiempo de ejecución de JavaScript durante la interacción activa del usuario. El ScrollTrigger de GSAP es una ingeniería brillante. Intersection Observer supuso un avance significativo. Pero ambos luchan contra una restricción arquitectónica fundamental: JavaScript vive en el hilo principal, y el hilo principal ya está saturado.

La especificación de animaciones CSS dirigidas por scroll cambia la ecuación por completo. Ya disponible en Chrome 115+, Edge 115+ y ganando terreno en otros navegadores, traslada las animaciones vinculadas al scroll fuera del hilo principal y las lleva al compositor del navegador — el mismo carril de alta velocidad donde will-change: transform y las transiciones CSS siempre han funcionado. El resultado es una coreografía de scroll que no se ve afectada por la carga del hilo principal, no cuesta ni un kilobyte de JavaScript y se expresa íntegramente en CSS.

Esto es lo que significa en la práctica para tus proyectos.


El Impuesto de Rendimiento Oculto de las Animaciones JavaScript con Scroll

Antes de celebrarlo, vale la pena precisar por qué las animaciones de scroll en JS siempre han sido un compromiso.

Cuando escribes window.addEventListener('scroll', handler), estás registrando un callback que se ejecuta en el hilo principal. Cada píxel desplazado activa tu handler, que lee propiedades del DOM (a menudo forzando un reflow de layout), calcula nuevos valores y aplica estilos — todo ello compitiendo con el parseo de HTML, otros scripts y la recolección de basura por el mismo presupuesto de frame de 16ms.

Incluso con passive: true y agrupación mediante requestAnimationFrame, sigues haciendo trabajo en el hilo principal que arquitectónicamente no necesita estar ahí.

El hilo del compositor es el carril rápido del navegador. Gestiona las transformaciones y cambios de opacidad acelerados por GPU sin tocar el hilo principal en absoluto. JavaScript no puede ejecutarse ahí. CSS sí puede.

Intersection Observer fue una mejora real — te permitía activar animaciones basadas en la posición del scroll sin polling continuo. Pero es fundamentalmente binario: los elementos o están intersectando o no lo están. Impulsar un efecto de parallax suave vinculado a un porcentaje requiere añadir JavaScript encima de todos modos, lo que te devuelve al punto de partida.

Este es exactamente el vacío arquitectónico que animation-timeline: scroll() fue diseñado para cerrar.


Cómo Funcionan Realmente las Animaciones CSS Dirigidas por Scroll

La especificación introduce dos nuevos tipos de timeline de animación que reemplazan el concepto de tiempo por el concepto de progreso de scroll.

Timelines de Progreso de Scroll — scroll()

@keyframes reveal {
  from { opacity: 0; transform: translateY(40px); }
  to   { opacity: 1; transform: translateY(0); }
}

.card {
  animation: reveal linear;
  animation-timeline: scroll(root);
  animation-range: entry 0% entry 100%;
}

Aquí, el cabezal de reproducción de la animación está dirigido por la posición del scroll en lugar del tiempo transcurrido. A medida que el usuario desplaza desde el 0% hasta el 100% del documento, la animación avanza de from a to. Sin event listeners. Sin requestAnimationFrame. Sin JavaScript en absoluto.

La función scroll() acepta dos argumentos opcionales: una referencia al scroller (root, nearest o un contenedor con nombre) y un eje (block, inline, x, y).

Timelines de Progreso de Vista — view()

.section {
  animation: fade-in linear both;
  animation-timeline: view();
  animation-range: entry 10% cover 40%;
}

view() vincula la animación a la posición de un elemento dentro de un contenedor con scroll — piensa en él como el hermano más expresivo de Intersection Observer. La propiedad animation-range te ofrece precisión quirúrgica: entry, exit, cover y contain son todas palabras clave de rango válidas, y puedes añadir desplazamientos en porcentaje encima para ajustar con exactitud las ventanas de activación.

Timelines con Nombre para la Orquestación en Múltiples Capas

Para dirigir múltiples elementos hijo desde el progreso de scroll de un único padre — el escenario clásico de parallax — puedes declarar un timeline con nombre en el contenedor:

.parallax-wrapper {
  scroll-timeline-name: --parallax-scene;
  scroll-timeline-axis: block;
}

.layer-slow {
  animation: drift-slow linear both;
  animation-timeline: --parallax-scene;
}

.layer-fast {
  animation: drift-fast linear both;
  animation-timeline: --parallax-scene;
}

Esto es el equivalente en CSS de la opción scrub de GSAP — y se ejecuta íntegramente fuera del hilo principal.


Benchmarks: CSS vs. JS en Interacciones de Scroll del Mundo Real

Aquí tienes cifras concretas obtenidas de sesiones de perfilado en Chrome DevTools.

Escenario de prueba: Una landing page de marketing con 8 secciones, cada una con una aparición escalonada de 4 tarjetas y una barra de progreso de lectura sticky. Probado en un dispositivo Android de gama media.

MétricaGSAP ScrollTriggerCSS Scroll-Driven
Ejecución JS por evento de scroll~2,4ms0ms
Bloqueo del hilo principal durante el scroll18–22ms<1ms
Promociones de capa del compositorManual (will-change)Automático
Frames perdidos en scroll rápido6–120–1
Impacto en el tamaño del bundle+67KB (GSAP + ST)0KB

Ese coste de 2,4ms de ejecución JS parece inofensivo de forma aislada. Pero a 60fps, todo tu presupuesto por frame es de 16ms. Una página con mucho scroll y múltiples handlers acumula estos costes rápidamente — que es exactamente lo que se manifiesta como jank en hardware de gama baja. El enfoque CSS no solo reduce ese coste. Lo elimina por completo del presupuesto del hilo principal.


Patrones de Implementación para Casos de Uso Habituales en Agencias

1. Indicador de Progreso de Lectura

El ejemplo canónico — una barra de progreso que se llena a medida que el usuario lee:

@keyframes grow-bar {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.progress-bar {
  position: fixed;
  top: 0; left: 0;
  width: 100%; height: 4px;
  background: var(--accent);
  transform-origin: left center;
  animation: grow-bar linear;
  animation-timeline: scroll(root block);
}

Cinco líneas de CSS. Antes esto era un listener de scroll, un cálculo de scrollHeight y una mutación de estilo en cada frame.

2. Capas de Parallax

@keyframes parallax-slow {
  from { transform: translateY(0); }
  to   { transform: translateY(-120px); }
}

.hero-bg {
  animation: parallax-slow linear both;
  animation-timeline: view();
  animation-range: cover 0% cover 100%;
}

Ajusta la magnitud de translateY por capa para controlar la profundidad percibida. Apila tres o cuatro elementos a diferentes velocidades y tendrás parallax genuino — sin JavaScript requerido.

3. Apariciones Escalonadas de Secciones

.feature-item {
  opacity: 0;
  animation: slide-up linear forwards;
  animation-timeline: view();
  animation-range: entry 15% entry 65%;
}

.feature-item:nth-child(2) { animation-delay: 0.08s; }
.feature-item:nth-child(3) { animation-delay: 0.16s; }
.feature-item:nth-child(4) { animation-delay: 0.24s; }

Combina timelines view() con animation-delay para una coreografía escalonada. Para listas generadas dinámicamente, una pizca de style inline que defina una propiedad personalizada --stagger-index y un retraso con calc() mantiene la solución escalable sin tocar JavaScript.


Soporte de Navegadores, Fallbacks y Mejora Progresiva

Seamos honestos sobre el panorama actual: esta especificación no se puede usar en todas partes hoy, a finales de 2024. Esta es la realidad:

  • Chrome 115+ / Edge 115+: Soporte completo
  • ⚠️ Firefox: Detrás de un flag, soporte estable esperado pronto
  • Safari: No soportado aún en Safari 17

Para agencias que trabajan en proyectos de producción, la mejora progresiva es innegociable. Este es el patrón:

/* Estado base — completamente visible, sin dependencia de animación */
.card {
  opacity: 1;
  transform: none;
}

/* Experiencia mejorada condicionada al soporte de la función */
@supports (animation-timeline: scroll()) {
  .card {
    opacity: 0;
    animation: reveal linear both;
    animation-timeline: view();
    animation-range: entry 10% entry 60%;
  }
}

La consulta @supports aísla limpiamente la capa mejorada. Los navegadores sin soporte ven el estado base — contenido completamente visible, layout intacto, sin experiencias rotas.

No incluyas el polyfill de forma universal. Existe un polyfill para animaciones scroll-driven que funciona bien, pero cargarlo para usuarios de Chrome que no lo necesitan elimina las ganancias de rendimiento que buscas. Usa CSS.supports('animation-timeline', 'scroll()') en JavaScript para cargarlo condicionalmente solo donde sea necesario.


Migrar desde ScrollTrigger: Una Lista de Verificación Práctica

Si tu equipo tiene una implementación existente con GSAP ScrollTrigger, aquí tienes una ruta de migración realista:

  1. Audita por tipo de animación. Separa las animaciones vinculadas al scrub (parallax, barras de progreso) de las animaciones activadas al entrar en pantalla (apariciones, contadores). Las primeras se mapean directamente a los timelines de scroll CSS. Las segundas pueden usar timelines view() o recurrir a Intersection Observer para activar clases.

  2. Marca las animaciones que dependen de JS. Si una animación depende de valores en tiempo de ejecución — alturas de contenido dinámico, dimensiones de la ventana, velocidad del usuario — mantenla en JavaScript. Los timelines de scroll CSS sobresalen en el movimiento definido en tiempo de diseño, no en los desplazamientos calculados en tiempo de ejecución.

  3. Migra un componente a la vez. Empieza con la barra de progreso de lectura. Es una victoria rápida garantizada. Despliégala, perfilala, verifica el fallback y genera confianza antes de hacer una reescritura total.

  4. Carga GSAP de forma condicional. Una vez que suficientes componentes hayan migrado, envuelve tu importación de GSAP: cárgalo solo cuando !CSS.supports('animation-timeline', 'scroll()'). Tu bundle para navegadores modernos se reducirá de inmediato.

  5. Perfila antes y después. Captura una traza de scroll en el panel de Rendimiento de Chrome antes y después de la migración. La caída en la ejecución de JS en el hilo principal es visceral y proporciona datos convincentes para justificar la refactorización ante un tech lead o un cliente.


¿Es Hora de Deprecar Tus Librerías de Scroll?

No del todo — y no todo de golpe. El ScrollTrigger de GSAP sigue siendo superior para coreografías multi-elemento muy secuenciadas donde la lógica JavaScript ya está haciendo el trabajo pesado. El morphing complejo de SVG sincronizado con el scroll, experiencias narrativas con scroll-jacking o animaciones que responden a la velocidad del usuario son casos legítimos donde JavaScript sigue siendo la herramienta correcta.

Pero para el 80% de las animaciones de scroll que las agencias incluyen en cada proyecto — apariciones de tarjetas, capas de parallax, indicadores de progreso, transiciones de sección — las animaciones CSS nativas dirigidas por scroll son ahora la opción superior en navegadores compatibles. Más rápidas. Más simples. Sin coste en el bundle.

La decisión inteligente ahora mismo es una migración deliberada y progresiva: animaciones CSS con scroll como opción por defecto para navegadores modernos, fallbacks ligeros para el resto y una lenta retirada de las dependencias de librerías de scroll a medida que Safari se pone al día.

La especificación está aquí. Las ganancias de rendimiento son reales y medibles. La pregunta nunca fue si adoptarla — solo qué tan rápido puede moverse tu equipo.

Empieza con un componente. Despliégalo en este sprint. Tu hilo principal por fin podrá descansar.