wandres.dev
NIVEL DIOS · Síntesis de la animación web

El árbol de decisión completo de la animación web

Las tres preguntas que ordenan cualquier decisión de animación, el árbol de la técnica desde la propiedad hasta la librería, el mapa de patrones con su técnica recomendada, y las restricciones que no se negocian.

⏱ 20 min

Cuarenta y dos niveles de territorio se pueden comprimir en tres preguntas, y hacerlas en el orden correcto resuelve la mayoría de las decisiones antes de escribir nada. Qué propiedad vas a animar decide el coste. Qué mecanismo la ejecuta decide la potencia y la dependencia. Quién la dispara decide dónde vive el código. Todo lo demás son consecuencias.

🎯 Al terminar esta lección sabrás
  • Aplicar las tres preguntas en orden para acotar cualquier decisión de animación.
  • Recorrer el árbol de la técnica desde la propiedad hasta la elección de librería.
  • Consultar el mapa de patrones para saber qué técnica corresponde a cada caso resuelto.
  • Enumerar las restricciones que ninguna decisión puede violar.

Las tres preguntas, en orden

Uno: ¿qué propiedad se mueve? Es la primera porque determina el coste y el coste determina si todo lo demás importa. transform, opacity y en menor medida filter se ejecutan en el compositor: cuestan prácticamente cero en el hilo principal y sobreviven a que ese hilo esté bloqueado. Todo lo demás dispara alguna combinación de recálculo de estilo, layout y pintado en cada fotograma. La diferencia no es de porcentajes.

Si la propiedad que necesitas está en el lado caro, la pregunta correcta no es “cómo lo optimizo” sino “cómo expreso esto con transform y opacity. Casi siempre se puede: una altura se convierte en una escala con contra-escala o en un grid-template-rows, una posición se convierte en una traslación, un cambio de color se convierte en una capa superpuesta que aparece. Y cuando no se puede, se hace igual pero sabiendo lo que cuesta y midiéndolo.

Dos: ¿qué mecanismo la ejecuta? En orden de menor a mayor dependencia: CSS, WAAPI, librería declarativa, librería híbrida, motor completo. La regla es coger el primero que resuelva el problema, no el más potente que puedas justificar. Cada escalón añade bytes, una superficie de API que hay que conocer y una decisión que revisar dentro de dos años.

Tres: ¿quién la dispara? Un cambio de clase, un evento de puntero, un cambio de estado de un componente, el scroll, una navegación, o el paso del tiempo. Esto decide dónde vive el código y qué API es natural: lo que dispara el scroll quiere una timeline de scroll; lo que dispara una navegación quiere View Transitions; lo que dispara el montaje de un componente quiere el modelo declarativo del framework.

Hacerlas en otro orden produce las decisiones malas típicas. Empezar por la librería lleva a animar width con un motor de última generación, que es rápido haciendo una cosa lenta. Empezar por el disparador lleva a manejadores de scroll que fuerzan layout. La propiedad va primero porque es la única de las tres que impone un límite físico.

El árbol de la técnica

Si es un cambio de estado que se expresa con una clase o una pseudoclase, y no necesitas control programático: CSS. Con @starting-style y transition-behavior: allow-discrete cubres entrada y salida completas de un dialog o un popover; con interpolate-size: allow-keywords, la altura automática. No necesitas nada más y funciona antes de que hidrate nada.

Si necesitas pausar, invertir, leer el progreso, esperar el final o gobernar todas las animaciones del documento: WAAPI. element.animate() devuelve un objeto con finished como promesa, playbackRate, currentTime y commitStyles, y document.getAnimations() te da el inventario completo. Cero dependencias.

Si el elemento se monta y se desmonta con el estado de un componente: la librería declarativa del framework. El desmontaje es el problema que no se puede resolver bien desde fuera, porque solo el framework sabe cuándo va a ocurrir.

Si necesitas muelles interrumpibles o una API imperativa compacta sin acoplarte: una librería híbrida. Delega en WAAPI lo que puede y baja a su bucle cuando hace falta.

Si necesitas al menos una de estas cuatro, un motor completo: secuencias largas con solapes que se recalculan solos, scroll con fijado y ajuste por secciones, división de texto con recomposición al cambiar el ancho, o morfismo entre formas SVG arbitrarias. Si no necesitas ninguna de las cuatro, no lo necesitas.

Si es una ilustración vectorial compleja hecha por diseño: un reproductor de Lottie, sabiendo que es un intérprete completo ejecutándose en el hilo principal. Para menos de una docena de formas, SVG animado a mano.

Si es una ilustración con efectos que el vector no soporta: vídeo con canal alfa. El decodificador es hardware y el coste por fotograma de tu hilo principal es cero.

El mapa de patrones

