Hacia una métrica de fluidez de animación

Aprende a medir animaciones, a pensar en los marcos de animación y a la fluidez general de la página.

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

Es probable que hayas visto páginas que se "intermiten" o se "inmovilizan" durante el desplazamiento o las animaciones. Nos gusta decir que estas experiencias no son lisas. Para abordar este tipo de problemas, el equipo de Chrome estuvo trabajando con el objetivo de agregar más compatibilidad con nuestras herramientas del lab para la detección de animaciones y realizar mejoras constantes en los diagnósticos de la canalización de renderización en Chromium.

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

Esta publicación abarcará tres temas principales:

  • Un vistazo rápido a las animaciones y los marcos de animación.
  • Nuestras ideas actuales sobre cómo medir la fluidez general de la animación.
  • Estas son algunas sugerencias prácticas que puedes aprovechar hoy mismo en las herramientas del lab.

¿Qué son las animaciones?

Las animaciones le dan vida al contenido. Al hacer que el contenido se mueva, especialmente 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 el simple hecho de agregar demasiadas animaciones pueden degradar la experiencia y hacer que definitivamente no sea divertida. Probablemente, todos interactuamos con una interfaz que acaba de agregar demasiados efectos de transición "útiles" y que, en realidad, se vuelven hostiles cuando tienen un rendimiento deficiente. Por lo tanto, es posible que algunos usuarios prefieran el movimiento reducido, una preferencia del usuario que debes respetar.

¿Cómo funcionan las animaciones?

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

  1. Estilo: calcula los diseños 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. Composición: Dibuja las capas en la pantalla.

Si bien hay muchas formas de definir animaciones, en esencia, todas funcionan mediante una de las siguientes opciones:

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

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

Si bien animar las propiedades de diseño puede ser conveniente, existen costos para hacerlo, 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 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 medir!

¿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 finalmente se renderiza en la pantalla del usuario.

Muestra actualizaciones 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 (de 90 a 120 Hz son cada vez más comunes). A menudo, estas pantallas pueden adaptarse activamente entre frecuencias 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 en lotes y producir siempre un fotograma de animación visualmente completo dentro del plazo límite. Ten en cuenta que este objetivo es totalmente distinto de otras tareas importantes del navegador, como cargar contenido de la red rápidamente 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 que asigna la pantalla. Cuando esto sucede, el navegador descarta un marco. La pantalla no se pone negra, sino que se repite. Verás la misma actualización visual durante un poco más: el mismo fotograma de animación que se presentó en la oportunidad de fotogramas anterior.

En realidad, esto sucede a menudo. No es necesariamente perceptible, en especial para el contenido estático o similar a documentos, algo que es común en la plataforma web en particular. Los fotogramas descartados solo se hacen evidentes cuando hay actualizaciones visuales importantes, como las animaciones, para las que necesitamos un flujo constante de actualizaciones de animación que muestren un movimiento suave.

¿Qué afecta a los fotogramas de animación?

Los desarrolladores web pueden generar un gran impacto 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
  • Demasiadas capas, lo que requiere demasiada memoria de GPU
  • Definir animaciones web o estilos de CSS demasiado complejos
  • El uso de antipatrones de diseño que inhabiliten las optimizaciones de renderización rápida.
  • 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 plazo y provocó la caída de un fotograma?

Un método posible es usar el sondeo de 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 la función de devolución de llamada en el momento que esperabas, significa que no se ejecutó la pintura y se omitieron uno o más fotogramas. Si sondeas y cuentas con qué frecuencia 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 el sondeo de rAF es rápido, puede impedir que requestIdleCallback() pueda programar bloques inactivos largos cuando se usan de forma continua (bloques que superan un solo fotograma).
  • Del mismo modo, la falta de bloques inactivos prolongados evita que el navegador programe otras tareas prolongadas (como la recolección de elementos no utilizados más larga y otros trabajos en segundo plano o especulativos).
  • Si el sondeo está activado y desactivado, no se considerarán los casos en los que se haya superado el presupuesto de fotogramas.
  • El sondeo informará falsos positivos en los casos en los que el navegador use una frecuencia de actualización variable (por ejemplo, debido al estado de encendido o de visibilidad).
  • Y lo más importante, no captura todos los tipos de actualizaciones de animación.

