Hacia una métrica de fluidez de animación

Obtén información para medir animaciones, cómo pensar en los fotogramas de animación y la fluidez general de la página.

Behdad Bakhshinategh
Behdad Bakhshinategh
Jonathan Ross
Jonathan Ross
Michal Mocny
Michal Mocny

Es probable que hayas experimentado páginas que "tartamudean" o "se bloquean" durante el desplazamiento o las animaciones. Nos gusta decir que estas experiencias no son suaves. A fin de solucionar este tipo de problemas, el equipo de Chrome estuvo trabajando para agregar más compatibilidad con nuestras herramientas de lab para la detección de animaciones, además de realizar mejoras continuas en el diagnóstico de la canalización de renderización en Chromium.

Nos gustaría compartir algunos avances recientes, ofrecer orientación sobre herramientas concretas y discutir ideas para futuras métricas de fluidez de animación. Como siempre, nos encantaría recibir tus comentarios.

En esta publicación, se abordarán tres temas principales:

  • Una vista rápida de las animaciones y los fotogramas de animación.
  • Nuestras ideas actuales sobre la medición de la fluidez general de la animación
  • Estas son algunas sugerencias prácticas para que aproveches las herramientas del lab hoy mismo.

¿Qué son las animaciones?

Las animaciones le dan vida al contenido. Cuando se hace que el contenido se mueva, en especial en respuesta a las interacciones del usuario, las animaciones pueden hacer que una experiencia se sienta más natural, comprensible y divertida.

Sin embargo, las animaciones mal implementadas o la adición de demasiadas animaciones pueden degradar la experiencia y hacer que no sea nada divertida. Es probable que todos hayamos interactuado con una interfaz que solo agregó demasiados efectos de transición “útiles”, que en realidad se vuelven hostiles para la experiencia cuando tienen un rendimiento bajo. Por lo tanto, es posible que algunos usuarios prefieran reducir el movimiento, una preferencia del usuario que debes respetar.

¿Cómo funcionan las animaciones?

En resumen, la canalización de renderización consta de algunas etapas secuenciales:

  1. Estilo: Calcula los estilos que se aplican a los elementos.
  2. Diseño: Genera la geometría y la posición de cada elemento.
  3. Paint: Completa los píxeles de cada elemento en capas.
  4. Compuesto: Dibuja las capas en la pantalla.

Si bien existen muchas formas de definir animaciones, todas funcionan, en esencia, a través de una de las siguientes opciones:

  • Ajustar las propiedades de diseño
  • Ajustar las propiedades de Paint
  • Ajusta las propiedades compuestas.

Debido a que estas etapas son secuenciales, es importante definir animaciones en términos de propiedades que se encuentran más adelante en la canalización. Cuanto antes ocurra la actualización en el proceso, mayores serán los costos y es menos probable que sea fluida. (Consulta Rendimiento de la renderización para obtener más detalles).

Si bien puede ser conveniente animar las propiedades del diseño, hacerlo tiene costos, incluso si esos costos no son evidentes de inmediato. Siempre que sea posible, las animaciones deben definirse en términos de cambios de propiedades compuestas.

Definir animaciones de CSS declarativas o usar animaciones web, y asegurarte de animar las propiedades compuestas es un excelente primer paso para garantizar animaciones fluidas y eficientes. Sin embargo, esto por sí solo no garantiza la fluidez, ya que incluso las animaciones web eficientes tienen límites de rendimiento. Por eso, siempre es importante realizar mediciones.

¿Qué son los fotogramas de animación?

Las actualizaciones en la representación visual de una página tardan en aparecer. Un cambio visual generará un nuevo fotograma de animación, que se renderizará en la pantalla del usuario.