flowchart LR
acor[Acordeon] --> css[CSS puro]
modal[Modal y hoja] --> css
menu[Menu y tooltip] --> css
skel[Esqueleto de carga] --> css
boton[Respuesta al puntero] --> css
reveal[Revelado al hacer scroll] --> sdt[Timeline de scroll con retroceso]
progreso[Barra de progreso de lectura] --> sdt
lista[Lista que se reordena] --> flip[FLIP con WAAPI]
filtro[Rejilla que se filtra] --> flip
pagina[Transicion de pagina] --> vt[View Transitions]
detalle[Tarjeta que se expande a detalle] --> vt
drag[Arrastrar y soltar] --> gesto[Pointer Events mas muelle]
swipe[Deslizar para descartar] --> gesto
intro[Secuencia narrativa larga] --> motor[Motor con timeline]
texto[Texto que entra por lineas] --> motor
ilustra[Ilustracion animada compleja] --> lottie[Lottie o video con alfa]
style css fill:#a6e3a1,color:#11111b
style sdt fill:#94e2d5,color:#11111b
style flip fill:#89b4fa,color:#11111b
style vt fill:#cba6f7,color:#11111b
style gesto fill:#f9e2af,color:#11111b
style motor fill:#fab387,color:#11111b
style lottie fill:#f38ba8,color:#11111b

Lo que salta a la vista de este mapa, y es la conclusión principal del track: la columna verde es la más larga. Los cinco patrones más frecuentes de cualquier interfaz —acordeón, modal, menú, esqueleto y respuesta al puntero— se resuelven con CSS puro, sin una sola dependencia, con el coste más bajo posible y con el mejor comportamiento ante un hilo principal ocupado. Un producto entero puede vivir en esa columna, y muchos deberían.

Las cinco técnicas siguientes cubren casi todo lo demás, y solo la última fila necesita algo que no está en la plataforma. Las cuatro lecciones restantes de este nivel desarrollan cada patrón con código completo.

Las restricciones que no se negocian

Todo lo anterior son decisiones. Esto no lo son: son condiciones que cualquier solución tiene que cumplir, y una animación que no las cumpla está mal aunque sea preciosa.

El movimiento tiene una versión reducida diseñada. No apagada: sustituida. Y el movimiento que simula desplazamiento propio —escalas grandes, paralaje, rotación, áreas grandes— no debería existir sin un control visible para desactivarlo, independientemente de las preferencias del sistema.

Nada destella más de tres veces por segundo. No es una preferencia, es un riesgo médico y no admite versión.

Nada que empiece solo dura más de cinco segundos sin un control para pararlo. Criterio 2.2.2, nivel A.

El estado lógico se representa con atributos que el navegador entiende, no con propiedades visuales. hidden, inert, aria-expanded, open, popover. La animación se cuelga del estado, nunca al revés. Esto elimina de golpe casi todos los fallos de foco y de lectura.

Toda animación tiene que sobrevivir a que la interrumpan a mitad. Pulsar dos veces rápido, cambiar de estado a medio camino, redimensionar mientras corre. La mayoría de los defectos de animación en producción son de interrupción, no de rendimiento.

Nada decorativo va en la ruta crítica. Ni retrasa el primer pintado, ni retrasa el momento en que la persona puede hacer lo que vino a hacer.

Se mide con estrangulamiento de CPU. Un resultado obtenido en tu máquina de desarrollo no dice nada sobre el dispositivo del usuario.

La progresión del track es una historia sobre delegación, y saber en qué punto de esa historia estás es lo que evita las decisiones caras

Si miras hacia atrás los cuarenta y dos niveles con un poco de distancia, no son cuarenta y dos temas: son una única línea argumental sobre cuánto trabajo puedes delegar y a quién. En el extremo más delegado está CSS, donde tú declaras un estado final y el navegador decide cuándo interpolar, con qué frecuencia muestrear, en qué hilo ejecutarlo y qué hacer si el usuario cambia de opinión a mitad; no controlas nada y a cambio no puedes equivocarte casi en nada. En el extremo opuesto está tu propio bucle de requestAnimationFrame, donde controlas cada valor de cada fotograma y por tanto eres responsable del delta time, del framerate variable, de la interrupción, de la limpieza, del hilo en el que corre y de que siga funcionando cuando el dispositivo esté ocupado. Todas las herramientas del track se ordenan entre esos dos extremos, y cada escalón que subes hacia el control te transfiere una responsabilidad que antes tenía otro. Eso no es malo: hay animaciones que solo se pueden hacer arriba. Lo que es malo, y es el error caro que se comete una y otra vez, es subir escalones sin necesitarlos, porque las responsabilidades transferidas no se devuelven: se quedan en tu código, las hereda quien venga después, y aparecen en forma de bugs que nadie relaciona con la decisión que los causó. Un equipo que resuelve un acordeón con un motor completo no ha elegido una herramienta mejor: ha aceptado gestionar a mano la interrupción, la limpieza, el movimiento reducido y el comportamiento en un hilo bloqueado, cuatro cosas que el navegador le estaba haciendo gratis. La madurez en esta disciplina no se demuestra sabiendo usar la herramienta más potente; se demuestra sabiendo cuál es el escalón más bajo que resuelve el problema, y quedándose ahí aunque sepas manejar los de arriba.