10 principios para animaciones web fluidas
La guía completa para lograr animaciones a 60fps con CSS

Desde que lanzamos Gyroscope el año pasado, mucha gente nos preguntó por la librería de JavaScript que usamos para nuestras animaciones. Pensamos en publicarla, pero en realidad no es ahí donde está la magia.
No queremos que nadie sienta que depende de algún plugin especial de JavaScript que resuelve estos problemas por arte de magia. En general, solo estamos aprovechando las mejoras recientes en el rendimiento de los navegadores, en las GPU y en la especificación de CSS3.
No hay una bala de plata para lograr buenas animaciones, más allá de dedicarles mucho tiempo de pruebas y optimización. Aun así, después de años de experimentar y de chocar contra los límites del rendimiento de los navegadores, llegamos a una serie de principios de diseño & código que parecen dar animaciones lindas de forma confiable. Estas técnicas deberían darte páginas que se sienten fluidas, funcionan en navegadores modernos de escritorio y móviles y, lo más importante, son fáciles de mantener.

La tecnología y la implementación van a ser algo distintas para cada uno, pero los principios generales deberían servir en casi cualquier situación.
¿Qué es una animación?
Las animaciones existen desde mucho antes que internet, y hacerlas bien es algo a lo que podrías dedicarle la vida entera. Sin embargo, hacerlas para internet tiene restricciones y desafíos propios.
Para un rendimiento fluido a 60fps, ¡cada cuadro tiene que renderizarse en menos de 16ms! No es mucho tiempo, así que hay que encontrar formas muy eficientes de renderizar cada cuadro.
Hay decenas de formas de animar en la web. Por ejemplo, la tira de fotogramas es un enfoque anterior a internet: cuadros dibujados a mano, apenas distintos entre sí, que se intercambian muchas veces por segundo para crear la ilusión de movimiento.
Twitter usó hace poco este enfoque simple para su nueva animación del corazón, pasando por los cuadros de un sprite.

Este efecto se podría haber hecho con un montón de elementos diminutos animados uno por uno, o quizá como un SVG, pero sería innecesariamente complejo y probablemente no se vería tan fluido.

En muchos casos vas a querer usar la propiedad transition de CSS para animar automáticamente un elemento a medida que cambia. Esta técnica también se conoce como “tweening”, es decir, la transición entre dos valores distintos. Tiene la ventaja de que se puede cancelar o revertir con facilidad sin tener que programar toda esa lógica. Es ideal para animaciones del tipo “ponlo y olvídate”, como las secuencias de entrada, o para interacciones simples como los hovers.
Para leer más: All you need to know about CSS Transitions

