
Estilos CSS: Animaciones con @keyframes
- Dacadev
- Programación
- June 18, 2026
Table of Contents
Una transición anima el salto entre dos estados; pero cuando necesitas movimiento continuo, varios pasos intermedios o una secuencia que se repite —un spinner de carga, un latido, un texto que aparece— necesitas algo más expresivo. Ahí entran las animaciones con @keyframes, el sistema de CSS para describir secuencias de movimiento complejas de forma declarativa, sin una sola línea de JavaScript.
Esta entrega extiende la serie Estilos CSS, retomando justo donde lo dejaron las transiciones y transformaciones. Cubriremos la regla @keyframes, todas las subpropiedades de animation, y las consideraciones de accesibilidad y rendimiento que separan una animación profesional de una que marea al usuario.
Note
Aprenderás a definir secuencias con @keyframes, a controlarlas con la propiedad animation y sus ocho subpropiedades, y a respetar las preferencias de movimiento del usuario con prefers-reduced-motion.
Transición vs. animación
Aunque ambas producen movimiento, resuelven problemas distintos:
- Una transición (
transition) interpola entre el estado actual y uno nuevo. Necesita un disparador —un:hover, un cambio de clase— y va de un punto A a un punto B. - Una animación (
animation) ejecuta una secuencia definida en@keyframes. No necesita disparador: puede arrancar sola, repetirse indefinidamente y pasar por múltiples estados intermedios.
Info
Regla práctica: usa transition para cambios de estado provocados por interacción; usa animation para movimiento autónomo, cíclico o multipaso.
La regla @keyframes
Una animación se define en dos partes: la secuencia (con @keyframes) y su aplicación (con la propiedad animation). La regla @keyframes recibe un nombre y describe los estados de la animación en distintos momentos, expresados como porcentajes del 0% al 100% (o con las palabras clave from y to).
@keyframes aparecer {
from { opacity: 0; transform: translateY(1rem); }
to { opacity: 1; transform: translateY(0); }
}
.elemento {
animation: aparecer 0.6s ease-out;
}
La secuencia se repite para que puedas observarla.
Múltiples pasos con porcentajes
El verdadero poder de @keyframes aparece con pasos intermedios. Cada porcentaje es una “foto” del estado en ese momento de la animación:
@keyframes latido {
0% { transform: scale(1); }
15% { transform: scale(1.25); }
30% { transform: scale(1); }
45% { transform: scale(1.15); }
60% { transform: scale(1); }
}
La propiedad animation y sus subpropiedades
animation es una propiedad abreviada que agrupa ocho subpropiedades. Conviene conocerlas por separado para tener control fino:
| Subpropiedad | Función | Ejemplo |
|---|---|---|
animation-name | Nombre del @keyframes a ejecutar | aparecer |
animation-duration | Duración de un ciclo | 0.6s |
animation-timing-function | Curva de progreso | ease-in-out |
animation-delay | Espera antes de iniciar | 200ms |
animation-iteration-count | Número de repeticiones | infinite |
animation-direction | Sentido de reproducción | alternate |
animation-fill-mode | Estilos antes/después de animar | forwards |
animation-play-state | Reproducir o pausar | paused |
La forma abreviada las combina en una sola declaración:
.spinner {
animation: girar 1s linear infinite;
/* name | duration | timing-function | iteration-count */
}
iteration-count y direction
animation-iteration-count define cuántas veces se ejecuta (infinite para un bucle perpetuo). animation-direction controla el sentido:
normal— siempre de 0% a 100%.reverse— siempre de 100% a 0%.alternate— alterna ida y vuelta en cada ciclo.alternate-reverse— igual, pero empezando al revés.
El caso clásico es un spinner de carga, que combina rotación infinita con velocidad constante:
@keyframes girar { to { transform: rotate(360deg); } }
.spinner { animation: girar 0.8s linear infinite; }
fill-mode: el estado antes y después
Por defecto, un elemento vuelve a su estilo original en cuanto la animación termina. animation-fill-mode cambia ese comportamiento:
none(por defecto) — no conserva estilos fuera de la ejecución.forwards— mantiene el estado del último keyframe al terminar.backwards— aplica el primer keyframe durante eldelay, antes de arrancar.both— combinaforwardsybackwards.
forwards es esencial cuando quieres que el elemento permanezca en su estado final (por ejemplo, un mensaje que aparece y se queda visible):
.toast {
animation: aparecer 0.5s ease-out forwards;
}
play-state y delay
animation-play-state permite pausar (paused) y reanudar (running) una animación, típicamente al combinarla con :hover. Aquí, la barra de progreso se anima sola pero se congela al pasar el cursor:
@keyframes cargar { from { width: 0; } to { width: 100%; } }
.barra__relleno { animation: cargar 3s ease-in-out infinite; }
.barra:hover .barra__relleno { animation-play-state: paused; }
Pasa el cursor sobre la barra para pausar la animación.
Encadenar varias animaciones
Puedes aplicar varias animaciones a un mismo elemento separándolas con comas. Cada una mantiene su propia duración, retraso y curva, lo que permite componer comportamientos independientes:
.elemento {
animation:
aparecer 0.5s ease-out,
flotar 3s ease-in-out 0.5s infinite alternate;
}
Accesibilidad: respeta prefers-reduced-motion
El movimiento excesivo puede causar mareos o malestar a personas con sensibilidad vestibular. Los sistemas operativos exponen una preferencia de “reducir movimiento”, y CSS la consulta con la media query prefers-reduced-motion. Es una responsabilidad profesional desactivar o atenuar las animaciones no esenciales cuando el usuario lo solicita:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Warning
Ignorar prefers-reduced-motion es un fallo de accesibilidad real. Reserva las animaciones llamativas para lo decorativo y asegúrate de que la interfaz siga siendo plenamente funcional cuando el movimiento se reduce.
Rendimiento: anima en la capa de composición
La misma regla de oro de las transiciones aplica aquí: anima propiedades que solo afecten la etapa de composición del navegador —transform y opacity— en lugar de propiedades que disparen layout o paint (width, height, top, left, margin).
/* ❌ Costoso: recalcula layout en cada frame */
@keyframes mover-malo { to { left: 200px; } }
/* ✅ Eficiente: solo composición, fluido a 60 fps */
@keyframes mover-bien { to { transform: translateX(200px); } }
Tip
Si una animación se ve entrecortada, lo primero que debes revisar es qué propiedades estás animando. Reescribir un left/top como transform: translate() suele eliminar el jank de inmediato.
Conclusión
Las animaciones con @keyframes te dan un lenguaje declarativo para describir movimiento complejo: secuencias multipaso, bucles infinitos y comportamientos compuestos, todo en CSS puro. Dominar la propiedad animation y sus subpropiedades —especialmente fill-mode, iteration-count y play-state— te permite construir spinners, indicadores de carga y microinteracciones pulidas. Y recuerda: anima transform y opacity, y respeta siempre prefers-reduced-motion.
Note
🚀 Con esta entrega completas el recorrido de la serie Estilos CSS: desde la cascada y los selectores hasta el layout, el posicionamiento, los fondos, las transformaciones y, ahora, las animaciones. Tienes el repertorio completo para escribir CSS expresivo, accesible y de alto rendimiento.


