Optimizar animaciones

La propiedad will-change y otros consejos


Las transiciones y animaciones CSS son un mecanismo super potente para crear animaciones fluidas de forma sencilla en nuestras páginas. Sin embargo, es probable que realizándolas, de repente descubras que no funcionan como esperabas o que al navegador le cuesta moverlas de forma suave y fluida.

Dependiendo del código escrito (y otros factores) puede que nuestras animaciones sean costosas para el navegador y no se vean lo bien que esperamos. Vamos a repasar una serie de consejos que mejorarán el rendimiento de nuestras animaciones.

Usa propiedades eficientes

Al interpretar código CSS, los navegadores pasan por varias fases:

Browser render performance Si haces cambios en una fase, todas las fases de la derecha deben revisarse

  • 1️⃣ Javascript: Esta fase se activa cuando Javascript está realizando tareas visuales que, aunque se podrían hacer con CSS, se están realizando con Javascript.
  • 2️⃣ Styles: En esta fase, se revisan los selectores y se analiza que reglas CSS se aplican a que elementos del documento HTML.
  • 3️⃣ Layout: Esta fase calcula los tamaños, posiciones y dimensiones que los elementos ocupan en una página. Además, el cambio de un elemento puede afectar a otros como hermanos o hijos.
  • 4️⃣ Paint: Es el proceso de renderización en varias capas, relacionado con colores, imágenes, bordes, sombras, textos, etc...
  • 5️⃣ Composite: La composición es la fase donde se organizan o reordenan las diferentes capas para mostrar visualmente de la forma correcta.

No todas las propiedades CSS afectan a la misma fase. Ciertas propiedades CSS como transform, opacity, z-index o cursor, sólo repercuten en la fase de Composite, por lo que son muy eficientes.

Otras propiedades como color, background, outline, border-radius, box-shadow (u otras) afectan a la fase Paint, la cuál luego necesita revisar la fase Composite, por lo que serán algo más costosas.

Propiedades como width, height, margin, padding, display, font-size, text-align (u otras) son de las propiedades CSS más costosas, ya que causan un reflow (proceso en el que cambia la geometría) y hay que recalcular esta fase de layout, la fase de pintado y la fase de composición.

A la hora de animar estas propiedades, es importante analizar si es posible darle prioridad o buscar formas alternativas de hacer animaciones mediante las propiedades menos costosas.

La propiedad will-change

Una propiedad poco conocida es will-change. Se trata de una propiedad CSS mediante la cuál podemos avisar al navegador de que se va a producir una animación y necesitaremos que optimice y se anticipe a cambios en ciertas propiedades. De esta forma, puede estar preparado con antelación y realizar la animación de forma muy eficiente.

.element {
  animation: animate-shadow 5s linear;
  will-change: box-shadow;
}

En este ejemplo, vamos a realizar una animación con sombras, algo que puede ser costoso en términos de eficiencia. Con la propiedad will-change avisamos al navegador que la propiedad box-shadow debe ser optimizada anticipadamente, para que cuando necesite realizar la animación, lo haga de forma ágil y rápido.

Hay que tener mucho cuidado y utilizar esta propiedad sabiamente. En general, los navegadores ya optimizan estos casos correctamente, por lo que normalmente no deberías necesitar utilizarla. Sólo en casos muy concretos donde el rendimiento te suponga un problema notable, deberías utilizarla. Si es posible, lo ideal sería añadirla en situaciones concretas y eliminarla cuando no haga falta.

Evita usar all en las transiciones

Cuando realizamos transiciones en nuestro código CSS, muchas veces solemos indicar el valor all para expresar que queremos transicionar todas las propiedades del elemento:

.element:hover {
  background: #485;
  opacity: 25%;
  width: 200px;
  border: 2px solid black;
  transition: all 1s linear;
}

En este caso, la transición se va a aplicar en todas las propiedades que cambien del elemento. Sin embargo, si solo queremos una transición suave en propiedades como background y opacity, en lugar de utilizar el valor all, podemos separar por comas e indicar las propiedades específicas:

.element:hover {
  background: #485;
  opacity: 25%;
  width: 200px;
  border: 2px solid black;
  transition:
    background 0.5s,
    opacity 1s;
}

Esto siempre será mucho más eficiente. Además, reducir los tiempos de las transiciones y las animaciones, puede ser mucho más interesante, ya que tiempos muy altos puede producir efectos de saltos o estancamiento en la transición o animación.

Utiliza prefers-reduced-motion

Existe una preferencia de usuario llamada prefers-reduced-motion donde indicamos el código CSS que se debe ejecutar si el usuario ha indicado en su sistema o dispositivo que no quiere que se utilicen animaciones, ya porque le resultan molestas o porque necesita desactivarlas por motivos de accesibilidad:

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

En este caso, hemos eliminado las transiciones sobre el elemento .element.

Evita usar Javascript

Evita siempre que puedas animar con Javascript, ya que realizar animaciones con CSS es mucho más eficiente y adecuado.

En algunas situaciones puede ser recomendable hacerlo con Javascript, si es el caso, dale preferencia a mecanismos como Web Animations, que utiliza animaciones CSS mediante una API nativa de Javascript, e intentar evitar el uso de librerías de terceros, que requieren más tiempo y recursos.

También intenta evitar el uso de mecanismos como setTimeout o setInterval, y utiliza requestAnimationFrame, que es mucho más eficiente a la hora de procesar animaciones con Javascript cuando trabajamos con <canvas>, por ejemplo.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev