Guía de animación CSS: Transiciones, keyframes y rendimiento
Las animaciones CSS dan vida a las interfaces, proporcionando retroalimentación visual, guiando la atención del usuario y creando experiencias memorables. Las animaciones bien hechas se sienten naturales e intuitivas; las mal hechas causan tartamudeo, distraen a los usuarios e incluso provocan malestar físico. Esta guía cubre todo, desde los fundamentos de transiciones y keyframes hasta optimización avanzada de rendimiento y accesibilidad, brindándote el conocimiento para crear animaciones fluidas, con propósito e inclusivas.
Transiciones y animaciones CSS
CSS ofrece dos mecanismos distintos para crear movimiento: transiciones y animaciones. Comprender cuándo usar cada uno es fundamental para trabajar eficazmente con animaciones CSS.
Transiciones CSS
Las transiciones animan los cambios entre dos estados de una propiedad CSS. Defines qué propiedad animar, la duración y la curva de easing, y el navegador maneja automáticamente la interpolación entre los valores inicial y final. Las transiciones se activan mediante cambios de estado como hover, focus, adición de clases o cambios de propiedad desde JavaScript.
.button {
background: #3b82f6;
transform: scale(1);
transition: background 0.3s ease, transform 0.2s ease;
}
.button:hover {
background: #2563eb;
transform: scale(1.05);
}Las transiciones son perfectas para animaciones simples de dos estados. Requieren un código mínimo, son fáciles de entender y funcionan de forma fiable en todos los navegadores. La limitación es que solo animan entre dos valores: no puedes definir pasos intermedios.
Animaciones CSS (keyframes)
Las animaciones usan la regla @keyframes para definir una secuencia de cambios de estilo en cualquier número de pasos. A diferencia de las transiciones, las animaciones pueden ejecutarse independientemente de los cambios de estado, repetirse infinitamente, reproducirse en reversa y pausarse. Te dan control preciso sobre cada fotograma de la animación.
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.8;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.pulse-element {
animation: pulse 2s ease-in-out infinite;
}Cuándo usar cada una
| Escenario | Usar transición | Usar animación |
|---|---|---|
| Efecto hover | Sí | No |
| Estado focus | Sí | No |
| Alternar visibilidad | Sí | Posiblemente |
| Secuencia de múltiples pasos | No | Sí |
| Animación en bucle | No | Sí |
| Independiente del estado | No | Sí |
| Animación de entrada | Posiblemente | Sí |
Sintaxis de keyframes en profundidad
La regla @keyframes es el corazón de las animaciones CSS. Comprender completamente su sintaxis desbloquea todo el poder de las secuencias de animación de múltiples pasos.
Keyframes basados en porcentaje
Los keyframes se definen usando valores porcentuales de 0% a 100%, que representan el progreso en la línea de tiempo de la animación. Puedes definir tantos keyframes como necesites, y el navegador interpola entre ellos:
@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
25% {
transform: translateY(-20px);
}
50% {
transform: translateY(0);
}
75% {
transform: translateY(-10px);
}
}Múltiples keyframes pueden compartir el mismo bloque de estilo separando los valores porcentuales con comas, como 0%, 100% en el ejemplo anterior. Esto es útil para animaciones que regresan al estado inicial.
Propiedad abreviada animation
La propiedad abreviada animation combina ocho subpropiedades en una sola declaración. El orden es: name, duration, timing-function, delay, iteration-count, direction, fill-mode y play-state.
.element {
animation: slideIn 0.5s ease-out 0.2s 1 forwards running;
}
/* Equivalent longhand */
.element {
animation-name: slideIn;
animation-duration: 0.5s;
animation-timing-function: ease-out;
animation-delay: 0.2s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: forwards;
animation-play-state: running;
}Modos de relleno de animación
La propiedad animation-fill-mode controla qué estilos se aplican antes y después de que se ejecute la animación. Es una de las propiedades de animación más malinterpretadas:
- none (predeterminado): El elemento vuelve a su estilo previo a la animación cuando esta termina.
- forwards: El elemento conserva el estilo del último fotograma después de que termine la animación. Esencial para animaciones de entrada donde quieres que el elemento permanezca en su posición final.
- backwards: Durante el retraso de la animación (antes de que comience), el elemento aplica el estilo del primer fotograma.
- both: Combina el comportamiento de forwards y backwards. El elemento muestra el primer fotograma durante el retraso y conserva el último fotograma al completarse.
Funciones de easing
Las funciones de easing (también llamadas funciones de temporización) definen la curva de aceleración de una animación. Determinan si la animación comienza lentamente y luego acelera, comienza rápido y luego desacelera, o sigue un patrón más complejo. La función de easing correcta hace que la animación se sienta natural; la incorrecta la hace sentir mecánica o abrupta.
Funciones de easing integradas
- linear: Velocidad constante durante toda la animación. Rara vez se ve natural porque los objetos del mundo real no se mueven a velocidad constante. Adecuado para animaciones mecánicas o de rotación.
- ease (predeterminado): Comienza lento, acelera en el medio, desacelera al final. Un buen easing de propósito general para la mayoría de las transiciones UI.
- ease-in: Comienza lento y luego acelera. Crea una sensación de 'acumular impulso'. Adecuado para elementos que salen de la pantalla o caen.
- ease-out: Comienza rápido y luego desacelera. Crea una sensación de 'asentarse'. El easing más común para elementos UI que entran en la pantalla.
- ease-in-out: Comienzo y final lentos, más rápido en el medio. Similar a ease pero con aceleración y desaceleración más pronunciadas. Adecuado para transiciones más grandes y dramáticas.
Curvas cubic-bezier
La función cubic-bezier() te permite definir curvas de easing personalizadas con control preciso. Acepta cuatro parámetros que representan los puntos de control de una curva de Bézier cúbica: cubic-bezier(x1, y1, x2, y2). Los valores x representan tiempo (0 a 1), los valores y representan progreso (pueden exceder 0-1 para efectos de sobreimpulso).
.element {
/* Smooth deceleration - great for entrances */
transition: transform 0.3s cubic-bezier(0.0, 0.0, 0.2, 1.0);
/* Smooth acceleration - great for exits */
transition: transform 0.2s cubic-bezier(0.4, 0.0, 1, 1);
/* Material Design standard easing */
transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}Funciones de pasos (steps)
La función steps() crea animaciones discretas fotograma a fotograma en lugar de interpolación suave. Es útil para animaciones de sprites o para crear un efecto de 'escritura':
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
.typing-effect {
animation: typing 3s steps(40, end);
overflow: hidden;
white-space: nowrap;
}Optimización de rendimiento
Las animaciones fluidas requieren 60 fotogramas por segundo (fps), lo que significa que cada fotograma debe completarse en 16.67 milisegundos. No cumplir este presupuesto provoca tartamudeo visible: vibración de la pantalla, pérdida de fotogramas y degradación de la experiencia del usuario. Comprender el pipeline de renderizado del navegador es clave para escribir animaciones de alto rendimiento.
Pipeline de renderizado
Cuando una propiedad CSS cambia, el navegador pasa por hasta tres etapas para actualizar la pantalla:
- Estilo: Determina qué reglas CSS se aplican a qué elementos.
- Layout: Calcula el tamaño y la posición de cada elemento. Activado por cambios en width, height, margin, padding, top, left, font-size y otras propiedades geométricas.
- Paint: Rellena los píxeles de cada elemento. Activado por cambios en color, background, box-shadow, border-radius y otras propiedades visuales.
- Composición: Combina las capas pintadas en el orden correcto. Solo este paso se ejecuta en la GPU. Activado por cambios en transform y opacity.
Las animaciones que solo activan el paso de composición tienen el mejor rendimiento porque evitan completamente el layout y el paint. Por eso transform y opacity son el estándar de oro para animaciones CSS de alto rendimiento.
Propiedades solo de compositor
| Propiedad | ¿Activa layout? | ¿Activa paint? | ¿Composición GPU? |
|---|---|---|---|
| transform | No | No | Sí |
| opacity | No | No | Sí |
| filter | No | Sí | A veces |
| top / left | Sí | Sí | No |
| width / height | Sí | Sí | No |
| margin / padding | Sí | Sí | No |
| background-color | No | Sí | No |
| box-shadow | No | Sí | No |
Uso de will-change
La propiedad will-change le dice al navegador qué propiedades se espera que cambien, permitiéndole optimizar por adelantado promoviendo el elemento a su propia capa del compositor. Sin embargo, debe usarse con moderación:
/* Apply will-change just before the animation */
.element:hover {
will-change: transform;
}
/* Remove it after the animation completes */
.element {
transition: transform 0.3s ease;
}Los errores comunes con will-change incluyen aplicarlo a demasiados elementos (cada capa del compositor consume memoria GPU) y mantenerlo permanentemente (desperdiciando recursos). Una buena práctica es añadir will-change mediante JavaScript justo antes de que comience la animación y eliminarlo cuando termine.
Usar Transform en lugar de propiedades de layout
La optimización de rendimiento más efectiva es reemplazar las propiedades que activan el layout con transform:
- Usa transform: translateX(100px) en lugar de left: 100px
- Usa transform: translateY(50px) en lugar de top: 50px
- Usa transform: scale(1.5) en lugar de width: 150%; height: 150%
- Usa transform: rotate(45deg) en lugar de rotación mediante layout
Patrones comunes de animación
Ciertos patrones de animación aparecen repetidamente en las interfaces web. Dominar estos patrones te proporciona un kit de herramientas para la mayoría de las necesidades comunes de animación UI.
1. Fade in
La animación de entrada más simple y versátil. El elemento pasa de transparente a opaco:
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 0.4s ease-out forwards;
}2. Deslizar hacia arriba con fade
Un efecto de entrada más dinámico que combina movimiento vertical y cambio de opacidad. Esto crea la sensación de que el elemento llega desde abajo:
@keyframes slideUpFade {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.slide-up {
animation: slideUpFade 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}3. Escala al hover
Un sutil aumento de escala al pasar el cursor proporciona una retroalimentación interactiva satisfactoria:
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}4. Animación de lista escalonada
Cuando aparece una lista de elementos, establecer retrasos de animación escalonados para cada elemento crea un efecto de cascada que guía la mirada:
.list-item {
opacity: 0;
transform: translateY(10px);
animation: slideUpFade 0.3s ease-out forwards;
}
.list-item:nth-child(1) { animation-delay: 0.0s; }
.list-item:nth-child(2) { animation-delay: 0.05s; }
.list-item:nth-child(3) { animation-delay: 0.1s; }
.list-item:nth-child(4) { animation-delay: 0.15s; }
.list-item:nth-child(5) { animation-delay: 0.2s; }Para listas dinámicas, usa JavaScript para establecer animation-delay basado en el índice de cada elemento, o usa propiedades personalizadas CSS: style="animation-delay: calc(var(--i) * 0.05s)".
5. Spinner de carga
La rotación continua y suave es el clásico indicador de carga:
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 24px;
height: 24px;
border: 3px solid rgba(255, 255, 255, 0.2);
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}Accesibilidad en animaciones: prefers-reduced-motion
No todos los usuarios se benefician de las animaciones. Para personas con trastornos vestibulares, sensibilidad al movimiento o ciertas condiciones cognitivas, las animaciones pueden causar mareos, náuseas o convulsiones. La media query prefers-reduced-motion te permite respetar la preferencia de reducción de animación a nivel de sistema del usuario.
Implementar reducción de animación
El enfoque recomendado es habilitar las animaciones para usuarios que no tienen establecida la preferencia de reducción de animación:
/* Default: no animation for users who prefer reduced motion */
.element {
opacity: 1;
transform: none;
}
/* Only animate for users who have no motion preference */
@media (prefers-reduced-motion: no-preference) {
.element {
animation: slideUpFade 0.5s ease-out forwards;
}
}Alternativamente, puedes deshabilitar animaciones específicas para usuarios que prefieren animación reducida:
.element {
animation: slideUpFade 0.5s ease-out forwards;
}
@media (prefers-reduced-motion: reduce) {
.element {
animation: none;
opacity: 1;
transform: none;
}
/* Keep functional transitions but shorten duration */
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}Qué conservar y qué eliminar
Cuando los usuarios prefieren animación reducida, no todas las animaciones deben eliminarse. Las animaciones funcionales que transmiten significado o estado deben conservarse, solo simplificadas:
- Eliminar: Animaciones decorativas, parallax scrolling, carruseles de reproducción automática, efectos de pulso y animaciones de fondo en bucle.
- Simplificar: Las duraciones de transición deben acortarse a casi instantáneas (0.01ms) en lugar de eliminarse por completo, para que los cambios de estado sigan siendo perceptibles.
- Conservar: Transiciones de estado funcionales (hover, focus, active), indicadores de progreso y cualquier animación que transmita información importante.
Bibliotecas de animación
Aunque las animaciones CSS manejan la mayoría de las necesidades UI, las bibliotecas de animación JavaScript ofrecen características avanzadas como movimiento basado en física, animaciones vinculadas al scroll y orquestación de secuencias complejas.
Bibliotecas CSS-first
- Animate.css: Colección de clases de animación CSS preconstruidas. Solo añade nombres de clase a los elementos para aplicar animaciones. Bueno para prototipado rápido, pero puede llevar a animaciones genéricas si se abusa.
- Hamburgers: Colección de transiciones animadas de iconos de menú hamburguesa, todas implementadas en CSS puro.
Bibliotecas de animación JavaScript
- Framer Motion: Biblioteca de animación para React que ofrece una API declarativa de animación con física de resortes, animaciones de layout y soporte de gestos. La mejor opción para aplicaciones React.
- GSAP (GreenSock): La biblioteca de animación JavaScript más potente. Ofrece control preciso de línea de tiempo, easing complejo, morphing SVG y animaciones activadas por scroll. Usada por grandes marcas para sitios de marketing y experiencias interactivas.
- Anime.js: Biblioteca de animación JavaScript ligera con una API limpia. Soporta propiedades CSS, SVG, atributos DOM y objetos JavaScript. Una buena opción intermedia entre CSS y GSAP.
- Motion One: Biblioteca de animación moderna y ligera construida sobre la Web Animations API. Ofrece una API mínima con física de resortes y líneas de tiempo.
Cuándo usar JavaScript vs CSS
CSS para animaciones declarativas simples que responden a cambios de estado. JavaScript para: movimiento basado en física (resortes, momento), animaciones vinculadas al scroll, secuencias complejas con control de tiempo preciso, parámetros de animación dinámicos calculados en tiempo de ejecución, o animaciones que necesitan pausarse, invertirse o arrastrarse programáticamente.
Depuración de animaciones
Los bugs de animación pueden ser sutiles y difíciles de diagnosticar. Las herramientas y técnicas de depuración adecuadas hacen el proceso más eficiente.
Panel de animaciones de Chrome DevTools
Chrome DevTools incluye un panel de animaciones dedicado que proporciona potentes capacidades de depuración:
- Vista de línea de tiempo: Ve todas las animaciones activas en la página con sus duraciones, retrasos y keyframes.
- Controles de reproducción: Ralentiza las animaciones a 1/4 de velocidad, pausa o arrastra la línea de tiempo fotograma a fotograma.
- Inspección de propiedades: Haz clic en una animación en la línea de tiempo para ver las propiedades CSS exactas que se animan y sus valores en cada keyframe.
- Edición en vivo: Modifica duraciones, retrasos y easing de animaciones en tiempo real sin recargar la página.
Análisis de rendimiento
Usa el panel Performance en Chrome DevTools para identificar el tartamudeo de animaciones:
- Graba un perfil de rendimiento mientras se ejecutan las animaciones
- Busca fotogramas que excedan el presupuesto de 16.67ms (se muestran como barras rojas en el gráfico de fotogramas)
- Verifica si hay operaciones de 'Layout' en los fotogramas de animación, lo que indica propiedades que activan el layout
- Usa la pestaña 'Rendering' para habilitar 'Paint flashing' (muestra las áreas repintadas en verde) y 'Layer borders' (muestra las capas del compositor)
Escenarios comunes de depuración
- La animación no se ejecuta: Verifica que animation-fill-mode esté configurado correctamente. Sin forwards o both, el elemento vuelve a su estado previo a la animación. También verifica que el elemento tenga las dimensiones correctas: transform: scale(0) hace invisible el elemento aunque sigue existiendo.
- La animación tartamudea: Abre el panel Performance para buscar fotogramas largos. Verifica si estás animando propiedades que activan el layout. Cambia a transform y opacity.
- El retraso de animación no se siente bien: Recuerda que animation-delay crea un intervalo antes de que comience la animación. Durante este intervalo, el elemento muestra su estado previo a la animación a menos que se establezca animation-fill-mode: backwards o both.
- La animación funciona en Chrome pero no en Safari: Safari es más estricto al analizar la abreviatura animation. Asegúrate de que todos los valores estén en el orden correcto y no uses características no soportadas.
¿Trabajas con CSS? Prueba nuestras herramientas CSS gratuitas para formatear, minificar y optimizar tus hojas de estilo para producción.
Formateador CSSMinificador CSSPreguntas frecuentes
¿Debo usar transiciones CSS o animaciones CSS?
Las transiciones CSS son para cambios de estado simples de punto A a punto B, como efectos hover, estados de focus y alternar visibilidad. Las animaciones CSS (keyframes) son para secuencias complejas de múltiples pasos, animaciones en bucle o animaciones que necesitan ejecutarse independientemente de los cambios de estado. Las transiciones son más simples; las animaciones ofrecen más control.
¿Qué propiedades CSS son seguras para animar con buen rendimiento?
Las propiedades con mejor rendimiento para animar son transform y opacity, porque pueden ser manejadas completamente por el compositor GPU sin necesidad de activar layout o paint. Otras propiedades como width, height, margin y top activan el recálculo del layout, lo cual es costoso. Prioriza siempre transform: translateX() sobre left, y transform: scale() sobre cambios de width/height.
¿Cómo hacer accesibles las animaciones para usuarios sensibles?
Usa la media query prefers-reduced-motion para deshabilitar o simplificar animaciones para usuarios que tienen habilitada la configuración de 'reducir animación' en su sistema operativo. Envuelve las animaciones no esenciales en @media (prefers-reduced-motion: no-preference) y proporciona cambios de estado instantáneos como alternativa para usuarios que prefieren animación reducida.
¿Qué es will-change y cuándo debo usarlo?
will-change es una propiedad CSS que indica al navegador qué propiedades cambiarán en el futuro, permitiéndole optimizar por adelantado. Úsalo con moderación, solo cuando observes problemas de rendimiento. Aplícalo antes de que comience la animación y elimínalo cuando termine. El uso excesivo de will-change desperdicia memoria GPU y puede perjudicar el rendimiento.
¿Cómo depurar animaciones CSS?
Chrome DevTools proporciona potentes herramientas de depuración de animaciones. Abre el panel de animaciones (en el menú Más herramientas) para ver todas las animaciones activas, arrastrar la línea de tiempo, modificar duraciones y retrasos en tiempo real, y ralentizar las animaciones a 1/4 de velocidad. También puedes usar el panel Performance para identificar tartamudeo de animaciones y layout thrashing.