wandres.dev
PRINCIPIOS DEL MOVIMIENTO · De la animación clásica a la UI

La duración correcta y por qué 800ms en un botón es un error

Las escalas de duración que usa el sistema perceptivo, de dónde salen sus umbrales, y por qué la duración de una microinteracción no es cuestión de gusto.

⏱ 17 min

Discutir duraciones de animación suele degenerar en opiniones porque se plantea como una cuestión estética. No lo es: hay umbrales perceptivos medidos que dividen el eje del tiempo en tramos con propiedades distintas, y una animación cae en un tramo o en otro con consecuencias que no dependen de a quién le guste qué. Una transición de 800 milisegundos en un botón no es “un poco lenta para mi gusto”: está en el tramo donde el usuario ya ha decidido que la interfaz no le responde, y eso es un hecho sobre su sistema nervioso, no sobre su paladar.

🎯 Al terminar esta lección sabrás
  • Situar los cuatro umbrales perceptivos que estructuran el eje de duraciones.
  • Asignar cada tipo de animación a su tramo con una justificación, no con una preferencia.
  • Explicar por qué una escala de duraciones no debe ser lineal.
  • Reconocer las tres excusas habituales para alargar una animación y desmontarlas.

Los cuatro umbrales

Alrededor de 100 milisegundos: el límite de la respuesta inmediata. Por debajo de este valor, una respuesta se percibe como causada directamente por la acción. No hay sensación de espera: la acción y el resultado se funden en un solo evento. Es el presupuesto para cualquier acuse de recibo —el hundimiento de un botón, el resalte de una fila, el cambio de un interruptor.

Alrededor de 1 segundo: el límite del flujo de pensamiento. Entre 100 milisegundos y un segundo, el usuario percibe una demora pero no pierde el hilo de lo que estaba haciendo. No necesita indicador de progreso porque no llega a preguntarse si algo va mal. Es el tramo de las transiciones de estado con contenido: paneles, diálogos, cambios de vista.

Alrededor de 10 segundos: el límite de la atención. Más allá de un segundo el usuario empieza a dudar; más allá de diez, se marcha mentalmente y hace otra cosa. Este tramo no es de animación de interfaz, es de indicadores de progreso, y ninguna animación de transición debería acercarse a él.

Alrededor de 16 milisegundos: el límite de la continuidad. Es el otro extremo, y es de otra naturaleza: es el tiempo entre fotogramas a 60 hercios. Nada dura menos que un fotograma. Una animación de 30 milisegundos son dos fotogramas, y con dos fotogramas no hay curva posible: es un salto con un paso intermedio. Por debajo de unos 80 o 100 milisegundos, la función de suavizado deja de tener efecto perceptible porque no hay suficientes muestras para expresarla.

Ese último umbral tiene una consecuencia que sorprende: hay un mínimo por debajo del cual animar no aporta nada y sí cuesta. Si la animación va a durar 50 milisegundos, quítala. El resultado visual es prácticamente el mismo y ahorras trabajo al motor.

De los cuatro umbrales sale la asignación completa:

Qué se anima Tramo Rango típico
Acuse de recibo de una pulsación Respuesta inmediata 40 a 100 ms
Cambio de estado sin movimiento (color, opacidad) Respuesta inmediata 80 a 160 ms
Elemento pequeño que entra o sale Flujo 150 a 250 ms
Panel, diálogo o menú Flujo 200 a 350 ms
Transición entre vistas completas Flujo 300 a 500 ms
Cualquier cosa en un botón Respuesta inmediata 40 a 150 ms

Por qué 800ms en un botón es un error de diseño

Un botón tiene una propiedad que lo distingue de casi cualquier otro elemento: es el punto donde el usuario está mirando cuando actúa, y es el punto donde espera confirmación. Su animación no es decoración, es la respuesta del sistema a una orden.

Una animación de 800 milisegundos en un botón cruza tres líneas a la vez.

Cruza el umbral de respuesta inmediata por un factor de ocho. La confirmación llega cuando el usuario ya ha dejado de esperarla, así que no cumple su función. Peor: en ese hueco de espera el usuario a menudo pulsa otra vez, porque no ha recibido señal de que la primera pulsación llegó. Eso genera dobles envíos, que es un bug funcional causado por una decisión de temporización.

Bloquea la interacción siguiente o la desincroniza. Si el botón se sigue moviendo mientras el usuario ya está pulsando el siguiente control, la interfaz muestra un estado que ya no es cierto. Y si el código espera al final de la animación para hacer algo, el usuario espera de verdad.

Se ve muchas veces. Un botón se pulsa cientos de veces. Todo lo que se repite tiende a la sobriedad, porque el valor de la novedad se agota a la segunda vez y el coste temporal no se agota nunca. Ochocientos milisegundos por doscientas pulsaciones al día son casi tres minutos diarios de espera regalada.

La forma correcta de comprobarlo no es discutir, es medir el tiempo entre la acción y la señal:

