Obtén información para medir animaciones, cómo pensar en los fotogramas de animación y la fluidez general de la página.
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 fluidas. Para abordar este tipo de problemas, el equipo de Chrome trabajó para agregar más compatibilidad a nuestras herramientas de lab para la detección de animaciones, además de realizar mejoras constantes en los diagnósticos del canal de renderización en Chromium.
Nos gustaría compartir algunos avances recientes, ofrecer orientación sobre herramientas concretas y analizar 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?
A modo de resumen, la canalización de renderización contiene algunas etapas secuenciales:
- Estilo: Calcula los estilos que se aplican a los elementos.
- Diseño: Genera la geometría y la posición de cada elemento.
- Pintura: Completa los píxeles de cada elemento en capas.
- 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
- Ajusta las propiedades de pintura.
- Ajusta las propiedades compuestas.
Dado que estas etapas son secuenciales, es importante definir las animaciones en términos de propiedades que están más abajo en la canalización. Cuanto antes se realice la actualización en el proceso, mayores serán los costos y es menos probable que sea fluida. (consulta Rendimiento de la representación para obtener más información).
Si bien puede ser conveniente animar las propiedades de diseño, hacerlo tiene costos, incluso si esos costos no son evidentes de inmediato. Las animaciones deben definirse en términos de cambios de propiedades compuestas siempre que sea posible.
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 realizar mediciones.
¿Qué son los fotogramas de animación?
Las actualizaciones de 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.
Muestra la actualización en algún intervalo, por lo que las actualizaciones visuales se agrupan. Muchas pantallas se actualizan en un intervalo de tiempo fijo, como 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, 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é afecta a 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 patrones de diseño antipatrón que inhabiliten 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 le solicita una oportunidad para 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);
No es recomendable usar el sondeo de requestAnimationFrame()
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 se activa y desactiva la sondeo, se perderán los casos en los que se haya excedido el presupuesto de fotogramas.
- El sondeo informará falsos positivos en los casos en que el navegador use una frecuencia de actualización variable (por ejemplo, debido al estado de la batería o la visibilidad).
- Y, lo más importante, no captura todos los tipos de actualizaciones de animación.
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á la pérdida de fotogramas, menos devoluciones de llamada de rAF y FPS más bajos.
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.
En el caso de los fotogramas de animación, la historia no es tan simple.
Fotogramas 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 es el caso de que los fotogramas solo se puedan descartar o presentar 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 de esto es cuando el navegador no puede producir una nueva actualización del subproceso principal dentro del plazo del fotograma, 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 la presentación, pero solo después de perder varios plazos de fotogramas. Aquí, el navegador tendrá alguna 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 ocurre cuando los elementos multimedia, como las imágenes, no terminan de decodificarse ni 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 las renderizaciones de píxeles del contenido más allá de la ventana de visualización visible se pueden descartar para ahorrar memoria de la GPU. La renderización de píxeles lleva tiempo y puede tardar más que un solo fotograma en renderizar todo después de un desplazamiento grande, como un deslizamiento del dedo. Esto se conoce comúnmente como tablero de ajedrez.
Con cada oportunidad de renderización de fotogramas, es posible hacer un seguimiento de cuánto de las actualizaciones visuales más recientes llegó a la pantalla. Medir la capacidad de hacerlo en muchos fotogramas (o tiempo) se conoce como tráfico de fotogramas.
Si la GPU está realmente sobrecargada, es posible que el navegador (o la plataforma) incluso comience a limitar la velocidad a la que intenta realizar actualizaciones visuales y, por lo tanto, disminuya las tasas de fotogramas efectivas. Si bien, técnicamente, eso puede reducir la cantidad de actualizaciones de fotogramas perdidas, visualmente, seguirá apareciendo como una menor capacidad de procesamiento de fotogramas.
Sin embargo, no todos los tipos de rendimiento de fotogramas bajo son negativos. 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 importa 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 su actualización dentro de la fecha límite. 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 impulsadas por entradas del usuario, son más claras de definir que las animaciones impulsadas por JavaScript implementadas como actualizaciones periódicas de propiedades de estilo animables.
Incluso con requestAnimationFrame()
, no siempre puedes suponer que cada llamada a rAF produce necesariamente una actualización o animación visual. Por ejemplo, usar la sondeo de rAF solo para hacer un seguimiento de la velocidad de fotogramas (como se muestra 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 o muestra artefactos de renderización.
Y, por supuesto, un sitio puede tener animaciones realmente malas 🙂
Quiero decir, supongo que eran bastante buenas para su época.
Estados de un solo fotograma de animación
Debido a que los fotogramas pueden presentarse de forma parcial o pueden caer de formas que no afectan la fluidez, comenzamos a pensar que cada fotograma tiene una puntuación de finalización o fluidez.
Este es el espectro de formas en las que interpretamos el estado de un solo fotograma de animación, ordenado del mejor al peor caso:
No se desea realizar ninguna actualización | Tiempo inactivo, repetición del fotograma anterior. |
Presentación completa | La actualización del subproceso principal se confirmó dentro del plazo o no se deseaba ninguna actualización del subproceso principal. |
Presentación parcial | Solo 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 compositor: El subproceso principal tuvo una actualización visual que afecta la fluidez, pero llegó un fotograma inactivo y se usó en su lugar. |
Presentación parcial | Solo 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. Es posible que un solo fotograma perdido no sea muy observable, pero una secuencia de muchos fotogramas perdidos que afectan 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 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:
- Fotogramas por segundo, para
- Detecta actualizaciones de animación importantes y faltantes para lo siguiente:
- 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 ordenado oculto detrás de una marca (chrome://flags/#show-performance-metrics-hud
). En él, puedes encontrar puntuaciones en vivo para elementos como las Métricas web esenciales y algunas definiciones experimentales para la fluidez de la animación en función del porcentaje de fotogramas perdidos a lo largo del tiempo.
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 completamente presentados.
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 fotogramas. 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 del visor de fotogramas están mejor alineados con los límites de vsync y codificados 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.
Registro de Chrome
Por último, con el seguimiento de Chrome, la herramienta de preferencia para profundizar en los detalles, puedes grabar un registro 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
).
¿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 el lab para la fluidez de la animación.
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.