Demasiado trabajo en el subproceso principal puede afectar la capacidad de ver los fotogramas de animación. Consulta el Ejemplo de bloqueo para ver cómo una animación basada en rAF, una vez que haya demasiado trabajo en el subproceso principal (como el diseño), generará una pérdida de fotogramas, menos devoluciones de llamadas de rAF y menores FPS.

Cuando el subproceso principal se embrolla, las actualizaciones visuales comienzan a entrecortarse. ¡Eso es un bloqueo!

Muchas herramientas de medición se han centrado en gran medida en la capacidad del subproceso principal para generar rendimiento de manera oportuna y lograr que los fotogramas de animación se ejecuten sin problemas. ¡Pero esta no es la historia completa! Consulta el siguiente ejemplo:

En el video anterior, se muestra una página que inserta periódicamente tareas largas en el subproceso principal. Estas tareas largas arruinan por completo la capacidad de la página de proporcionar ciertos tipos de actualizaciones visuales, y puedes ver en la esquina superior izquierda una disminución correspondiente de requestAnimationFrame() informados por FPS 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 a menudo cuenta con un subproceso, controlado por completo por el compositor.

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

En el caso de los marcos de animación, la historia no es tan simple.

Fotogramas de animación: actualizaciones importantes

En el ejemplo anterior, se muestra que la historia no se limita solo a requestAnimationFrame().

¿Cuándo son importantes las actualizaciones y los fotogramas de animación? Estos son algunos criterios que estamos considerando y sobre los que nos encantaría recibir comentarios:

  • Actualizaciones del subproceso principal y del compositor
  • Actualizaciones de pintura faltantes
  • Cómo detectar animaciones
  • Calidad frente a cantidad

Actualizaciones del subproceso principal y del compositor

Las actualizaciones de los marcos de animación no son booleanas. No es el caso que los fotogramas solo se pierdan por completo o se presenten por completo. Existen muchos motivos por los que un fotograma de animación se puede presentar parcialmente . En otras palabras, puede tener contenido inactivo de manera simultánea y, al mismo tiempo, tener algunas actualizaciones visuales nuevas que se presentan.

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

Un motivo importante por el que se recomienda usar animaciones declarativas para animar propiedades compuestas es que, al hacerlo, se permite que el subproceso compositor controle 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 no se cumplan varios plazos de fotogramas. Aquí, el navegador tendrá algunas actualizaciones nuevas, pero es posible que no sean las más recientes.

En términos generales, consideramos los fotogramas que contienen algunas actualizaciones visuales nuevas, sin todas las actualizaciones visuales nuevas, como un marco parcial. Los fotogramas parciales son bastante comunes. Lo ideal sería que las actualizaciones parciales incluyan, al menos, las actualizaciones visuales más importantes, como las animaciones, pero eso solo puede ocurrir si el subproceso compositor controla las animaciones.

Actualizaciones de pintura faltantes

Otro tipo de actualización parcial ocurre cuando el contenido multimedia, como las imágenes, no terminó de decodificar ni de rasterizar a tiempo para la presentación de fotogramas.

O bien, incluso si una página es perfectamente estática, es posible que los navegadores dejen de renderizar las actualizaciones visuales durante el desplazamiento rápido. Esto se debe a que las renderizaciones de píxeles del contenido más allá del viewport visible pueden descartarse para ahorrar memoria de la GPU. La renderización de píxeles tarda en renderizarse y puede tardar más que un solo fotograma en renderizar todo después de un desplazamiento grande, como deslizar el dedo. Esto se conoce comúnmente como checkerboarding.