// Cuanto tarda el usuario en ver una respuesta a su pulsacion.
boton.addEventListener('pointerdown', (e) => {
  const t0 = e.timeStamp;
  requestAnimationFrame(() => {
    const anim = boton.getAnimations()[0];
    console.log('primer fotograma en', performance.now() - t0, 'ms');
    if (anim) console.log('senal completa en', anim.effect.getComputedTiming().endTime, 'ms');
  });
});

Lo que importa no es solo cuándo acaba, sino cuándo el usuario ve suficiente para saber que su acción llegó. Con una curva de salida rápida, el 80 por ciento del movimiento ocurre en el primer tercio de la duración, y esa es la cifra que hay que mirar.

La duración que percibe el usuario no es la que escribes: es la que tarda en verse el cambio

Aquí está la sutileza que convierte discusiones sobre duración en decisiones técnicas, y que casi nadie tiene en cuenta al calibrar. El número que pones en transition-duration es cuándo termina la interpolación, pero lo que el usuario cronometra inconscientemente es cuándo el cambio se ha hecho legible, que con una curva de salida ocurre muchísimo antes. Con cubic-bezier(0.2, 0, 0, 1) y 300 milisegundos, el elemento ha recorrido el 80 por ciento del camino en unos 110: perceptivamente, esa animación “dura” poco más de cien milisegundos y los otros doscientos son un asentamiento que nadie espera activamente. Con linear y los mismos 300, el 80 por ciento llega a los 240, y esa animación se percibe casi tres veces más lenta con el mismo número escrito en el CSS. La consecuencia práctica es doble y va en las dos direcciones. Primera: cambiar la curva es a menudo la forma correcta de arreglar una animación que se siente lenta, sin tocar la duración y por tanto sin desincronizar nada de lo que dependa de ella. Segunda, y menos obvia: en una escala de duraciones compartida por todo un sistema de diseño, fijar solo los milisegundos y dejar la curva a criterio de cada quien produce un sistema incoherente aunque todos usen los mismos tokens, porque dos componentes con 300ms y curvas distintas se perciben con duraciones distintas. La duración y la curva son un solo token, no dos. Si tu sistema tiene --dur-media sin un --ease-media que lo acompañe obligatoriamente, tiene la mitad de la información.

La escala no debe ser lineal

Una escala de duraciones con valores de 100, 200, 300, 400 y 500 milisegundos parece ordenada y funciona mal, porque la percepción del tiempo es aproximadamente logarítmica: la diferencia entre 100 y 200 se nota muchísimo, y la diferencia entre 400 y 500 apenas.

Una escala útil crece por un factor, no por una suma, y tiene menos peldaños de los que la gente cree necesitar. Cuatro o cinco bastan para cualquier producto:

:root {
  --dur-instante: 80ms;   /* acuse de recibo */
  --dur-rapida:   140ms;  /* cambio de estado sin movimiento */
  --dur-media:    240ms;  /* elemento que entra o sale */
  --dur-lenta:    380ms;  /* panel o vista */

  --ease-entrada: cubic-bezier(0.2, 0, 0, 1);
  --ease-salida:  cubic-bezier(0.4, 0, 1, 1);
  --ease-mueve:   cubic-bezier(0.4, 0, 0.2, 1);
}

Cada peldaño es aproximadamente 1.6 veces el anterior, que es un salto perceptible sin ser brusco. Y hay una regla que no se ve en la escala pero que la acompaña: la salida siempre es más corta que la entrada del mismo elemento, típicamente entre el 60 y el 80 por ciento. Cuando algo aparece, el usuario tiene que localizarlo y leerlo; cuando desaparece, ya no le interesa y alargarlo es hacerle esperar por nada.

Las tres excusas para alargar

“Es que si no, no se ve.” Si una animación necesita ser larga para percibirse, el problema es la magnitud del cambio, no la duración. Un desplazamiento de tres píxeles no se ve en 200 milisegundos ni en 800; se ve si son doce píxeles en 200. Aumenta el recorrido, no el tiempo.

“Es que queda más elegante.” Casi siempre lo que se percibe como elegancia es una curva de salida bien elegida, no una duración larga. Prueba a bajar la duración a la mitad y a alargar la cola de la curva; en la mayoría de los casos la sensación se conserva y el tiempo de espera se parte por dos.

“Es que la marca es así.” Legítimo en una página de presentación de producto, donde el usuario ha ido a mirar. Ilegítimo en una herramienta, donde ha ido a trabajar. La misma marca puede tener dos escalas de duración, y los productos serios las tienen: una para el escaparate y otra para la aplicación.

⚔️ Audita la escala de un producto
  1. Recoge todas las duraciones de animación que existan en un proyecto real y ordénalas. Cuenta cuántos valores distintos hay.
  2. Sustitúyelas por la escala de cuatro peldaños de esta lección, asignando cada una a su tramo perceptivo. Anota cuáles cambiaron mucho.
  3. Para las que estaban por encima de su tramo, prueba a mantener la duración original pero con una curva de salida más pronunciada, y decide con datos cuál de las dos correcciones prefieres.