
Las animaciones CSS han dejado de ser simples efectos decorativos para convertirse en una parte importante de la experiencia de usuario. Durante mucho tiempo, cuando queríamos crear animaciones vinculadas al desplazamiento de la página, lo habitual era recurrir a JavaScript: escuchar el evento de scroll, calcular la posición del usuario, añadir clases dinámicamente y sincronizar cada movimiento con el avance de la navegación.
Ese enfoque sigue siendo válido en muchos casos, pero también puede añadir complejidad, afectar al rendimiento y hacer que una interacción visual sencilla dependa de demasiado código. Por eso resulta tan interesante la llegada de animation-timeline en CSS, una propiedad que permite controlar el progreso de una animación a partir de una línea de tiempo distinta al tiempo tradicional.
Dicho de una forma sencilla: con animation-timeline, una animación ya no tiene por qué avanzar únicamente durante una cantidad fija de segundos. También puede avanzar según el scroll de la página, el desplazamiento de un contenedor o la visibilidad de un elemento dentro del viewport.
Esto abre la puerta a una nueva generación de animaciones CSS modernas, mucho más conectadas con la interacción real del usuario. Podemos crear barras de progreso de lectura, revelados suaves de contenido, efectos de entrada, transformaciones progresivas o pequeñas microinteracciones sin depender siempre de JavaScript.
En este artículo vamos a ver qué es animation-timeline CSS, cómo funciona una CSS animation timeline, qué relación tiene con scroll timeline CSS y cómo utilizar esta técnica con criterio, accesibilidad y buen rendimiento.
Qué es animation-timeline en CSS
La propiedad animation-timeline permite definir qué línea de tiempo controla el progreso de una animación CSS. En una animación tradicional, lo habitual es trabajar con una duración concreta:
.elemento {
animation: aparecer 1s ease-out forwards;
}
En este ejemplo, la animación empieza, avanza durante un segundo y termina. Es una animación basada en tiempo.
Con animation-timeline, la lógica cambia. La animación puede avanzar en función de otro tipo de timeline, por ejemplo, la visibilidad del elemento en pantalla:
.elemento {
animation: aparecer linear both;
animation-timeline: view();
}
Aquí ya no estamos diciendo que la animación dure un segundo. Estamos indicando que el avance de la animación se relaciona con la presencia del elemento dentro del área visible del navegador.
Esta diferencia es importante porque permite crear efectos mucho más naturales. La animación responde a lo que hace el usuario, no a un temporizador fijo.
Si estás empezando a trabajar con movimiento en interfaces, te recomiendo complementar este tema con la guía sobre animaciones CSS desde cero, donde se explican los fundamentos antes de pasar a técnicas más avanzadas.
De las animaciones temporales a las animaciones guiadas por scroll
Las animaciones CSS clásicas funcionan muy bien para muchos casos. Por ejemplo, un botón puede cambiar de color en 300ms, una tarjeta puede aparecer en 600ms o un icono puede rotar suavemente al hacer hover.
Ese tipo de animaciones siguen siendo útiles, especialmente cuando queremos responder a una acción concreta. Sin embargo, hay situaciones en las que una duración fija no representa bien la interacción.
Pensemos en una barra de progreso de lectura. No queremos que avance automáticamente durante dos segundos. Queremos que avance según el usuario recorre el contenido. Lo mismo ocurre con una sección que se revela al entrar en pantalla: tiene más sentido que la animación dependa de su posición en el viewport que de una duración fija al cargar la página.
Ahí entran las scroll-driven animations, es decir, animaciones impulsadas por el scroll. En este modelo, el desplazamiento controla el progreso de la animación. Si el usuario baja, la animación avanza. Si sube, retrocede. Si se detiene, la animación también se detiene.
Para profundizar en este concepto, puedes enlazar este artículo con una guía específica sobre scroll-driven animations: qué son y cómo usarlas, ya que ambos temas están muy relacionados.
Conceptos clave antes de escribir código
Antes de usar animation-timeline, conviene tener claros algunos conceptos:
Timeline: es la línea de tiempo que controla el progreso de una animación. Puede estar basada en tiempo, scroll o visibilidad.
Scroll progress timeline: es una línea de tiempo basada en el progreso de desplazamiento de un contenedor.
View progress timeline: es una línea de tiempo basada en la visibilidad de un elemento dentro del área visible.
scroll(): función que crea una timeline anónima vinculada al scroll de un contenedor.
view(): función que crea una timeline basada en la visibilidad del propio elemento animado.
animation-range: propiedad complementaria que permite definir en qué tramo de la timeline debe ejecutarse la animación.
Estos términos pueden sonar técnicos al principio, pero se entienden mucho mejor cuando los vemos aplicados a ejemplos reales.
Sintaxis básica de animation-timeline
La estructura habitual combina tres partes: una animación definida con @keyframes, la propiedad animation y la propiedad animation-timeline.
@keyframes aparecer {
from {
opacity: 0;
transform: translateY(2rem);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.elemento {
animation: aparecer linear both;
animation-timeline: view();
}
En este caso, @keyframes define los estados de la animación. La propiedad animation indica qué animación se aplica, con qué interpolación y con qué comportamiento de relleno. Finalmente, animation-timeline: view(); indica que la animación se vincula a la visibilidad del elemento.
Un detalle importante: conviene declarar animation-timeline después del shorthand animation. Esto se debe a que animation puede resetear algunas propiedades relacionadas con la animación. Si escribimos primero animation-timeline y después animation, es posible que la timeline no se aplique como esperamos.
La forma recomendada sería:
.card {
animation: fade-in linear both;
animation-timeline: view();
}
Y no esta:
.card {
animation-timeline: view();
animation: fade-in linear both;
}
Este pequeño detalle puede evitar errores difíciles de detectar.
Ejemplo 1: barra de progreso de lectura con scroll()
Uno de los usos más claros de animation-timeline CSS es crear una barra de progreso que avance a medida que el usuario hace scroll por un artículo.
<div class="reading-progress"></div>
.reading-progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 0.35rem;
transform-origin: left center;
transform: scaleX(0);
z-index: 9999;
animation: progress linear both;
animation-timeline: scroll(root block);
}
@keyframes progress {
to {
transform: scaleX(1);
}
}
En este ejemplo, la animación progress modifica la escala horizontal de la barra. Al principio, scaleX(0) hace que la barra no se vea. Al final, scaleX(1) hace que ocupe todo el ancho disponible.
La clave está en esta línea:
animation-timeline: scroll(root block);
root indica que la timeline se basa en el scroll principal del documento. block indica que se tiene en cuenta el eje de bloque, que normalmente corresponde al desplazamiento vertical en páginas escritas de arriba hacia abajo.
Este tipo de efecto es muy útil en artículos largos, documentación técnica, tutoriales y páginas editoriales. Aporta una referencia visual clara sin interrumpir la lectura.
Además, desde el punto de vista del rendimiento, es preferible animar transform en lugar de modificar directamente el ancho con width. Si quieres profundizar en este criterio, puedes leer el artículo sobre por qué animar transform y opacity antes que width o height.
Ejemplo 2: revelar tarjetas al entrar en pantalla con view()
Otro uso habitual de animation-timeline es animar elementos cuando entran en el viewport. Antes, este patrón solía resolverse con JavaScript y la API Intersection Observer. Ahora, en muchos casos, podemos hacerlo solo con CSS.
<section class="grid">
<article class="card">Contenido 1</article>
<article class="card">Contenido 2</article>
<article class="card">Contenido 3</article>
</section>
.card {
opacity: 0;
transform: translateY(3rem) scale(0.96);
animation: reveal-card linear both;
animation-timeline: view();
animation-range: entry 0% cover 35%;
}
@keyframes reveal-card {
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
Aquí la animación no se ejecuta simplemente al cargar la página. Se vincula a la visibilidad de cada .card. Cuando el elemento entra en pantalla, la animación avanza.
La propiedad animation-range permite ajustar el tramo en el que se desarrolla la animación:
animation-range: entry 0% cover 35%;
Esto indica que la animación empieza cuando el elemento entra en el área visible y progresa durante una parte concreta de su recorrido. El resultado es una aparición más controlada, sin movimientos demasiado bruscos ni animaciones innecesariamente largas.
Este patrón funciona muy bien para listados de proyectos, bloques de servicios, secciones de landing page o tarjetas de contenido.
Ejemplo 3: una timeline con nombre usando scroll-timeline
Además de usar timelines anónimas con scroll() o view(), también podemos crear timelines con nombre. Esto resulta útil cuando varios elementos deben depender del mismo contenedor de scroll o cuando queremos que el CSS sea más explícito.
<div class="scroller">
<div class="content">
<div class="box"></div>
</div>
</div>
.scroller {
height: 400px;
overflow-y: auto;
scroll-timeline: --panel-scroll block;
}
.box {
width: 120px;
height: 120px;
animation: rotate-box linear both;
animation-timeline: --panel-scroll;
}
@keyframes rotate-box {
to {
transform: rotate(360deg);
}
}
En este ejemplo, .scroller define una timeline llamada --panel-scroll. Después, .box utiliza esa timeline para controlar su animación.
Este enfoque puede ser más claro en proyectos grandes, porque permite nombrar la timeline y reutilizarla en diferentes elementos.
Diferencia entre scroll() y view()
Aunque scroll() y view() se utilizan con animation-timeline, no sirven exactamente para lo mismo.
Cuándo usar scroll()
Conviene usar scroll() cuando la animación depende del progreso general de desplazamiento de un contenedor.
Algunos casos habituales son:
- Barras de progreso de lectura.
- Indicadores de avance en una página.
- Animaciones vinculadas al scroll completo de un contenedor.
- Transformaciones progresivas desde el inicio hasta el final de una sección.
Ejemplo:
.progress {
animation: grow linear both;
animation-timeline: scroll(root block);
}
En este caso, la animación se controla mediante el scroll global de la página.
Cuándo usar view()
Conviene usar view() cuando la animación depende de la visibilidad de un elemento concreto.
Algunos casos habituales son:
- Tarjetas que aparecen al entrar en pantalla.
- Imágenes que se revelan progresivamente.
- Títulos que se desplazan suavemente al hacerse visibles.
- Elementos decorativos que reaccionan cuando pasan por el viewport.
Ejemplo:
.image {
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 10% cover 40%;
}
En este caso, la animación se controla por la relación entre el elemento y el área visible.
Una regla práctica para decidir
Puedes quedarte con esta idea:
Si quieres animar algo según el avance total del scroll, usa scroll().
Si quieres animar algo según cuándo aparece en pantalla, usa view().
Esta diferencia ayuda mucho a elegir la solución correcta y evita complicar el CSS sin necesidad.
Buenas prácticas para usar animaciones CSS modernas
animation-timeline es una herramienta potente, pero no conviene usarla sin criterio. Una animación puede mejorar mucho una interfaz, pero también puede empeorarla si añade ruido, distrae o dificulta la lectura.
Prioriza transform y opacity
Para conseguir animaciones más fluidas, es recomendable priorizar propiedades como:
transform
opacity
Estas propiedades suelen ser más eficientes que animar width, height, top, left, margin o padding, porque reducen el riesgo de provocar recálculos de layout costosos.
Por ejemplo, para una barra de progreso es mejor usar:
transform: scaleX();
en lugar de animar directamente:
width
Visualmente pueden parecer soluciones parecidas, pero a nivel de rendimiento no siempre lo son. Este criterio también se relaciona con otras buenas prácticas que puedes ampliar en el artículo sobre animaciones CSS y rendimiento.
Usa animaciones con intención
Una animación debería cumplir una función concreta. Puede guiar la atención, reforzar una jerarquía visual, explicar una relación entre elementos o hacer más fluida una transición.
Lo que conviene evitar son las animaciones gratuitas. Si cada bloque entra con un efecto exagerado, si todo se mueve al mismo tiempo o si el scroll se vuelve incómodo, la experiencia se resiente.
Una buena animación CSS moderna debería sentirse natural. Está ahí para acompañar, no para robar protagonismo.
Si tienes dudas sobre cuándo aplicar movimiento y cuándo simplificar, puedes enlazar este tema con el artículo sobre cuándo usar animaciones CSS y cuándo evitarlas.
Respeta prefers-reduced-motion
No todas las personas disfrutan de las animaciones. Algunas pueden experimentar incomodidad, mareo o fatiga visual con movimientos constantes. Por eso es importante respetar la preferencia del sistema prefers-reduced-motion.
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 1ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
}
.card,
.image,
.section-title {
animation-timeline: auto;
transform: none;
opacity: 1;
}
}
Este bloque reduce o desactiva animaciones para las personas que han indicado esa preferencia en su sistema operativo o navegador.
La accesibilidad no es un añadido final. Es parte de una buena implementación front-end. Por eso, cualquier técnica moderna de animación debería plantearse siempre desde la mejora progresiva y el respeto a las preferencias del usuario.
Añade fallbacks con @supports
Como animation-timeline es una característica moderna, conviene ofrecer una experiencia alternativa en navegadores que no la soporten completamente.
Una buena forma de hacerlo es utilizar @supports:
.card {
opacity: 1;
transform: none;
}
@supports (animation-timeline: view()) {
.card {
opacity: 0;
transform: translateY(2rem);
animation: reveal linear both;
animation-timeline: view();
animation-range: entry 0% cover 35%;
}
}
Así nos aseguramos de que, si el navegador no entiende animation-timeline, el contenido siga siendo visible y usable.
Este punto es fundamental: el contenido nunca debería depender de una animación para poder verse.
Errores frecuentes al usar animation-timeline
Aunque la sintaxis no es excesivamente compleja, hay algunos errores habituales que conviene evitar.
Declarar animation-timeline antes de animation
Como el shorthand animation puede resetear algunas propiedades, es mejor declarar animation-timeline después.
Correcto:
.element {
animation: reveal linear both;
animation-timeline: view();
}
Incorrecto:
.element {
animation-timeline: view();
animation: reveal linear both;
}
Este error puede hacer que la timeline no se aplique correctamente y que la animación se comporte como una animación temporal tradicional.
Olvidar que sigue haciendo falta @keyframes
animation-timeline no crea una animación por sí sola. Solo define qué timeline controla su progreso. Para que haya un cambio visual, necesitamos seguir usando @keyframes.
@keyframes fade-in {
to {
opacity: 1;
}
}
Sin una animación definida, no hay nada que ejecutar.
Animar demasiados elementos a la vez
Aunque CSS permita crear efectos muy llamativos, conviene limitar la cantidad de elementos animados simultáneamente. Una página con demasiadas animaciones vinculadas al scroll puede sentirse pesada, especialmente en dispositivos móviles o equipos con menos potencia.
La recomendación práctica es empezar con pocos efectos, probar la experiencia real y ajustar según el contexto.
No probar en diferentes navegadores
Las animaciones CSS modernas avanzan rápido, pero no siempre llegan igual a todos los navegadores. Antes de utilizar animation-timeline en producción, conviene comprobar la compatibilidad, probar en dispositivos reales y asegurar que el contenido sigue siendo accesible si la animación no se ejecuta.
Ejemplo completo: sección editorial animada con CSS
Veamos ahora un ejemplo más completo. Imaginemos una sección editorial con texto e imagen.
<section class="feature">
<div class="feature__content">
<p class="feature__eyebrow">CSS moderno</p>
<h2 class="feature__title">Animaciones vinculadas al scroll</h2>
<p class="feature__text">
Crea efectos progresivos sin depender de JavaScript para cada interacción visual.
</p>
</div>
<img class="feature__image" src="imagen.jpg" alt="Interfaz con animación CSS">
</section>
.feature {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3rem;
align-items: center;
padding: 6rem 2rem;
}
.feature__content,
.feature__image {
opacity: 0;
transform: translateY(3rem);
animation: reveal-feature linear both;
animation-timeline: view();
animation-range: entry 10% cover 40%;
}
.feature__image {
transform: translateY(3rem) scale(0.96);
}
@keyframes reveal-feature {
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@media (max-width: 768px) {
.feature {
grid-template-columns: 1fr;
}
}
Este ejemplo crea una entrada suave para el contenido y la imagen. La animación está vinculada a la visibilidad de cada elemento, no al momento de carga de la página.
El resultado es una experiencia más natural: el contenido aparece cuando tiene sentido, no antes.
Mejora progresiva aplicada al ejemplo
Para que el ejemplo sea más robusto, podemos envolver la parte avanzada con @supports:
.feature__content,
.feature__image {
opacity: 1;
transform: none;
}
@supports (animation-timeline: view()) {
.feature__content,
.feature__image {
opacity: 0;
transform: translateY(3rem);
animation: reveal-feature linear both;
animation-timeline: view();
animation-range: entry 10% cover 40%;
}
}
De esta manera, los navegadores sin soporte verán el contenido de forma normal. Los navegadores compatibles disfrutarán de la animación.
Este enfoque es muy recomendable para proyectos reales, porque combina innovación con estabilidad.
SEO, UX y rendimiento: por qué importan estas animaciones
Desde el punto de vista SEO, una animación no posiciona por sí sola. Google no va a premiar una página únicamente porque utilice animation-timeline CSS. Sin embargo, una buena experiencia de usuario sí puede influir indirectamente en cómo se percibe el contenido.
Una página clara, fluida, accesible y agradable puede favorecer la lectura, reducir la fricción y ayudar a que las personas permanezcan más tiempo interactuando con el contenido. Pero para lograrlo, las animaciones deben estar al servicio del mensaje.
En artículos técnicos, por ejemplo, una barra de progreso puede ayudar al lector a orientarse. En un portfolio, una animación de entrada puede presentar los proyectos de forma más cuidada. En una landing page, una transición sutil puede reforzar la narrativa visual.
La clave está en usar las animaciones como parte del diseño, no como decoración añadida al final.
Criterios para decidir si una animación aporta valor
Antes de implementar un efecto con animation-timeline, puedes hacerte estas preguntas:
- ¿Ayuda a entender mejor la interfaz?
- ¿Refuerza la jerarquía visual?
- ¿Acompaña una acción del usuario?
- ¿Funciona bien en móvil?
- ¿Sigue siendo usable si la animación no se ejecuta?
- ¿Respeta las preferencias de accesibilidad?
Si la respuesta es sí, probablemente la animación tenga sentido. Si la respuesta es no, quizá conviene simplificar.
Preguntas frecuentes sobre animation-timeline CSS
¿Qué es animation-timeline en CSS?
animation-timeline es una propiedad CSS que permite indicar qué línea de tiempo controla una animación. En lugar de depender únicamente del paso del tiempo, una animación puede progresar según el scroll de la página, el scroll de un contenedor o la visibilidad de un elemento.
Esto permite crear efectos como barras de progreso, revelados al entrar en pantalla o animaciones vinculadas al desplazamiento sin tener que recurrir siempre a JavaScript.
¿Cuál es la diferencia entre scroll() y view()?
scroll() se utiliza cuando queremos que la animación dependa del progreso de desplazamiento de un contenedor. Por ejemplo, una barra que se llena a medida que avanzamos por un artículo.
view() se utiliza cuando queremos que la animación dependa de la visibilidad de un elemento. Por ejemplo, una tarjeta que aparece progresivamente cuando entra en el viewport.
En resumen: scroll() mira el avance del scroll; view() mira la presencia del elemento en la zona visible.
¿Es recomendable usar animation-timeline en producción?
Sí, puede ser recomendable, pero con cuidado. Lo ideal es aplicarlo con mejora progresiva, revisar compatibilidad, usar @supports, mantener el contenido visible aunque la animación no funcione y respetar prefers-reduced-motion.
También conviene probar en dispositivos reales y evitar que las animaciones sean necesarias para comprender o utilizar la página.
Una forma más natural de animar la web
animation-timeline representa un paso importante en la evolución de CSS. Nos permite crear animaciones más conectadas con la interacción real del usuario, especialmente en experiencias basadas en scroll.
La gran ventaja no es solo técnica. También es conceptual. En lugar de pensar en animaciones como eventos aislados que ocurren durante una cantidad fija de segundos, podemos diseñarlas como respuestas progresivas al movimiento, a la lectura y a la presencia del contenido en pantalla.
Esto hace que las interfaces puedan sentirse más vivas, pero también más coherentes. Una barra que avanza mientras leemos, una imagen que se revela cuando llega su momento o una tarjeta que aparece suavemente al entrar en el viewport son detalles que pueden mejorar la experiencia sin sobrecargarla.
Como ocurre con cualquier recurso visual, la clave está en el equilibrio. No se trata de animar por animar, sino de utilizar las herramientas modernas de CSS para construir interfaces más claras, accesibles y agradables.
Si se usa con intención, animation-timeline CSS puede convertirse en una pieza muy valiosa dentro del conjunto de animaciones CSS modernas. Permite reducir dependencias innecesarias de JavaScript, escribir código más declarativo y crear experiencias visuales que acompañan al usuario de forma natural.
En definitiva, las animaciones con animation-timeline no son solo una novedad técnica. Son una invitación a pensar el movimiento en la web de una manera más fluida, contextual y humana.

