Animación

Cuándo mover algo, cuánto debe durar y con qué curva. Con lo que dicen Apple, Google, IBM y Emil Kowalski, y dónde se contradicen.

borrador Actualizado 2026-07-29 · 11 fuentes archivadas

Cómo leer esta guía

Tres tipos de párrafo, siempre marcados:

Si algo no lleva marca, es que falta trabajo. No lo trates como establecido.

La decisión rápida

Antes de elegir duración o curva, dos preguntas que descartan la mayor parte del trabajo:

  1. ¿El usuario va a ver esto más de cien veces al día? Entonces no lo animes. (Citado — Emil Kowalski señala Raycast como ejemplo de interfaz que no anima precisamente porque se abre cientos de veces al día. Apple lo dice con otras palabras: «in apps, generally avoid adding motion to UI interactions that occur frequently».)
  2. ¿La acción salió del teclado? No la animes. (Citado — Emil Kowalski: «never animate keyboard initiated actions».)

Si pasa el filtro:

Qué ocurre Curva
Algo entra o sale de pantalla ease-out (entrada) / ease-in (salida)
Algo que ya está en pantalla se mueve o cambia de tamaño ease-in-out
Hover, color, estado sutil ease
Movimiento continuo (marquesina, progreso temporal) linear

(Citado — es la división de Material: la curva de deceleración «elements enter the screen at full velocity and slowly decelerate», la de aceleración «elements leave the screen at full velocity», y la estándar para lo que permanece en pantalla. Carbon usa la misma tripleta con los nombres entrance / exit / standard.)

Duración: aquí las fuentes no se ponen de acuerdo

Esto es lo más útil de la guía, porque quien lea sólo una fuente se llevará una idea equivocada de que hay consenso.

Fuente Qué prescribe
Emil Kowalski Por debajo de 300 ms. (Citado)
Rauno Freiberg «Animation duration should not be more than 200ms for interactions to feel immediate». (Citado)
Material 1 300 ms típico en móvil; entrada 225 ms; salida 195 ms; pantalla completa hasta 375 ms; «transitions that exceed 400ms may feel too slow». (Verificado)
Material 3 Escala de tokens, sin prescribir uno: short 50/100/150/200, medium 250/300/350/400, long 450/500/550/600, extra-long 700/800/900/1000 ms. (Verificado en el .scss del design system)
Carbon (IBM) Escala por función: 70 ms micro-interacción, 110 ms fundido, 150 ms expansión corta, 240 ms toast, 400 ms expansión grande, 700 ms atenuado de fondo. (Verificado)
Apple Ningún número. Sólo «aim for brevity and precision». (Citado)

La contradicción es aparente. Rauno y Emil hablan de respuesta a un gesto del usuario, donde cualquier retraso se lee como lentitud. Material y Carbon cubren además transiciones de superficie — una hoja que ocupa la pantalla, un fondo que se atenúa — donde 200 ms resulta brusco. Carbon lo explicita: la duración «should be dynamic based on the size of the animation; the larger the change in distance (traveled) or size (scaling) of the element, the longer the animation takes». Material 1 dice lo mismo y añade dos escalas que nadie más documenta: tablet un 30 % más lento que móvil, wearable un 30 % más rápido. (Verificado)

Decisión Sensa. Dos reglas, no una:

Curvas verificadas

Todas sacadas del código o la documentación de cada emisor, no de memoria.

Material 3 — md.sys.motion (Verificado)

--md-easing-emphasized:             cubic-bezier(0.2, 0, 0, 1);
--md-easing-emphasized-accelerate:  cubic-bezier(0.3, 0, 0.8, 0.15);
--md-easing-emphasized-decelerate:  cubic-bezier(0.05, 0.7, 0.1, 1);
--md-easing-standard:               cubic-bezier(0.2, 0, 0, 1);
--md-easing-standard-accelerate:    cubic-bezier(0.3, 0, 1, 1);
--md-easing-standard-decelerate:    cubic-bezier(0, 0, 0, 1);
--md-easing-legacy:                 cubic-bezier(0.4, 0, 0.2, 1);

Nota: emphasized y standard tienen hoy el mismo valor en el archivo de tokens. No es un error de transcripción, es lo que hay en el fuente.

Material 1 — las curvas clásicas (Verificado)

/* standard */      cubic-bezier(0.4, 0.0, 0.2, 1);
/* deceleration */  cubic-bezier(0.0, 0.0, 0.2, 1);
/* acceleration */  cubic-bezier(0.4, 0.0, 1, 1);
/* sharp */         cubic-bezier(0.4, 0.0, 0.6, 1);

La sharp es la menos conocida y la más útil: es para lo que sale de pantalla pero puede volver en cualquier momento.

Carbon — productive vs expressive (Verificado)

Productive Expressive
Standard cubic-bezier(0.2, 0, 0.38, 0.9) cubic-bezier(0.4, 0.14, 0.3, 1)
Entrance cubic-bezier(0, 0, 0.38, 0.9) cubic-bezier(0, 0, 0.3, 1)
Exit cubic-bezier(0.2, 0, 1, 0.9) cubic-bezier(0.4, 0.14, 1, 1)

La distinción de Carbon es la más transferible a nuestro trabajo: productive para lo que el usuario hace todo el día, expressive para los momentos que importan. Es la misma idea que «no animes lo que se ve cien veces», pero graduada en lugar de binaria.

tw-animate-css — lo que shadcn trae de fábrica (Verificado)

animate-in y animate-out usan 150 ms y ease por defecto. Si usas shadcn sin tocar nada, esos son tus valores reales. Están dentro del rango razonable, así que la mayor parte del tiempo lo correcto es no tocarlos.

Rendimiento

(Citado — Emil Kowalski) Animar sólo transform y opacity: son las que no disparan layout ni paint. Evitar padding, margin, width, height. Objetivo 60 fps. Las animaciones CSS y la Web Animations API corren fuera del hilo principal, lo que importa cuando ese hilo está ocupado.

(Citado — Rauno Freiberg) Las animaciones en bucle deben pausarse cuando no están visibles. Cambiar de tema no debe disparar transiciones.

(Citado — Material 1) En web, las transiciones complejas sueltan frames si no están aceleradas por GPU; una duración más corta lo disimula porque termina antes.

Accesibilidad

(Citado — WCAG 2.3.3, nivel AAA) «Motion animation triggered by interaction can be disabled, unless the animation is essential to the functionality or the information being conveyed». Esencial significa que quitarlo cambiaría la información o la función y no hay otra manera de lograrlo. Ojo con el criterio hermano 2.2.2, que cubre lo que se mueve solo sin que el usuario lo dispare.

(Citado — Apple) «Make motion optional. Not everyone can or wants to experience the motion in your app or game, so it's essential to avoid using it as the only way to communicate important information». Apple recomienda apoyar el feedback visual con hápticos y sonido.

(Citado — Apple) «Let people cancel motion. As much as possible, don't make people wait for an animation to complete before they can do anything, especially if they have to experience the animation more than once.» Esto se olvida siempre y es lo que más molesta.

Decisión Sensa. Cada elemento animado lleva su propia media query. Sin excepciones para opacidad o color.

@media (prefers-reduced-motion: reduce) {
  .thing { animation: none; transition: none; }
}

Anti-patrones

Checklist de revisión

Lo que falta