¡Hola Devs! Olvídate del IntersectionObserver 🚀

Si alguna vez te has pasado una tarde entera escribiendo callbacks de IntersectionObserver solo para que un div haga fade-in al entrar en pantalla, esto te va a interesar. Y mucho.

La nueva propiedad animation-trigger hace exactamente eso: retrasa el inicio de una animación CSS hasta que se dispare un trigger con nombre — ya sea por posición de scroll, intersección con el viewport, o incluso un evento del DOM como un click.

.element {
  /* Espera a que --trigger se active, reproduce al entrar y al revés al salir */
  animation: fade-in 0.35s ease-in-out both;
  animation-trigger: --trigger play-forwards play-backwards;
}

Una sola línea reemplaza un bloque bastante grande de JS. Vamos a ver cómo funciona de verdad.

⚠️ Ojo, Dev: la spec sigue en Editor's Draft y solo corre en Chrome 145+. Trátalo como experimental hasta que haya soporte más amplio.

El artículo original sobre animation-trigger es la 근거자료 por si quieres profundizar en la spec.

Developer writing CSS animation-trigger property code in a modern editor for scroll-triggered effects Dev Environment Setup

Cómo funciona animation-trigger de verdad

Sintaxis

animation-trigger: none | <nombre-trigger> <acción> [<acción>];
  • none — por defecto; la animación se comporta normal.
  • <nombre-trigger> — un dashed ident (ej.: --fade-in-trigger) que debe coincidir con un nombre definido por timeline-trigger o event-trigger.
  • <acción> — qué hacer cuando el trigger se activa (y opcionalmente, cuando se desactiva).

Las acciones disponibles

AcciónComportamiento
play-forwardsReproduce hacia adelante
play-backwardsReproduce al revés
playReproduce a la velocidad actual
play-onceSolo desde el estado inicial/pausado; ignora si ya terminó
pauseCongela en el lugar
resetVuelve el progreso a 0 y pausa
replayVuelve a 0 y reproduce de inmediato
noneNo hace nada

Algunas acciones no son exclusivas — puedes combinar play-backwards al entrar con play-forwards al salir para efectos reversibles.

Configurando un timeline-trigger

No puedes usar animation-trigger solo. Primero necesitas una fuente de trigger:

.trigger {
  /* Shorthand: nombre | fuente | activation-range / active-range */
  timeline-trigger: --trigger scroll() contain / cover;
}

Separado en longhands:

.timeline-trigger-name: --fade-in;
timeline-trigger-source: view();
timeline-trigger-activation-range: contain;
timeline-trigger-active-range: cover;
  • activation-range — cuándo se enciende el trigger (ej.: contain = elemento totalmente visible).
  • active-range — el límite externo donde el trigger sigue activo. Si lo omites, hereda el activation range.
  • El active range debe incluir el activation range, o el trigger nunca se enciende.

A diferencia de background o border, el orden del shorthand es fijo. No lo revuelvas.

Enganchándolo a la animación

/* El trigger vive en un elemento centinela padre */
.trigger {
  timeline-trigger: --trigger scroll() contain / cover;
}

/* La animación aplica a cuantos hijos quieras */
.text {
  animation-trigger: --trigger play;
  animation: fade 0.6s ease-out;
}

Como trigger y animación están desacoplados, un trigger puede manejar varios elementos. Pones un centinela al inicio de una sección y todos los hijos animan juntos al entrar al viewport — sin observer por elemento.

Scope de triggers

Por defecto, los nombres de trigger son globales. Si dos elementos declaran --trigger, el último en la cascada gana. Usa trigger-scope para restringirlo a un subtree del DOM — esencial para componentes reutilizables.

Laptop screen showing Chrome DevTools inspecting CSS timeline-trigger and animation-trigger values System Abstract Visual

Scroll-triggered vs. scroll-driven: NO son lo mismo

Esta es la confusión más común. Los nombres se parecen, los dos usan scroll, pero resuelven problemas distintos.

AspectoScroll-DrivenScroll-Triggered
Modelo de progresoContinuo, atado al offset del scrollEstado binario (on/off)
TimingScrubbing frame a frame con el scrollDispara una vez, luego corre como animación CSS normal
¿Reversible?Sí, naturalmenteSolo si defines acción de desactivación
Uso típicoParallax, barras de progreso, reveals stickyFade-ins, reveals puntuales, llamar la atención
Propiedad claveanimation-timeline: scroll()animation-trigger: --x play

En resumen: scroll-driven = scrub, scroll-triggered = dispara. Si necesitas rebobinar conforme subes, es scroll-driven. Si necesitas un momento discreto de "entró, reproduce", es trigger.

Cuidados que NO puedes ignorar

  • Solo Chrome 145+. Firefox y Safari aún no lo entregan. Cualquier uso en producción hoy requiere feature query o fallback a IntersectionObserver.
  • Estado de Editor's Draft. La spec puede cambiar. Nombres, keywords y orden del shorthand no están congelados.
  • Scope global por defecto. Fácil de colisionar en codebases grandes; siempre usa trigger-scope en componentes.
  • No hay animation-trigger sin fuente. Aún necesitas timeline-trigger o event-trigger configurado.
  • El debug es complicado. El soporte de DevTools para rangos de activación todavía está madurando.

Si te late mantener pipelines con "human-in-the-loop" en proyectos open source, los mismos principios de scope y fallback aplican — checa el pipeline semanal de huggingface_hub para un paralelo en CI.

Web designer previewing scroll-triggered text reveal animation in browser with CSS animation-trigger property Development Concept Image

¿Dónde nos deja esto?

animation-trigger es la dirección correcta para la plataforma web: menos observers en JS, más CSS declarativo, y una separación limpia entre qué anima y cuándo se dispara. Solo el desacople trigger/animación ya vale la pena — un centinela, varios hijos animando.

Pero no está listo para producción. Solo Chrome, Editor's Draft, y sin degradación graciosa incluida. La jugada pragmática hoy es:

  1. Prototipa con él. Familiarízate con la sintaxis ahora para estar listo cuando Safari y Firefox entreguen.
  2. Usa feature query. Envuelve el uso en @supports (animation-trigger: none) y mantén vivo el fallback con IntersectionObserver.
  3. Scopéa tus triggers. No dejes que nombres globales se vuelvan el próximo !important.

Qué estudiar después

  • Scroll-driven animations (animation-timeline: scroll()) — la spec hermana que querrás en el mismo kit.
  • trigger-scope — para aislar triggers dentro de Web Components.
  • Event triggers — la spec también soporta eventos del DOM, no solo timeline.

Lecturas relacionadas

Este contenido fue redactado con la asistencia de herramientas de IA, basándose en fuentes confiables, y fue revisado por nuestro equipo editorial antes de su publicación. No reemplaza el asesoramiento de un profesional especializado.