Con cada oportunidad de renderización de fotogramas, es posible realizar un seguimiento de cuánta de las actualizaciones visuales más recientes llegaron realmente a la pantalla. La medición de la capacidad para hacerlo en muchos fotogramas (o tiempo) se conoce, en términos generales, como capacidad de procesamiento de fotogramas.

Si la GPU está realmente atascada, el navegador (o la plataforma) puede comenzar a limitar la velocidad a la que intenta realizar actualizaciones visuales y, por lo tanto, disminuye la velocidad de fotogramas efectiva. Si bien, técnicamente, eso puede reducir la cantidad de actualizaciones de fotogramas descartadas, visualmente seguirá apareciendo como una capacidad de procesamiento de fotogramas más baja.

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

¿Cuándo es importante la capacidad de procesamiento de fotogramas?

Cómo detectar animaciones

La alta capacidad de procesamiento de fotogramas es importante, sobre todo 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 el subproceso proporcione la actualización dentro del plazo. Se dice que un subproceso determinado afecta la fluidez cada vez que hay una animación activa que depende de esa actualización del subproceso.

Algunos tipos de animaciones son más fáciles de definir y detectar que otros. Las animaciones declarativas o las animaciones basadas en entradas del usuario son más claras para definir que las animaciones basadas en JavaScript que se implementan como actualizaciones periódicas de las propiedades de estilo que se pueden animar.

Incluso con requestAnimationFrame(), no siempre puedes suponer que cada llamada de rAF produce necesariamente una actualización visual o animación. Por ejemplo, el uso del sondeo de rAF solo para realizar 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 actualización visual.

Calidad frente a cantidad

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

Por ejemplo, puedes ver una velocidad de fotogramas constante de 60 FPS mientras miras un video. Técnicamente, funciona con fluidez, pero el video en sí puede tener una tasa de bits baja o problemas con el almacenamiento en búfer de la red. Esto no se captura directamente mediante las métricas de fluidez de animación, pero es posible que moleste al usuario.

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

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

GIF de Old School en construcción

Quiero decir, supongo que fueron geniales para su tiempo.

Estados de un solo fotograma de animación

Debido a que los fotogramas pueden presentarse parcialmente o que los fotogramas se pueden descartar de maneras que no afectan la fluidez, empezamos a pensar que cada fotograma tiene una puntuación de integridad o suavidad.

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

No hay actualizaciones deseadas Tiempo de inactividad, repetición del fotograma anterior.
Presentación completa La actualización del subproceso principal se confirmó dentro del plazo límite, o bien no se deseaba ninguna actualización del subproceso principal.
Parcialmente presentado Solo para el compositor. La actualización retrasada del subproceso principal no tuvo cambios visuales.
Parcialmente presentado Solo para el compositor. El subproceso principal tuvo una actualización visual, pero esa actualización no incluyó una animación que afecte la suavidad.
Parcialmente presentado Solo compositor. El subproceso principal tenía una actualización visual que afecta la fluidez, pero llegó un fotograma antiguo y se usó en su lugar.
Parcialmente presentado Solo para el compositor; sin la actualización principal deseada, la actualización del compositor tiene una animación que afecta la fluidez.
Parcialmente presentado Solo el compositor, pero su actualización no tiene una animación que afecte la fluidez.
Fotograma descartado Sin actualizaciones. No se deseaba actualizar el compositor y se retrasó la instancia principal.
Fotograma descartado Se deseaba actualizar el compositor, pero se retrasó.
Fotograma inactivo Se deseaba una actualización; el procesador la produjo, pero la GPU todavía no la presentó antes de la fecha límite de vsync.

Es posible convertir estos estados en una puntuación. Y tal vez una forma de interpretar esta puntuación es considerarla una probabilidad de que el usuario pueda observarla. Es posible que un solo fotograma descartado no sea muy observable, pero una secuencia de muchos fotogramas descartados que afectan la fluidez en una fila sí lo es.

Revisión general: métrica de porcentaje de fotogramas descartados

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