Las pantallas se actualizan en algún intervalo, por lo que las actualizaciones visuales se agrupan en lotes. Muchas pantallas se actualizan en un intervalo de tiempo fijo, por ejemplo, 60 veces por segundo (es decir, 60 Hz). Algunas pantallas más modernas pueden ofrecer frecuencias de actualización más altas (entre 90 y 120 Hz se están volviendo comunes). A menudo, estas pantallas pueden adaptarse de forma activa entre las tasas de actualización según sea necesario o incluso ofrecer velocidades de fotogramas completamente variables.

El objetivo de cualquier aplicación, como un juego o un navegador, es procesar todas estas actualizaciones visuales por lotes y producir un fotograma de animación visualmente completo dentro del plazo límite, cada vez. Ten en cuenta que este objetivo es completamente distinto de otras tareas importantes del navegador, como cargar contenido de la red con rapidez o ejecutar tareas de JavaScript de manera eficiente.

En algún momento, puede ser demasiado difícil completar todas las actualizaciones visuales dentro del plazo asignado por la pantalla. Cuando esto sucede, el navegador salta un fotograma. La pantalla no se pone negra, solo se repite. Verás la misma actualización visual por un poco más de tiempo, el mismo fotograma de animación que se presentó en la oportunidad de fotogramas anterior.

Esto sucede con frecuencia. Ni siquiera es necesariamente perceptible, en especial para el contenido estático o similar a un documento, que es común en la plataforma web en particular. Los fotogramas perdidos solo se hacen evidentes cuando hay actualizaciones visuales importantes, como animaciones, para las que necesitamos un flujo constante de actualizaciones de animación para mostrar un movimiento fluido.

¿Qué factores influyen en los fotogramas de animación?

Los desarrolladores web pueden influir en gran medida en la capacidad de un navegador para renderizar y presentar actualizaciones visuales de forma rápida y eficiente.

Estos son algunos ejemplos:

  • Usar contenido demasiado grande o que requiere muchos recursos para decodificarse rápidamente en el dispositivo de destino
  • Usar demasiadas capas requiere demasiada memoria de GPU.
  • Definir animaciones web o estilos CSS demasiado complejos
  • Usar antipatrones de diseño que inhabilitan las optimizaciones de renderización rápida.
  • Hay demasiado trabajo de JS en el subproceso principal, lo que genera tareas largas que bloquean las actualizaciones visuales.

Pero, ¿cómo puedes saber cuándo un fotograma de animación no cumplió con su fecha límite y causó que se descartara un fotograma?

Un método posible es usar el sondeo requestAnimationFrame(), pero tiene varias desventajas. requestAnimationFrame(), o "rAF", le indica al navegador que deseas realizar una animación y solicita la oportunidad de hacerlo antes de la siguiente etapa de pintura de la canalización de renderización. Si no se llama a tu función de devolución de llamada en el momento en que lo esperas, significa que no se ejecutó una pintura y se omitieron uno o más fotogramas. Si sondeas y cuentas la frecuencia con la que se llama a rAF, puedes calcular una especie de métrica de "fotogramas por segundo" (FPS).

let frameTimes = [];
function pollFramesPerSecond(now) {
  frameTimes = [...frameTimes.filter(t => t > now - 1000), now];
  requestAnimationFrame(pollFramesPerSecond);
  console.log('Frames per second:', frameTimes.length);
}
requestAnimationFrame(pollFramesPerSecond);

Usar el sondeo de requestAnimationFrame() no es una buena idea por varios motivos:

  • Cada secuencia de comandos debe configurar su propio bucle de sondeo.
  • Puede bloquear la ruta crítica.
  • Incluso si la sondeo de rAF es rápida, puede impedir que requestIdleCallback() pueda programar bloques inactivos largos cuando se usan de forma continua (bloques que superan un solo fotograma).
  • De manera similar, la falta de bloques inactivos largos evita que el navegador programe otras tareas de larga duración (como una recolección de basura más larga y otro trabajo en segundo plano o especulativo).
  • Si el sondeo está activado o desactivado, omitirás los casos en los que se haya excedido el presupuesto de fotogramas.
  • El sondeo generará falsos positivos en los casos en que el navegador use una frecuencia de actualización variable (por ejemplo, debido al estado de batería o visibilidad).
  • Lo más importante es que no captura todos los tipos de actualizaciones de animaciones.