En otros casos, la propiedad animation de CSS basada en keyframes puede ser ideal para detalles de fondo que corren todo el tiempo. Por ejemplo, los anillos del logo de Gyroscope están programados para girar sin parar. Otro tipo de cosas que se benefician de la sintaxis de animation son las relaciones de engranajes.
Así que, sin más vueltas, acá van algunos consejos que ojalá mejoren mucho el rendimiento de tus animaciones…
#1
¡No cambies ninguna propiedad que no sea opacity o transform!
Aunque creas que en este caso no pasa nada, ¡no lo hagas!
Solo este principio básico te lleva el 80% del camino, incluso en móviles. Seguro ya lo escuchaste antes: no es una idea original, pero casi nadie la sigue. Es el equivalente web de “come sano y haz ejercicio”, que suena a buen consejo pero probablemente ignoras.
Es bastante directo una vez que te acostumbras a pensar así, aunque puede ser un salto grande para quienes están habituados a animar propiedades tradicionales de CSS.
Por ejemplo, si quieres achicar algo, puedes usar transform: scale() en vez de cambiar el width. Si quieres moverlo, en lugar de tocar márgenes o paddings, que obligan a reconstruir todo el layout de la página en cada cuadro, puedes usar simplemente transform: translateX o transform: translateY.
¿Por qué funciona esto?
Para una persona, cambiar el width, el margin u otras propiedades puede parecer poca cosa, o incluso preferible porque es más simple, pero en términos de lo que tiene que hacer la computadora son mundos distintos, y uno es muchísimo peor.
Los equipos de los navegadores hicieron un gran trabajo optimizando estas operaciones. Las transforms son muy fáciles de resolver de forma eficiente y muchas veces aprovechan tu tarjeta gráfica sin volver a renderizar los elementos.
Puedes hacer locuras al cargar la página por primera vez: redondear todas las esquinas, usar imágenes, ponerle sombra a todo y, si te sientes especialmente temerario, hasta un blur dinámico. Si pasa una sola vez, unos milisegundos extra de cálculo no importan. Pero una vez que el contenido está renderizado, no quieres seguir recalculando todo.
Para leer más: Moving elements with translate (Paul Irish)
#2
Esconde el contenido a plena vista.
Usa pointer-events: none junto con opacity cero para ocultar elementos
Este puede tener algunas advertencias entre navegadores, pero si solo construyes para webkit y otros navegadores modernos, te va a hacer la vida mucho más fácil.
Hace mucho tiempo, cuando las animaciones se manejaban con el animate() de jQuery, buena parte de la complejidad de aparecer y desaparecer cosas venía de cambiar entre display: none y block en el momento justo. Muy temprano y la animación no terminaba; muy tarde y te quedaba contenido invisible con opacity cero tapando la página. Todo necesitaba callbacks para limpiar después de la animación.
La propiedad pointer-events de CSS (que existe desde hace bastante, pero se usa poco) básicamente hace que las cosas no respondan a clics ni a interacciones, como si no estuvieran ahí. Se puede prender y apagar fácil desde CSS sin interrumpir animaciones ni afectar el renderizado o la visibilidad de ninguna forma.
Combinada con una opacity de cero, tiene prácticamente el mismo efecto que display none, pero sin el costo de rendimiento de disparar nuevos renders. Cuando escondo cosas, casi siempre me alcanza con poner la opacity en 0 y apagar pointer-events, y después olvidarme del elemento sabiendo que se cuida solo.
Esto funciona especialmente bien con elementos posicionados de forma absoluta, porque puedes estar seguro de que no están afectando absolutamente nada más de la página.
También te da un poco más de margen, porque el timing no tiene que ser perfecto: no es el fin del mundo si un elemento es clicable o tapa otras cosas un segundo más de lo que estuvo visible, o si solo se vuelve clicable cuando terminó de aparecer.
#3
No animes todo al mismo tiempo.
Mejor usa coreografía.
Una animación sola puede verse fluida, pero al mismo tiempo que muchas otras probablemente se rompa. Es muy fácil armar una demo básica de casi cualquier cosa funcionando bien, y un orden de magnitud más difícil mantener ese rendimiento con un sitio completo. Por eso es importante programarlas bien.
Conviene separar los tiempos para que no arranque ni corra todo exactamente a la vez. Normalmente 2 o 3 cosas pueden moverse al mismo tiempo sin frenar nada, sobre todo si arrancaron en momentos apenas distintos. Más que eso y te arriesgas a picos de lag.
A menos que en tus páginas haya literalmente una sola cosa, es importante entender el concepto de coreografía. Puede sonar a término de danza, pero es igual de importante para animar interfaces. Las cosas tienen que entrar desde la dirección correcta y en el momento correcto. Aunque estén separadas, deben sentirse parte de una única unidad bien diseñada.
El material design de Google tiene sugerencias interesantes sobre el tema. No es la única forma correcta de hacer las cosas, pero es algo en lo que deberías pensar y que deberías probar.

Para leer más: Google Material Design · Motion
#4
Aumentar de a poco los delays de transición hace fácil coreografiar el movimiento.
Coreografiar animaciones es importantísimo y va a llevarte mucha experimentación y muchas pruebas hasta que se sienta bien. Sin embargo, el código no tiene por qué ser complicado.
Normalmente cambio una sola clase en un elemento padre (muchas veces en body) para disparar un montón de transiciones, y cada una tiene su propio transition-delay para entrar en el momento justo. Desde el código solo te tienes que preocupar por un cambio de estado, y no por mantener decenas de tiempos en tu JavaScript.

Escalonar una serie de elementos es una forma fácil y simple de coreografiarlos. Es potente porque se ve bien y al mismo tiempo te compra un rendimiento precioso: recuerda que quieres pocas cosas pasando a la vez. Conviene separarlas lo suficiente para que cada una se sienta fluida, pero no tanto como para que todo se sienta lento. Deben superponerse lo justo para que parezca un flujo continuo y no una cadena de cosas sueltas.
Ejemplo de código
Hay un par de técnicas simples para escalonar tus elementos, sobre todo si es una lista larga. Si hay menos de 10 ítems, o una cantidad muy previsible (como en una página estática), suelo definir los valores en CSS. Es lo más simple y lo más fácil de mantener.

