Estilos CSS: Animaciones con @keyframes

Estilos CSS: Animaciones con @keyframes

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;
}
Aparezco con fade + desplazamiento

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:

SubpropiedadFunciónEjemplo
animation-nameNombre del @keyframes a ejecutaraparecer
animation-durationDuración de un ciclo0.6s
animation-timing-functionCurva de progresoease-in-out
animation-delayEspera antes de iniciar200ms
animation-iteration-countNúmero de repeticionesinfinite
animation-directionSentido de reproducciónalternate
animation-fill-modeEstilos antes/después de animarforwards
animation-play-stateReproducir o pausarpaused

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 el delay, antes de arrancar.
  • both — combina forwards y backwards.

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;
}
Floto suavemente

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.

Tags :