Demasiada actividad en el subproceso principal puede afectar la capacidad de ver fotogramas de animación. Consulta el ejemplo de bloqueo para ver cómo una animación impulsada por rAF, una vez que haya demasiado trabajo en el subproceso principal (como el diseño), provocará que se pierdan fotogramas, se reduzcan las devoluciones de llamada de rAF y disminuyan los FPS.

Cuando el subproceso principal se ralentiza, las actualizaciones visuales comienzan a fallar. ¡Eso es muy lento!

Muchas herramientas de medición se enfocaron en gran medida en la capacidad del subproceso principal para generar resultados de manera oportuna y para que los fotogramas de animación se ejecuten sin problemas. Pero esta no es toda la historia. Consulta el siguiente ejemplo:

En el video anterior, se muestra una página que inserta tareas largas de forma periódica en el subproceso principal. Estas tareas largas arruinan por completo la capacidad de la página para proporcionar ciertos tipos de actualizaciones visuales, y puedes ver en la esquina superior izquierda una disminución correspondiente de los FPS informados de requestAnimationFrame() a 0.

Sin embargo, a pesar de estas tareas largas, la página sigue desplazándose sin problemas. Esto se debe a que, en los navegadores modernos, el desplazamiento suele estar en subprocesos, lo que controla por completo el compositor.

Este es un ejemplo que contiene, de forma simultánea, muchos fotogramas perdidos en el subproceso principal, pero aún tiene muchos fotogramas de desplazamiento entregados correctamente en el subproceso del compositor. Una vez que se completa la tarea de larga duración, la actualización de pintura del subproceso principal no tiene ningún cambio visual para ofrecer. La sondeo de rAF sugirió una disminución de fotogramas a 0, pero visualmente, un usuario no podría notar la diferencia.

Para los marcos de animación, la historia no es tan simple.

Marcos de animación: Actualizaciones importantes

El ejemplo anterior muestra que hay más en la historia que solo requestAnimationFrame().

Entonces, ¿cuándo son importantes las actualizaciones de animación y los fotogramas de animación? Estos son algunos criterios que tenemos en mente y sobre los que nos gustaría recibir comentarios:

  • Actualizaciones de subprocesos principales y del compositor
  • Faltan actualizaciones de pintura
  • Cómo detectar animaciones
  • Calidad frente a cantidad

Actualizaciones de subprocesos principales y del compositor

Las actualizaciones de fotogramas de animación no son booleanas. No se trata de que los fotogramas solo se descarten o se presenten por completo. Existen muchos motivos por los que un fotograma de animación puede presentarse parcialmente. En otras palabras, puede tener contenido inactivo y, al mismo tiempo, algunas actualizaciones visuales nuevas que se presentan.

El ejemplo más común es cuando el navegador no puede producir una nueva actualización de subproceso principal dentro del plazo de fotogramas, pero tiene una nueva actualización del subproceso del compositor (como el ejemplo de desplazamiento de subprocesos anterior).

Una razón importante por la que se recomienda usar animaciones declarativas para animar propiedades compuestas es que, de esta manera, el subproceso del compositor puede controlar por completo una animación, incluso cuando el subproceso principal está ocupado. Estos tipos de animaciones pueden seguir produciendo actualizaciones visuales de manera eficiente y en paralelo.

Por otro lado, puede haber casos en los que una actualización del subproceso principal finalmente esté disponible para su presentación, pero solo después de que se hayan omitido varios plazos de marcos. Aquí, el navegador tendrá una actualización nueva, pero es posible que no sea la más reciente.

