En esta página
Transiciones y animaciones CSS
Transiciones vs animaciones
CSS ofrece dos mecanismos para agregar movimiento:
- Transiciones: animan el cambio entre dos estados (por ejemplo, hover)
- Animaciones con @keyframes: definen secuencias complejas con multiples pasos
Transiciones
Una transición suaviza el cambio de una propiedad CSS de un valor a otro. Se define en el estado base (no en el :hover).
La propiedad transition
.elemento {
transition: propiedad duracion timing-function delay;
}| Parametro | Descripcion | Ejemplo |
|---|---|---|
| propiedad | Que propiedad animar | opacity, transform, all |
| duracion | Cuanto dura | 200ms, 0.3s |
| timing-function | Curva de velocidad | ease, linear, ease-in-out |
| delay | Espera antes de iniciar | 0ms, 100ms |
Ejemplo práctico
.boton {
background: #1a1a2e;
transition: background 200ms ease, transform 150ms ease;
}
.boton:hover {
background: #3a3a5e;
transform: translateY(-2px);
}Multiples transiciones
Separa cada propiedad con coma. Evita transition: all porque puede animar propiedades inesperadas y afectar el rendimiento.
Timing functions
| Función | Comportamiento |
|---|---|
ease |
Inicio lento, rápido en medio, final lento (defecto) |
ease-in |
Inicio lento, final rápido |
ease-out |
Inicio rápido, final lento |
ease-in-out |
Lento en ambos extremos |
linear |
Velocidad constante |
cubic-bezier() |
Curva personalizada |
Para interacciones de usuario, ease-out se siente más natural porque responde rápido al input.
Duraciones recomendadas
| Tipo de interacción | Duracion |
|---|---|
| Hover, focus | 150-200ms |
| Apertura de menu | 200-300ms |
| Transición de página | 300-500ms |
| Animación de entrada | 400-600ms |
Más de 500ms se siente lento. Menos de 100ms es imperceptible.
Animaciones con @keyframes
Para movimientos más complejos, @keyframes permite definir multiples pasos:
@keyframes deslizar-entrada {
0% {
opacity: 0;
transform: translateX(-20px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.panel {
animation: deslizar-entrada 400ms ease both;
}Propiedades de animación
| Propiedad | Descripcion |
|---|---|
animation-name |
Nombre del @keyframes |
animation-duration |
Duracion total |
animation-timing-function |
Curva de velocidad |
animation-delay |
Espera antes de iniciar |
animation-iteration-count |
Veces que se repite (1, infinite) |
animation-direction |
Direccion (normal, reverse, alternate) |
animation-fill-mode |
Estado final (forwards, backwards, both) |
Shorthand
.elemento {
animation: nombre 400ms ease 0ms 1 normal both;
/* name dur timing delay count dir fill */
}Animaciones escalonadas
Para animar una lista de elementos con un efecto en cascada, usa animation-delay incrementado:
.item:nth-child(1) { animation-delay: 0ms; }
.item:nth-child(2) { animation-delay: 75ms; }
.item:nth-child(3) { animation-delay: 150ms; }O con custom properties para mayor flexibilidad:
.item {
animation: aparecer 400ms ease both;
animation-delay: calc(var(--i) * 75ms);
}<li class="item" style="--i: 0">Primero</li>
<li class="item" style="--i: 1">Segundo</li>
<li class="item" style="--i: 2">Tercero</li>Rendimiento de animaciones
El navegador puede animar eficientemente solo dos propiedades sin causar repaint:
- transform (translate, scale, rotate)
- opacity
Animar width, height, margin, top, left fuerza al navegador a recalcular el layout de toda la página (reflow), lo cual es costoso.
Accesibilidad: prefers-reduced-motion
Algunos usuarios experimentan mareos o malestar con animaciones. Respeta su preferencia:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}Las animaciones dan vida a tu interfaz. En la siguiente leccion aprenderemos custom properties, las variables nativas de CSS que hacen tu código mantenible y dinámico.
Práctica
- Anade transiciones a un boton: Crea un boton con transiciones en
backgroundytransformal hacer hover. Usaease-outy una duracion de 200ms para una sensacion natural. - Crea un spinner de carga: Implementa un spinner circular usando
@keyframescon una rotacion de 360 grados yanimation: spin 800ms linear infinite. - Respeta prefers-reduced-motion: Anade un bloque
@media (prefers-reduced-motion: reduce)que reduzca la duracion de todas las animaciones y transiciones a 0.01ms.
/* Transición básica en boton */
.boton {
background: #1a1a2e;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 200ms ease,
transform 150ms ease;
}
.boton:hover {
background: #2d2d44;
transform: translateY(-2px);
}
.boton:active {
transform: translateY(0) scale(0.98);
transition-duration: 50ms;
}
/* Card con multiples transiciones */
.card {
background: white;
border-radius: 12px;
padding: 1.5rem;
border: 1px solid #e0e0e0;
transition: border-color 200ms ease,
box-shadow 300ms ease;
}
.card:hover {
border-color: #b056ff;
box-shadow: 0 8px 24px rgb(176 86 255 / 15%);
}
/* Transición de entrada con delay escalonado */
.lista-item {
opacity: 0;
transform: translateY(10px);
animation: aparecer 400ms ease forwards;
}
.lista-item:nth-child(1) { animation-delay: 0ms; }
.lista-item:nth-child(2) { animation-delay: 75ms; }
.lista-item:nth-child(3) { animation-delay: 150ms; }
.lista-item:nth-child(4) { animation-delay: 225ms; }
/* Animación de aparicion */
@keyframes aparecer {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.sección {
animation: aparecer 600ms ease both;
}
/* Spinner de carga */
@keyframes girar {
to { rotate: 1turn; }
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid #e0e0e0;
border-top-color: #b056ff;
border-radius: 50%;
animation: girar 800ms linear infinite;
}
/* Pulso en notificación */
@keyframes pulso {
0%, 100% { scale: 1; }
50% { scale: 1.15; }
}
.badge-notificación {
background: #e6286a;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
animation: pulso 2s ease-in-out infinite;
}
/* Respetar preferencias del usuario */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Inicia sesión para guardar tu progreso