Transiciones y animaciones
El CSS que no se mueve es una foto. Las transiciones y animaciones añaden la dimensión del tiempo: comunican cambios de estado, guían la atención y hacen que las interfaces se sientan vivas sin necesidad de JavaScript.
Transiciones — cambios de estado suaves
transition interpola el cambio de una propiedad entre dos estados. Se define en el elemento en reposo, no en el estado final:
/* Sintaxis: propiedad duracion timing-function retardo */
.btn {
background: var(--color-primary);
transform: translateY(0);
box-shadow: 2px 2px 0 var(--blackMirror);
transition: background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
.btn:hover {
background: var(--color-accent);
transform: translateY(-2px);
box-shadow: 4px 4px 0 var(--blackMirror);
}
Propiedades de transition
.elemento {
transition-property: background, transform; /* qué propiedades */
transition-duration: 0.2s; /* cuánto dura */
transition-timing-function: ease-out; /* curva de velocidad */
transition-delay: 0.05s; /* retardo inicial */
/* Shorthand (el orden importa: propiedad | duración | timing | retardo) */
transition: background 0.2s ease-out 0.05s;
}
transition: all — úsalo con cuidado
transition: all es cómodo pero peligroso: anima todas las propiedades que cambien, incluyendo width, height o clip-path, que pueden ser costosas de animar. Sé específico.
Timing functions — la curva de velocidad
La timing function define cómo acelera y desacelera la animación:
transition-timing-function: ease; /* lento → rápido → lento (por defecto) */
transition-timing-function: ease-in; /* lento al principio */
transition-timing-function: ease-out; /* lento al final — el más natural */
transition-timing-function: ease-in-out; /* lento en ambos extremos */
transition-timing-function: linear; /* velocidad constante */
transition-timing-function: steps(4); /* saltos discretos — efecto escalonado */
/* Curva personalizada con cubic-bezier */
transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); /* efecto rebote */
Para la mayoría de interacciones de UI,
ease-outes la opción más natural: rápida al inicio (parece responsiva) y suave al final (parece física real).
@keyframes — animaciones continuas o complejas
Cuando necesitas más de dos estados o una animación que se repite, usas @keyframes:
@keyframes aparecer {
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.tarjeta {
animation: aparecer 0.3s ease-out forwards;
/* nombre dur timing fill-mode */
}
Puedes usar porcentajes para múltiples puntos de control:
@keyframes pulso {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
@keyframes parpadeo {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
Propiedades de animation
.elemento {
animation-name: aparecer;
animation-duration: 0.4s;
animation-timing-function: ease-out;
animation-delay: 0.1s;
animation-iteration-count: 1; /* o infinite */
animation-direction: normal; /* o reverse, alternate, alternate-reverse */
animation-fill-mode: forwards; /* qué estado mantiene al terminar */
animation-play-state: running; /* o paused — útil con JS */
/* Shorthand */
animation: aparecer 0.4s ease-out 0.1s 1 normal forwards;
}
fill-mode — qué pasa antes y después
animation-fill-mode: none; /* vuelve al estado original al terminar */
animation-fill-mode: forwards; /* se queda en el estado final (el más usado) */
animation-fill-mode: backwards; /* aplica el estado inicial durante el delay */
animation-fill-mode: both; /* combina forwards y backwards */
Animar listas con retraso escalonado
Un patrón muy habitual: animar elementos de una lista con un pequeño retraso entre cada uno:
.lista-item {
opacity: 0;
transform: translateY(8px);
animation: aparecer 0.3s ease-out forwards;
}
.lista-item:nth-child(1) { animation-delay: 0.0s; }
.lista-item:nth-child(2) { animation-delay: 0.05s; }
.lista-item:nth-child(3) { animation-delay: 0.10s; }
.lista-item:nth-child(4) { animation-delay: 0.15s; }
Con CSS custom properties puedes hacerlo sin repetir reglas si el framework permite pasar el índice:
.lista-item {
animation-delay: calc(var(--index, 0) * 0.05s);
}
<li class="lista-item" style="--index: 0">...</li>
<li class="lista-item" style="--index: 1">...</li>
Rendimiento: qué propiedades animar
No todas las propiedades cuestan lo mismo. El navegador tiene que recalcular el layout si cambias dimensiones, y repintar la pantalla si cambias colores de fondo.
Propiedades baratas (se animan en la GPU, no afectan al layout):
transform— mover, escalar, rotaropacity— transparencia
Propiedades costosas (fuerzan repaint o reflow):
width,height,margin,padding— reflowbackground-color,color,box-shadow— repaint
Siempre que puedas sustituir una animación de width por una de transform: scaleX(), hazlo. El resultado visual es similar pero el rendimiento, muy diferente.
Respetar las preferencias del usuario
Algunos usuarios configuran su sistema operativo para reducir el movimiento (por epilepsia, mareo o preferencia). Respétalo:
@keyframes slideIn {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
.panel {
animation: slideIn 0.3s ease-out forwards;
}
/* Desactiva las animaciones si el usuario las ha reducido */
@media (prefers-reduced-motion: reduce) {
.panel {
animation: none;
}
}
En la siguiente lección profundizamos en posicionamiento y stacking context: el comportamiento real de sticky, los bugs del z-index y por qué los elementos no se apilan donde esperas.