En términos generales, consideramos que los fotogramas que contienen algunas actualizaciones visuales nuevas, sin todas las actualizaciones visuales nuevas, son fotogramas parciales. Los fotogramas parciales son bastante comunes. Idealmente, las actualizaciones parciales deberían incluir al menos las actualizaciones visuales más importantes, como las animaciones, pero eso solo puede suceder si el subproceso del compositor controla las animaciones.

Faltan actualizaciones de pintura

Otro tipo de actualización parcial es cuando el contenido multimedia, como las imágenes, no termina de decodificarse y rasterizarse a tiempo para la presentación de fotogramas.

O incluso si una página es perfectamente estática, es posible que los navegadores aún no rendericen las actualizaciones visuales durante el desplazamiento rápido. Esto se debe a que los formatos de píxeles del contenido más allá del viewport visible pueden descartarse para ahorrar memoria de la GPU. Se necesita tiempo para renderizar los píxeles y puede tardar más que un solo fotograma en renderizar todo después de un desplazamiento grande, como deslizar el dedo por la pantalla. Esto se conoce comúnmente como escaqueado.

Con cada oportunidad de renderización de fotogramas, es posible realizar un seguimiento de la cantidad de actualizaciones visuales más recientes que realmente llegaron a la pantalla. Medir la capacidad de hacerlo en muchos fotogramas (o tiempo) se conoce como tráfico de fotogramas.

Si la GPU está muy sobrecargada, es posible que el navegador (o la plataforma) incluso comience a regular la velocidad a la que intenta realizar actualizaciones visuales y, por lo tanto, disminuye la velocidad de fotogramas efectiva. Si bien técnicamente esto puede reducir la cantidad de actualizaciones de fotogramas descartadas, visualmente aparecerá como una capacidad de procesamiento de fotogramas menor.

Sin embargo, no todos los tipos de capacidad de procesamiento de trama baja son malos. Si la página está inactiva la mayor parte del tiempo y no hay animaciones activas, una velocidad de fotogramas baja es tan atractiva visualmente como una alta (y puede ahorrar batería).

Entonces, ¿cuándo es importante la capacidad de procesamiento de fotogramas?

Cómo detectar animaciones

La alta capacidad de procesamiento de fotogramas es importante, en especial, durante los períodos con animaciones importantes. Los diferentes tipos de animación dependerán de las actualizaciones visuales de un subproceso específico (principal, compositor o trabajador), por lo que su actualización visual depende de que ese subproceso proporcione la actualización dentro del plazo. Decimos que un subproceso determinado afecta la fluidez cada vez que hay una animación activa que depende de la actualización de ese subproceso.

Algunos tipos de animaciones son más fáciles de definir y detectar que otros. Las animaciones declarativas, o las animaciones controladas por el usuario, son más claras de definir que las animaciones basadas en JavaScript implementadas como actualizaciones periódicas de las propiedades de diseño animadas.

Incluso con requestAnimationFrame(), no siempre puedes suponer que cada llamada de rAF producirá una actualización visual o una animación. Por ejemplo, usar la sondeo de rAF solo para hacer un seguimiento de la velocidad de fotogramas (como se muestra más arriba) no debería afectar las mediciones de fluidez, ya que no hay una actualización visual.

Calidad frente a cantidad

Por último, detectar animaciones y actualizaciones de fotogramas de animación sigue siendo solo parte de la historia, ya que solo captura la cantidad de actualizaciones de animación, no la calidad.

Por ejemplo, es posible que veas una velocidad de fotogramas estable de 60 fps mientras miras un video. Técnicamente, esto es perfectamente fluido, pero el video en sí puede tener una tasa de bits baja o problemas con el almacenamiento en búfer de la red. Las métricas de fluidez de la animación no capturan esto directamente, pero aún pueden ser perturbadoras para el usuario.

O bien, un juego que aprovecha <canvas> (quizás incluso con técnicas como el lienzo fuera de la pantalla para garantizar una velocidad de fotogramas constante) puede ser técnicamente perfectamente fluido en términos de fotogramas de animación, a la vez que no carga recursos de juego de alta calidad en la escena ni muestra artefactos de renderización.

