Jerarquía del movimiento: qué se mueve primero y por qué
El orden causal de una coreografía, las reglas del escalonado con sus números, por qué las salidas no se escalonan, la consistencia espacial y el límite de cosas que pueden moverse a la vez.
Con la escala de duraciones y el catálogo de curvas resueltos, cada animación por separado está bien y el conjunto puede seguir sintiéndose caótico. Lo que falta es el orden: qué se mueve primero, qué espera, qué se mueve junto y cuántas cosas pueden moverse a la vez sin que la pantalla se vuelva ilegible. La coreografía es el nivel donde el movimiento pasa de ser una propiedad de los componentes a ser una propiedad del producto.
- Ordenar una coreografía según la cadena causal de la interacción.
- Aplicar el escalonado con valores concretos y conocer su coste en duración total.
- Justificar por qué las entradas se escalonan y las salidas no.
- Limitar el número de elementos en movimiento simultáneo y agrupar el resto.
El orden lo dicta la causa
La regla que ordena todo lo demás: se mueve primero lo que el usuario tocó, después lo que cambió por eso, y al final lo que solo acompaña.
Esa secuencia no es una convención estética: reproduce la cadena causal del suceso, y el sistema visual está construido para leer cadenas causales. Cuando el orden se invierte —cuando el panel aparece antes de que el botón haya reaccionado— la interfaz se percibe como que “se adelanta”, y el efecto es de descontrol aunque todo dure lo mismo.
La coreografía de una apertura de panel, en orden:
- 0 ms. El botón responde. Hundido, cambio de estado, lo que sea, dentro del umbral de causalidad. Sin excepciones: esto no espera a nada.
- 0-60 ms. El fondo empieza a oscurecerse. Es el contexto que se retira, y tiene que empezar antes que el contenido nuevo para que se lea como “lo de detrás se aparta”.
- 60-100 ms. El contenedor del panel entra. Es el objeto principal del cambio.
- A partir de 120 ms. El contenido interior, si va escalonado.
El desfase entre el paso 2 y el 3 es de unos cuarenta a ochenta milisegundos: suficiente para que el orden se perciba, insuficiente para que se lea como espera. Por debajo de treinta no se nota y da igual; por encima de ciento veinte, el usuario percibe dos sucesos separados en lugar de uno.
Y el orden inverso en el cierre, que es donde más se falla: lo último que entró es lo primero que sale. El contenido antes que el contenedor, el contenedor antes que el fondo. Si el fondo se aclara primero, el panel se queda flotando sobre la interfaz ya visible durante un instante, y eso se lee como un error de renderizado.
El escalonado y sus números
El escalonado —retrasar cada elemento de un grupo un poco respecto al anterior— hace dos cosas: dirige el recorrido del ojo en un orden concreto, y reparte en el tiempo un cambio que de golpe sería demasiada información simultánea.
Los números que funcionan, con su razón:
Paso entre elementos: de 20 a 60 ms. Por debajo de veinte no se percibe como secuencia, se percibe como que todos entraron a la vez con ruido. Por encima de sesenta se percibe como que van uno detrás de otro, que es otro efecto distinto y casi siempre indeseado en una interfaz. Cuarenta es un buen valor por defecto.
Duración total del escalonado: máximo 300 ms. Este es el número que casi nadie respeta y el que arruina las coreografías. Con un paso de cuarenta milisegundos, ocho elementos son trescientos veinte milisegundos solo de retardos, más la duración del último. Un escalonado de veinte elementos a cuarenta milisegundos son ochocientos milisegundos de espera para ver la lista completa, cada vez que se abre.
Número máximo de elementos escalonados: de seis a ocho. Pasado ese número, el ojo deja de leer una secuencia y lee una ola, y la información que aportaba el orden se pierde. Lo que hay que hacer con una lista de cuarenta elementos es escalonar los primeros y que el resto entre junto, o escalonar por grupos en lugar de por elemento.
const PASO = 40;
const MAX_ESCALONADOS = 6;
elementos.forEach((el, i) => {
const retardo = Math.min(i, MAX_ESCALONADOS) * PASO;
el.animate(
[{ opacity: 0, transform: "translateY(12px)" }, { opacity: 1, transform: "none" }],
{ duration: 250, delay: retardo, easing: "cubic-bezier(0, 0, 0.2, 1)", fill: "both" }
);
});
Ese Math.min acota el retardo máximo a doscientos cuarenta milisegundos independientemente del tamaño de la lista. Los elementos a partir del séptimo entran todos juntos, y nadie lo nota, porque a esa altura de la lista el ojo ya no está contando.
En CSS, el mismo patrón con un índice:
.item {
opacity: 0;
translate: 0 12px;
transition:
opacity var(--mov-media) linear var(--retardo, 0ms),
translate var(--mov-media) var(--mov-entrada) var(--retardo, 0ms);
}
.visible .item { opacity: 1; translate: 0 0; }
.item:nth-child(1) { --retardo: 0ms; }
.item:nth-child(2) { --retardo: 40ms; }
.item:nth-child(3) { --retardo: 80ms; }
.item:nth-child(4) { --retardo: 120ms; }
.item:nth-child(5) { --retardo: 160ms; }
.item:nth-child(n + 6) { --retardo: 200ms; }
Esa última regla es la clave: a partir del sexto, todos comparten retardo. Es la versión declarativa del tope.
Un escalonado alarga la exposición al movimiento y añade elementos que se mueven en momentos distintos, que es peor que uno solo. En la versión reducida, todos los elementos entran a la vez con un fundido corto. Con la técnica del multiplicador, basta con poner el paso a cero.
Las salidas no se escalonan
Se escalona lo que hay que leer. Una entrada escalonada dirige la atención y ordena la información nueva. Una salida no aporta nada leer: el contenido ya no interesa, y escalonarlo solo alarga la espera hasta que la pantalla esté disponible.
La regla es directa: todo lo que sale, sale junto y rápido. Un panel que se cierra desvanece su contenido de golpe mientras el contenedor se va. Una lista que se filtra deja marchar a la vez todos los elementos que ya no encajan, y solo escalona la entrada de los nuevos si los hay.
La excepción, igual que con las duraciones, es cuando la salida es la información: elementos que se archivan hacia un sitio concreto y quieres que el usuario vea adónde van. Entonces la salida comunica y merece coreografía.
Consistencia espacial
Una interfaz se siente sólida cuando los objetos tienen un sitio y vuelven a él. Tres reglas.
Cada cosa entra por donde vive. El panel lateral derecho entra desde la derecha, siempre, en todas las pantallas. Un menú anclado a un botón crece desde ese botón, no desde el centro. Un aviso que aparece en la esquina inferior entra desde abajo. Cuando la dirección de entrada es arbitraria, la interfaz pierde geografía y todo parece flotar.
El origen de la transformación es el punto de la interacción. Un menú que se abre desde un botón debe escalar desde la esquina más cercana a ese botón, con transform-origin puesto en consecuencia. Es un detalle de dos palabras que cambia por completo la sensación de que el menú “sale de ahí” en lugar de “aparece encima de ahí”.
.menu[data-anclaje="abajo-derecha"] { transform-origin: top right; }
.menu[data-anclaje="abajo-izquierda"] { transform-origin: top left; }
.menu[data-anclaje="arriba-derecha"] { transform-origin: bottom right; }
Lo que es el mismo objeto se mueve como el mismo objeto. Si una tarjeta se expande a una vista de detalle, tiene que ser la misma caja transformándose, no una caja que desaparece y otra que aparece. Es el patrón de elemento compartido, y es lo que hace que dos pantallas se entiendan como dos estados de una cosa en lugar de como dos pantallas.
El límite de cosas en movimiento
La regla que más mejora una coreografía complicada: en cualquier instante, no más de tres o cuatro elementos moviéndose de forma independiente.
“De forma independiente” es la parte importante. Veinte elementos que se desplazan juntos dentro de un contenedor son un movimiento: el ojo los agrupa y lee un solo objeto. Cuatro elementos moviéndose en direcciones distintas con curvas distintas son cuatro, y ya es el máximo tolerable.
La consecuencia práctica es que la técnica principal de una coreografía compleja no es añadir animaciones sino agrupar: en lugar de animar doce tarjetas, anima el contenedor y deja que las tarjetas vayan dentro. Además de leerse mejor, cuesta una capa de compositor en lugar de doce.
Y una comprobación que detecta el exceso al instante: graba la pantalla y reprodúcela al 10% con el panel de animaciones. Si en algún fotograma hay más de cuatro trayectorias distintas, sobra coreografía.
Es fácil pensar en una coreografía como en un problema de planificación temporal —qué empieza cuándo, cuánto dura cada cosa, cómo se solapan— y con esa manera de pensarlo se llega a resultados que están técnicamente bien ordenados y se sienten mal. Lo que de verdad se está repartiendo no es tiempo sino atención, y la atención tiene una propiedad que el tiempo no tiene: es de un solo destino a la vez. Dos elementos que se mueven simultáneamente en direcciones distintas no consumen dos ranuras de un recurso divisible; compiten por uno indivisible, y el resultado es que la persona mira uno y se pierde el otro, o no mira ninguno del todo y no lee ninguno de los dos. Por eso el límite de tres o cuatro trayectorias no es una convención de buen gusto sino una consecuencia de cómo funciona el sistema visual, y por eso el escalonado funciona: no es que quede elegante, es que convierte una competencia por un recurso indivisible en una secuencia de usos. Y de ahí sale la prueba que resuelve casi cualquier discusión sobre coreografía, que es preguntar, para cada instante de la animación, dónde quieres que esté mirando la persona. Si la respuesta es “en el panel que entra”, entonces todo lo demás que se mueva en ese instante está robando; el fondo que se oscurece puede hacerlo antes o después, no a la vez. Si la respuesta es “en el botón que acaba de pulsar”, el panel no debería estar moviéndose todavía. Si la respuesta es “no lo sé” o “en varias cosas”, la coreografía no está diseñada: está simplemente ocurriendo, que es lo que pasa cuando cada componente anima su entrada por su cuenta sin saber que hay otros cinco haciendo lo mismo en la misma pantalla. Ese es el estado por defecto de cualquier producto sin sistema de movimiento, y explica por qué añadir animaciones componente a componente empeora la sensación de conjunto aunque cada una esté bien hecha.