Para listas más largas o contenido muy dinámico, los tiempos se pueden asignar dinámicamente recorriendo cada ítem.

Normalmente hay dos variables: tu delay base y el tiempo entre cada ítem. Es un equilibrio difícil de encontrar, pero cuando das con los números correctos se siente perfecto.
#5
Usa un multiplicador global para diseñar en cámara lenta
Y después acelera todo.
En el diseño de animaciones, el timing lo es todo. El 20% del trabajo es implementar algo, y el otro 80% es encontrar los parámetros & las duraciones correctas para que todo quede sincronizado y se sienta fluido.
Sobre todo cuando trabajas la coreografía de varias cosas y tratas de exprimir rendimiento y simultaneidad de la página, ver todo en cámara lenta te lo va a hacer mucho más fácil.
Ya sea que uses Javascript o algún preprocesador de CSS como SASS (que nos encanta), debería ser bastante sencillo hacer un poco de matemática extra y construir con variables.
Asegúrate de que sea cómodo probar distintas velocidades o tiempos. Por ejemplo, si una animación se traba incluso a 1/10 de velocidad, quizá haya algo mal de raíz. Si va fluida estirada 50x, entonces es solo cuestión de encontrar la velocidad máxima a la que funciona. Puede ser difícil notar problemas de 5 milisegundos a velocidad normal, pero si desaceleras todo se vuelven evidentísimos.
Sobre todo en animaciones muy complejas, o para resolver cuellos de botella difíciles de rendimiento, poder ver las cosas en cámara lenta es muy útil.
La idea principal es meter muchos detalles perfectos mientras va lento, y después acelerar todo para que se sienta perfecto. Va a ser muy sutil, pero la persona que lo use va a notar la fluidez y los detalles.
Esta función existe de hecho en OS X: si haces shift-clic en el botón de minimizar o en el icono de una app, vas a ver la animación en cámara lenta. En un momento incluso implementamos esta función de cámara lenta en Gyroscope, que se activaba al presionar shift.
#6
Graba videos de tu interfaz y míralos para ganar una valiosa perspectiva desde afuera.
A veces una perspectiva distinta te deja ver las cosas con más claridad, y el video es una gran forma de lograrlo.
Hay gente que arma un video en after effects y después intenta implementarlo en un sitio. Yo muchas veces voy al revés, y trato de hacer un buen video a partir de la interfaz de un sitio.
Poder publicar un Vine* o un video de algo es una vara bastante alta. Un día estaba entusiasmado con algo que había construido e intenté grabarlo para compartirlo con unos amigos.
Pero cuando lo miré de nuevo noté un montón de cosas que no estaban buenas. Había un pico de lag grande y todos los tiempos estaban un poco mal. Me dio un poco de vergüenza y, en lugar de mandarlo, me di cuenta de que quedaba mucho trabajo por hacer.
Es fácil pasar por alto estas cosas cuando lo usas en tiempo real, pero mirar las animaciones en video, una y otra vez o en cámara lenta, vuelve cualquier problema evidentísimo.
Dicen que la cámara suma 10 libras. Quizá también sume 10 cuadros.
Ya es parte importante de mi flujo de trabajo mirar videos en cámara lenta de mis páginas y hacer cambios si algún cuadro no se siente bien. Es fácil echarle la culpa a los navegadores lentos, pero con más optimización y más pruebas se pueden resolver todos esos problemas.
Cuando ya no te dé vergüenza que el video muestre picos de lag, y sientas que está lo bastante bien como para compartirlo, la página probablemente esté lista para salir.
#7
La actividad de red puede causar lag.
Conviene precargar o retrasar las peticiones HTTP grandes
Las imágenes son una gran culpable acá, ya sean unas pocas muy pesadas (un fondo grande, por ejemplo), muchísimas chiquitas (imagina 50 avatares cargando) o simplemente mucho contenido (una página larga con imágenes hasta el pie).
Cuando la página recién carga, se están inicializando y descargando un montón de cosas. Tener analítica, publicidad y otros scripts de terceros lo empeora. A veces, retrasar todas las animaciones apenas unos cientos de milisegundos después de la carga hace maravillas con el rendimiento.
No optimices de más por esto hasta que sea necesario, pero una página complicada puede necesitar delays y tiempos de contenido muy precisos para correr fluida. En general, conviene cargar la menor cantidad de datos posible al principio y después seguir cargando el resto de la página cuando ya pasó el trabajo pesado y las animaciones de entrada.
En páginas con muchos datos, el trabajo de cargar todo puede ser considerable. Una animación que funciona bien con contenido estático puede desarmarse cuando empiezas a cargar datos reales al mismo tiempo. Si algo parece que debería funcionar, o a veces va fluido y a veces no, sugiero revisar la actividad de red para asegurarte de que no estés haciendo otras cosas en paralelo.
#8
No ates nada directamente al scroll.
Parece una idea genial, pero no lo es.
Las animaciones basadas en scroll ganaron mucha popularidad en los últimos años, sobre todo las que usan parallax u otros efectos especiales. Si son buen diseño o no es discutible, pero hay mejores y peores formas de implementarlas técnicamente.
Una manera moderadamente eficiente de hacer cosas de este tipo es tratar la llegada a cierta distancia de scroll como un evento, y disparar las cosas una sola vez. A menos que sepas muy bien lo que estás haciendo, sugiero evitar esta categoría, porque es facilísimo que salga mal y muy difícil de mantener.
Peor todavía es construir tu propia barra de scroll en vez de usar la que ya existe, lo que se conoce como scrolljacking. Por favor, no lo hagas.
Esta es una de esas reglas especialmente útiles en móviles, pero probablemente también sea buena práctica para lograr la mejor experiencia posible.
Si de verdad quieres un tipo de experiencia concreta centrada en el scroll o en eventos especiales, sugiero armar un prototipo rápido para asegurarte de que rinda bien antes de dedicarle mucho tiempo al diseño.
#9
Prueba en móvil temprano & seguido.
Casi todos los sitios se construyen en una computadora, y lo más probable es que se prueben casi siempre en la misma máquina en la que se construyen. Así, la experiencia móvil & el rendimiento de las animaciones suelen quedar de última. Algunas tecnologías (como canvas) o técnicas de animación pueden rendir peor en móviles.
Sin embargo, si está bien programado & optimizado (mira la regla #1), la experiencia móvil puede ser incluso más fluida que en una computadora. Optimizar para móvil fue alguna vez un tema muy complicado, ¡pero los iPhones nuevos hoy son más rápidos que la mayoría de las laptops! Si vienes siguiendo los consejos anteriores, es muy posible que termines con un gran rendimiento móvil sin esfuerzo extra.

El uso móvil va a ser una parte grande e importantísima de casi cualquier sitio. Puede sonar extremo, pero sugiero que lo veas exclusivamente desde tu teléfono durante una semana entera. Que te obliguen a usar la versión móvil no debería sentirse como un castigo, pero muchas veces lo es.
Sigue haciendo mejoras de diseño & de rendimiento hasta que se sienta igual de pulida y cómoda que la versión grande del sitio.
Si te obligas a usar solo tu sitio móvil durante una semana, probablemente termines optimizándolo hasta que sea una experiencia mejor que la grande. ¡Vale la pena la molestia de usarlo a diario si eso significa que los problemas se arreglan antes de que los sufran tus usuarios!
#10
Prueba seguido en varios dispositivos
El tamaño de pantalla, la densidad o el dispositivo pueden tener grandes implicancias
Hay muchos factores además de móvil contra escritorio que pueden afectar mucho el rendimiento, como si la pantalla es “retina” o no, la cantidad total de píxeles de la ventana, qué tan viejo es el hardware, etc.
Aunque Chrome y Safari son navegadores basados en Webkit con sintaxis parecida, cada uno tiene sus propias rarezas. Cada actualización de Chrome puede arreglar cosas e introducir errores nuevos, así que hay que estar siempre atento.
Por supuesto, no quieres construir solo para el mínimo común denominador, así que encontrar formas ingeniosas de agregar o quitar las mejoras de manera progresiva puede ser muy útil.
Yo cambio seguido entre mi MacBook Air chiquita y mi iMac enorme, y cada ciclo revela pequeños problemas y mejoras por hacer, sobre todo en el rendimiento de las animaciones, pero también en el diseño general, la densidad de información, la legibilidad, etc.
Las media queries pueden ser herramientas muy potentes para atender estos distintos segmentos: dar estilos distintos según alto o ancho es el uso típico, pero también sirven para segmentar por densidad de píxeles u otras propiedades. Detectar el sistema operativo y el tipo de dispositivo también puede ser útil, porque el rendimiento en móviles puede ser muy distinto que en computadoras.

Espero que estas técnicas te sirvan en tu próximo proyecto. ¡Suerte!