Debido a que los fotogramas se pueden presentar de forma parcial y las actualizaciones de fotogramas que se omiten por completo pueden no afectar la fluidez, debemos enfocarnos menos en el recuento de fotogramas y más en la extensión en la que el navegador no puede proporcionar actualizaciones visualmente completas en los casos importantes.

El modelo mental debe avanzar de:

  1. fotogramas por segundo hasta
  2. La detección de actualizaciones de animación importantes y faltantes,
  3. Porcentaje disminuido en un período determinado.

Lo importante es la proporción de tiempo de espera de 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, usamos las siguientes métricas como conjunto inicial de métricas:

  • Porcentaje promedio descartado: Para todos los fotogramas de animación no inactivos en todo el cronograma
  • El peor caso de porcentaje de fotogramas descartados: según la medición durante períodos deslizantes de 1 segundo.
  • Percentil 95 del porcentaje de fotogramas descartados: según la medición durante períodos deslizantes de 1 segundo.

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

Pruébalo en las herramientas para desarrolladores.

HUD de rendimiento

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

HUD de rendimiento

Estadísticas de renderización de fotogramas

Habilita las "Estadísticas de renderización de fotogramas" en Herramientas para desarrolladores desde 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 descartadas por completo. Los FPS informados son solo para fotogramas con una presentación completa.

Estadísticas de renderización de fotogramas

Grabaciones del perfil de rendimiento de Frame Viewer en Herramientas para desarrolladores

Hace tiempo que el panel de rendimiento de Herramientas de desarrolladores cuenta con un visualizador de Frames. Sin embargo, estaba un poco desfasada con el funcionamiento real de la canalización de renderización moderna. Se realizaron muchas mejoras recientes, incluso en la versión más reciente de Chrome Canary, que creemos que facilitarán en gran medida los problemas de animación de depuración.

Hoy verás que los fotogramas del visor de fotogramas están mejor alineados con los límites de vsync y tienen un código de color basado en el estado. Todavía no se puede visualizar todos los matices descritos anteriormente, pero planeamos agregar más en un futuro cercano.

Visor de marcos en las Herramientas para desarrolladores de Chrome

Registro de Chrome

Por último, con Registro de Chrome, la herramienta preferida para ahondar en los detalles, puedes capturar un seguimiento de "Renderización de contenido web" a través de la nueva IU de Perfetto (o about:tracing) y analizar en profundidad la canalización de gráficos de Chrome. Puede ser una tarea abrumadora, pero recientemente se agregaron algunas funciones a Chromium para facilitarla. Puedes obtener una descripción general de lo que está disponible en el documento La vida de un marco.

Mediante los eventos de seguimiento, puedes determinar de forma definitiva lo siguiente:

  • Las animaciones que se ejecutan (mediante eventos llamados TrackerValidation)
  • Obtener el cronograma exacto de los fotogramas de animación (mediante 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 (mediante los desgloses de eventos dentro de los eventos PipelineReporter).
  • En el caso de las animaciones basadas en entradas, consulta cuánto tiempo se tarda en obtener una actualización visual (mediante eventos llamados EventLatency).

Generador de informes de canalizaciones de seguimiento de Chrome

Próximos pasos

El objetivo de la iniciativa Métricas web es proporcionar métricas y orientación para crear excelentes experiencias del usuario 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 mejorar la fluidez de la animación.

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

En el futuro, también nos gustaría diseñar APIs que permitan medir el rendimiento de la fluidez de las animaciones para usuarios reales en el campo y en el lab. No te pierdas las novedades.

Comentarios

Nos entusiasman todas las mejoras y las herramientas para desarrolladores recientes que se enviaron en Chrome para medir la fluidez de la animación. Prueba estas herramientas, compara tus animaciones y cuéntanos a dónde te lleva.

Puedes enviar tus comentarios al Grupo de Google de web-vitals-feedback con “[Smoothness Metrics]” en el asunto. ¡Estamos ansiosos por escuchar qué piensas!