Animaciones CSS impulsadas por desplazamiento: 5 patrones de animación de desplazamiento con CSS puro sin JavaScript
Animaciones CSS Impulsadas por Desplazamiento: Desplazamiento Suave Sin JS
Parallax con listeners de desplazamiento JS causando tartamudeo, código verboso de IntersectionObserver, sobrecarga de rendimiento de requestAnimationFrame — las animaciones de desplazamiento han dependido durante mucho tiempo de JavaScript. Las animaciones CSS impulsadas por desplazamiento te permiten implementar parallax, barras de progreso y animaciones de revelación puramente en CSS: cero JS, 60fps, aceleración GPU automática. En 2026, las animaciones CSS impulsadas por desplazamiento son totalmente soportadas en Chrome y Safari.
Este artículo cubre 5 patrones principales, guiándote a través de scroll-timeline → view-timeline → parallax → indicador de progreso → animaciones de revelación.
Conceptos Básicos
| Concepto | Descripción |
|---|---|
| scroll-timeline | Línea de tiempo de animación basada en la posición de desplazamiento |
| view-timeline | Línea de tiempo de animación basada en la visibilidad del elemento |
| animation-timeline | Especifica qué línea de tiempo de desplazamiento usa una animación |
| animation-range | Posiciones de inicio y fin de la animación dentro del rango de desplazamiento |
| scroll() | Función de línea de tiempo de desplazamiento anónima |
| view() | Función de línea de tiempo de vista anónima |
| scroll-progress | Progreso de desplazamiento 0-1 |
| view-progress | Progreso de visibilidad 0-1 |
Análisis del Problema: 5 Desafíos Principales de Animación de Desplazamiento CSS
- Compatibilidad de navegadores: El soporte de Firefox va por detrás
- Depuración difícil: El soporte de DevTools para animaciones de desplazamiento es limitado
- Desplazamiento anidado: La configuración de contenedores de desplazamiento que no son del documento es compleja
- Cálculo del rango de animación: El porcentaje de animation-range tiene alto costo de comprensión
- Fallback: Los navegadores no soportados necesitan fallback con JS
Paso a Paso: 5 Patrones de Animación de Desplazamiento CSS
Patrón 1: Animación de Progreso de Desplazamiento con scroll-timeline
/* Barra de progreso superior de la página */
@keyframes progress-bar {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
.progress-bar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: linear-gradient(90deg, #6366f1, #ec4899);
transform-origin: left;
animation: progress-bar linear;
animation-timeline: scroll(root);
}
Patrón 2: Animación de Revelación en Viewport con view-timeline
@keyframes reveal-up {
from {
opacity: 0;
transform: translateY(60px) scale(0.95);
filter: blur(4px);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
filter: blur(0);
}
}
.card {
animation: reveal-up linear both;
animation-timeline: view();
animation-range: entry 0% entry 80%;
}
Patrón 3: Efecto de Desplazamiento Parallax
@keyframes parallax-slow {
from { transform: translateY(0); }
to { transform: translateY(-100px); }
}
@keyframes parallax-fast {
from { transform: translateY(0); }
to { transform: translateY(-300px); }
}
.parallax-bg {
animation: parallax-slow linear both;
animation-timeline: scroll(root);
}
.parallax-fg {
animation: parallax-fast linear both;
animation-timeline: scroll(root);
}
Patrón 4: Línea de Tiempo de Desplazamiento Nombrada
.scroller {
overflow-y: auto;
scroll-timeline-name: --my-scroller;
scroll-timeline-axis: block;
}
@keyframes rotate-icon {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.rotating-icon {
animation: rotate-icon linear;
animation-timeline: --my-scroller;
}
Patrón 5: Secuencias de Animación Complejas
@keyframes hero-sequence {
0% {
opacity: 0;
transform: translateY(100px) scale(0.8);
filter: blur(10px);
}
30% {
opacity: 1;
transform: translateY(0) scale(1);
filter: blur(0);
}
70% {
opacity: 1;
transform: translateY(0) scale(1);
}
100% {
opacity: 0;
transform: translateY(-50px) scale(0.95);
}
}
.hero-title {
animation: hero-sequence linear both;
animation-timeline: view();
animation-range: entry 0% exit 100%;
}
Guía de Problemas Comunes
Problema 1: No especificar animation-timeline
/* ❌ Incorrecto: falta animation-timeline */
.element {
animation: slide-in 1s linear;
/* La animación no seguirá el desplazamiento */
}
/* ✅ Correcto: especificar línea de tiempo de desplazamiento */
.element {
animation: slide-in linear both;
animation-timeline: view();
}
Problema 2: Valores incorrectos de animation-range
/* ❌ Incorrecto: el rango excede el rango de desplazamiento */
.element {
animation-range: entry 0% entry 200%; /* 200% inválido */
}
/* ✅ Correcto: usar rango válido */
.element {
animation-range: entry 0% entry 100%;
}
Problema 3: Transform en conflicto con el desplazamiento
/* ✅ Correcto: usar sugerencia will-change */
.parallax {
animation: parallax linear both;
animation-timeline: scroll(root);
will-change: transform;
}
Problema 4: No manejar el fallback
/* ✅ Correcto: proporcionar fallback */
@supports (animation-timeline: view()) {
.card {
animation: reveal-up linear both;
animation-timeline: view();
}
}
@supports not (animation-timeline: view()) {
.card { opacity: 1; transform: none; }
}
Problema 5: Contenedor de desplazamiento sin overflow
/* ✅ Correcto: asegurar que el contenedor sea desplazable */
.scroller {
overflow-y: auto;
scroll-timeline-name: --my-scroll;
}
Solución de Errores
| # | Error | Causa | Solución |
|---|---|---|---|
| 1 | La animación no sigue el desplazamiento | No se estableció animation-timeline | Agregar animation-timeline: view() o scroll() |
| 2 | La animación termina prematuramente | animation-range demasiado pequeño | Aumentar el rango |
| 3 | Dirección de parallax incorrecta | scroll-timeline-axis mal configurado | Usar block/inline para la dirección |
| 4 | Línea de tiempo nombrada inválida | scroll-timeline-name no coincide | Asegurar que los nombres padre-hijo coincidan |
| 5 | Tartamudeo de animación | Sin will-change | Agregar will-change: transform |
| 6 | Firefox no funciona | El navegador no soporta | Usar @supports para fallback |
| 7 | Desplazamiento anidado no funciona | Conflicto de desplazamiento interno/externo | Usar scroll-timeline nombrado |
| 8 | Salto de animación | Keyframes no lo suficientemente suaves | Agregar más keyframes o usar linear |
| 9 | Elementos fijos anormales | transform afecta el posicionamiento fijo | Mover elementos fijos fuera del contenedor transform |
| 10 | Móvil no fluido | Aceleración GPU no habilitada | Agregar transform: translateZ(0) |
Optimización Avanzada
- Scroll Snap + Animaciones de Desplazamiento: Combinar desplazamiento paginado con animaciones
- Propiedades personalizadas CSS Houdini: Registrar propiedades de animación para efectos complejos
- prefers-reduced-motion: Respetar la preferencia del usuario de movimiento reducido
- Container queries + animaciones de desplazamiento: Sinergia responsiva y de animación de desplazamiento
- WAAPI + Scroll Timeline: Web Animations API combinada con líneas de tiempo de desplazamiento CSS
Comparación
| Dimensión | CSS Scroll-Driven | JS IntersectionObserver | Evento scroll JS | GSAP ScrollTrigger |
|---|---|---|---|---|
| Rendimiento | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| Volumen de código | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| Soporte de navegadores | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Flexibilidad | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Facilidad de depuración | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Curva de aprendizaje | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
Resumen: Las animaciones CSS impulsadas por desplazamiento te permiten lograr efectos de desplazamiento suaves con cero JS, superando ampliamente a las soluciones JS. Las animaciones de desplazamiento CSS son adecuadas para escenarios de interacción de desplazamiento que buscan rendimiento extremo, especialmente parallax, barras de progreso y animaciones de revelación. Con soporte completo de Chrome y Safari en 2026, usar con fallback @supports.
Herramientas en Línea
- Formateador JSON: /es-419/json/format
- Calculadora de Hash: /es-419/encode/hash
- cURL a Código: /es-419/dev/curl-to-code
Prueba estas herramientas que se ejecutan en tu navegador — no requieren registro →