31 puntos por GN⁺ 2025-06-27 | 2 comentarios | Compartir por WhatsApp
  • Es posible implementar animaciones vinculadas al scroll solo con CSS, sin JS ni librerías adicionales
  • Con propiedades CSS como animation-timeline: scroll() / view(), la animación avanza según la posición del scroll o la entrada al viewport
  • La propiedad animation-range permite ajustar en detalle en qué tramo del viewport empieza y termina la animación
  • Para usuarios sensibles al movimiento, se recomienda usar la media query prefers-reduced-motion
  • Desde Safari 26 beta hay soporte, lo que amplía mucho el alcance de uso de las animaciones de scroll basadas en CSS

Los 3 elementos de la animación basada en scroll

  • Target: el elemento objetivo al que se aplicará la animación (por ejemplo, una barra de progreso o una imagen)
  • Keyframes: define qué cambios ocurrirán según el scroll (igual que en @keyframes de CSS tradicional)
  • Timeline: determina cuándo y cómo avanza la animación (basado en scroll/vista, no en tiempo)

Timeline en CSS

  • Las animaciones CSS tradicionales usan por defecto la document timeline (basada en tiempo)
  • Con la introducción de la propiedad animation-timeline (CSS Animations Level 2, 2023), ahora es posible hacer que la animación avance según criterios distintos al tiempo, como el scroll o la entrada al viewport

timeline scroll()

  • La timeline scroll() hace que la animación avance solo cuando el usuario hace scroll
  • Ejemplo: una barra de progreso inferior que se llena de izquierda a derecha conforme se hace scroll
    footer::after {  
      content: "";  
      height: 1em;  
      width: 100%;  
      background: rgba(254, 178, 16, 1);  
      left: 0;  
      bottom: 0;  
      position: fixed;  
      animation: grow-progress linear;  
      animation-timeline: scroll();  
    }  
    @keyframes grow-progress {  
      from { transform: scaleX(0); }  
      to { transform: scaleX(1); }  
    }  
    
  • animation-timeline debe definirse después de la propiedad animation para que funcione correctamente

Consideraciones de accesibilidad para movimiento

  • Para proteger a usuarios sensibles al movimiento, se recomienda usar la media query prefers-reduced-motion
    @media not (prefers-reduced-motion) {  
        /* código de animación */  
    }  
    

timeline view()

  • La timeline view() inicia la animación cuando el elemento objetivo aparece en el viewport
  • Ejemplo: al hacer scroll, una imagen se desliza desde la derecha y aparece gradualmente
    @keyframes slideIn {  
      0% {  
        transform: translateX(100%);  
        opacity: 0;  
      }  
      100% {  
        transform: translateX(0%);  
        opacity: 1;  
      }  
    }  
    img {  
      animation: slideIn;  
      animation-timeline: view();  
    }  
    

Control del tramo de avance con animation-range

  • De forma predeterminada, animation-range va de 0% (entrada al viewport) a 100% (salida completa)

  • Ejemplo: hacer que la animación avance solo hasta el tramo del 50% del viewport

    img {  
      animation: slideIn;  
      animation-timeline: view();  
      animation-range: 0% 50%;  
    }  
    
  • Para una buena experiencia de usuario, es necesario ajustar valores adecuados de range

  • Si se considera la accesibilidad de movimiento, conviene usarlo junto con prefers-reduced-motion

    @media not (prefers-reduced-motion) {  
      img {  
        animation: slideIn;  
        animation-timeline: view();  
        animation-range: 0% 50%;  
      }  
    }  
    

Uso avanzado y siguientes pasos

  • scroll() y view() son funciones, y permiten especificar varias opciones como el elemento scroller (predeterminado: nearest) o el eje (block, inline, x, y)
  • Con animation-range, entry/exit y otros, se puede construir una UX mucho más precisa
  • El soporte inicial está llegando en navegadores recientes como Safari 26 beta, y se espera que con el tiempo aumenten la estandarización y la compatibilidad

2 comentarios

 
shakespeare 2025-06-29

Se puede implementar solo con animation-timeline. ¡Qué curioso!

 
[Este comentario fue ocultado.]