Y, por supuesto, un sitio puede tener animaciones realmente malas 🙂

GIF de la vieja escuela en construcción

Quiero decir, supongo que eran bastante buenas para su época.

Estados de un solo fotograma de animación

Debido a que los fotogramas se pueden presentar de forma parcial o que los fotogramas descartados pueden ocurrir de maneras que no afectan la fluidez, comenzamos a pensar que cada fotograma tiene una puntuación de integridad o fluidez.

A continuación, se muestra el espectro de las maneras en las que interpretamos el estado de un único fotograma de animación, ordenados del mejor al peor de los casos:

No se desea realizar ninguna actualización Tiempo inactivo, repetición del fotograma anterior.
Se debe presentar de forma completa La actualización del subproceso principal se confirmó dentro del plazo o no se deseó ninguna actualización del subproceso principal.
Presentación parcial Solo el compositor. La actualización retrasada del subproceso principal no tuvo cambios visuales.
Presentación parcial Solo compositor: El subproceso principal tuvo una actualización visual, pero esa actualización no incluyó una animación que afecte la fluidez.
Presentación parcial Solo el compositor. El subproceso principal tenía una actualización visual que afecta la suavidad, pero llegó un fotograma anteriormente inactivo y se usó en su lugar.
Presentación parcial Solo el compositor; sin la actualización principal deseada, y la actualización del compositor tiene una animación que afecta la fluidez.
Presentación parcial Solo en el compositor, pero la actualización del compositor no tiene una animación que afecte la fluidez.
Fotograma perdido Sin actualizaciones. No se deseaba una actualización del compositor, y se retrasó el elemento principal.
Fotograma perdido Se deseaba una actualización del compositor, pero se retrasó.
Fotograma inactivo Se deseaba una actualización, que el renderizador produjo, pero la GPU aún no la presentaba antes de la fecha límite de vsync.

Es posible convertir estos estados en una especie de puntuación. Y quizás una forma de interpretar esta puntuación es considerarla una probabilidad de que el usuario la observe. Un solo fotograma descartado puede no ser muy observable, pero una secuencia de muchos fotogramas descartados que afecta la fluidez en una fila sí lo es.

Cómo combinar todo: una métrica de porcentaje de fotogramas perdidos

Si bien, a veces, puede ser necesario profundizar en el estado de cada fotograma de animación, también es útil asignar una puntuación rápida "de un vistazo" para una experiencia.

Debido a que los fotogramas pueden presentarse de forma parcial y a que incluso las actualizaciones de fotogramas omitidas por completo pueden no afectar la fluidez, queremos enfocarnos menos en solo contar fotogramas y más en la medida en que el navegador no puede proporcionar actualizaciones completas visualmente cuando es importante.

El modelo mental debe pasar de lo siguiente:

  1. Fotogramas por segundo, hasta
  2. Detectar actualizaciones de animación faltantes e importantes para
  3. Porcentaje de usuarios que abandonaron durante un período determinado.

Lo que importa es la proporción de tiempo que se espera por actualizaciones importantes. Creemos que esto coincide con la forma natural en que los usuarios experimentan la fluidez del contenido web en la práctica. Hasta ahora, hemos estado usando lo siguiente como un conjunto inicial de métricas:

  • Porcentaje promedio de fotogramas perdidos: Para todos los fotogramas de animación que no están inactivos en toda la línea de tiempo
  • Peor caso de porcentaje de fotogramas perdidos: Se mide en ventanas deslizantes de 1 segundo.
  • Percentil 95 del porcentaje de fotogramas perdidos: Se mide en ventanas deslizantes de 1 segundo.

Actualmente, puedes encontrar estas puntuaciones en algunas herramientas para desarrolladores de Chrome. Si bien estas métricas se enfocan solo en la capacidad de procesamiento general de fotogramas, también evaluamos otros factores, como la latencia de fotogramas.

Pruébala tú mismo en las herramientas para desarrolladores.

HUD de rendimiento

Chromium tiene un HUD de rendimiento prolijo oculto detrás de una marca (chrome://flags/#show-performance-metrics-hud). En él, puedes encontrar puntuaciones en vivo de elementos como las Métricas web esenciales y también algunas definiciones experimentales para la fluidez de la animación según el Porcentaje de fotogramas descartados a lo largo del tiempo.

HUD de rendimiento

Estadísticas de renderización de fotogramas

Habilita "Frame Rendering Stats" en DevTools a través de la configuración de renderización para ver una vista en vivo de los nuevos fotogramas de animación, que están codificados por colores para diferenciar las actualizaciones parciales de las actualizaciones de fotogramas que se descartaron por completo. Los FPS informados son solo para los fotogramas presentados por completo.

Estadísticas de renderización de fotogramas

Visualizador de fotogramas en las grabaciones de perfiles de rendimiento de DevTools

El panel Rendimiento de DevTools tiene desde hace mucho tiempo un Visor de marcos. Sin embargo, se había desincronizado un poco con el funcionamiento real de la canalización de renderización moderna. Se realizaron muchas mejoras recientemente, incluso en la versión más reciente de Chrome Canary, que creemos que facilitará mucho la depuración de problemas de animación.

Hoy verás que los fotogramas en el visor de fotogramas están mejor alineados con los límites de vsync y se codifican por colores según el estado. Aún no hay una visualización completa de todos los matices descritos anteriormente, pero planeamos agregar más en un futuro cercano.

Visor de fotogramas en Herramientas para desarrolladores de Chrome

Registro de Chrome

Por último, con Chrome Tracing, la herramienta elegida para profundizar en los detalles, puedes registrar un seguimiento de "Renderización de contenido web" a través de la nueva IU de Perfetto (o about:tracing) y profundizar en la canalización de gráficos de Chrome. Puede ser una tarea abrumadora, pero se agregaron algunos elementos recientemente a Chromium para facilitarla. Puedes obtener una descripción general de lo que está disponible en el documento Life of a Frame.

A través de los eventos de seguimiento, puedes determinar de forma definitiva lo siguiente:

  • Qué animaciones se están ejecutando (con eventos denominados TrackerValidation)
  • Obtener el cronograma exacto de los fotogramas de animación (con eventos llamados PipelineReporter)
  • Para las actualizaciones de animación con bloqueos, averigua exactamente qué impide que la animación se ejecute más rápido (usa los desgloses de eventos dentro de los eventos PipelineReporter).
  • En el caso de las animaciones impulsadas por entradas, consulta cuánto tiempo tarda en obtenerse una actualización visual (con eventos llamados EventLatency).

Generador de informes de canalización de seguimiento de Chrome

¿Qué sigue?

El objetivo de la iniciativa Métricas web es proporcionar métricas y orientación para crear experiencias del usuario excelentes en la Web. Las métricas basadas en labs, como el tiempo de bloqueo total (TBT), son fundamentales para detectar y diagnosticar posibles problemas de interactividad. Planeamos diseñar una métrica similar basada en labs para lograr una animación fluida.

Te mantendremos al tanto a medida que sigamos trabajando en ideas para diseñar una métrica integral basada en datos de fotogramas de animación individuales.

En el futuro, también nos gustaría diseñar APIs que permitan medir la fluidez de la animación de manera eficiente para usuarios reales en el campo y en el laboratorio. No te pierdas las novedades allí.

Comentarios

Nos entusiasman todas las mejoras y herramientas para desarrolladores recientes que se enviaron en Chrome para medir la fluidez de la animación. Prueba estas herramientas, realiza comparativas de tus animaciones y danos tu opinión al respecto.

Puedes enviar tus comentarios al grupo de Google web-vitals-feedback con "[Métricas de fluidez]" en el asunto. Esperamos con ansias tu opinión.