Obtén información para medir las animaciones, cómo pensar en los fotogramas de animación y la fluidez general de la página.
Probablemente hayas experimentado páginas que "se traban" o "se congelan" 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 ha estado trabajando en agregar más compatibilidad a nuestras herramientas de laboratorio para la detección de animaciones, así como en realizar mejoras constantes en los diagnósticos de la canalización de renderización dentro de Chromium.
Queremos compartir algunos avances recientes, ofrecer orientación concreta sobre herramientas y analizar ideas para futuras métricas de fluidez de la animación. Como siempre, nos encantaría recibir tus comentarios.
En esta publicación, se abordarán tres temas principales:
- Un vistazo rápido a las animaciones y los fotogramas de animación.
- Nuestras ideas actuales sobre cómo medir la fluidez general de la animación.
- Algunas sugerencias prácticas para que aproveches las herramientas de lab hoy mismo.
¿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 la simple adición de demasiadas animaciones pueden degradar la experiencia y hacer que no sea divertida en absoluto. Probablemente todos interactuamos con una interfaz que agregó demasiados efectos de transición "útiles", que en realidad se vuelven hostiles para la experiencia cuando tienen un rendimiento deficiente. Por lo tanto, es posible que algunos usuarios prefieran la opción de 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:
- Estilo: Calcula los estilos que se aplican a los elementos.
- Diseño: Genera la geometría y la posición de cada elemento.
- Pintar: Rellena los píxeles de cada elemento en capas.
- Composite: Dibuja las capas en la pantalla.
Si bien hay muchas formas de definir animaciones, todas funcionan fundamentalmente a través de uno de los siguientes métodos:
- Ajustar las propiedades de diseño
- Ajustar las propiedades de pintura
- Ajusta las propiedades de composite.
Dado que estas etapas son secuenciales, es importante definir las animaciones en términos de propiedades que se encuentran más abajo en la canalización. Cuanto antes se realice la actualización en el proceso, mayores serán los costos y menos probable será que se realice sin problemas. (Consulta Rendimiento de la renderización para obtener más detalles).
Si bien puede ser conveniente animar las propiedades de diseño, esto tiene un costo, incluso si no es evidente de inmediato. Siempre que sea posible, las animaciones deben definirse en términos de cambios de propiedades compuestos.
Definir animaciones CSS declarativas o usar Web Animations, y garantizar que animes propiedades compuestas, es un excelente primer paso para garantizar animaciones fluidas y eficientes. Pero, aun así, 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 marcos 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, finalmente, 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 (90 a 120 Hz son cada vez más comunes). A menudo, estas pantallas pueden adaptarse de forma activa entre las frecuencias de actualización según sea necesario o, incluso, ofrecer frecuencias de actualización 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 rápidamente o ejecutar tareas de JavaScript de manera eficiente.
En algún momento, puede resultar demasiado difícil completar todas las actualizaciones visuales dentro del plazo asignado por la pantalla. Cuando esto sucede, el navegador descarta un fotograma. La pantalla no se pone negra, sino que se repite. Verás la misma actualización visual durante un poco más de tiempo, el mismo fotograma de animación que se presentó en la oportunidad del fotograma anterior.
Esto sucede a menudo. No necesariamente es 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 descartados 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 afectan 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 demasiados 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
- 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ó un fotograma descartado?
Un método posible es usar el sondeo de requestAnimationFrame()
, pero tiene varios inconvenientes. requestAnimationFrame()
, o "rAF", le indica al navegador que deseas realizar una animación y solicita una oportunidad para hacerlo antes de la siguiente etapa de pintura de la canalización de renderización. Si tu función de devolución de llamada no se llama en el momento esperado, significa que no se ejecutó una pintura y se omitieron uno o más fotogramas. Al sondear y contar 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 el sondeo de rAF es rápido, puede impedir que
requestIdleCallback()
pueda programar bloques inactivos largos cuando se usa de forma continua (bloques que superan un solo fotograma). - Del mismo modo, la falta de bloques inactivos largos impide que el navegador programe otras tareas de larga duración (como la recolección de basura más prolongada y otros trabajos especulativos o en segundo plano).
- Si la votación se activa y desactiva, te perderás los casos en los que se excedió 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 energía o visibilidad).
- Y, lo que es 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 fotogramas de animación. Consulta el ejemplo de Jank para ver cómo una animación controlada por rAF, una vez que hay demasiado trabajo en el subproceso principal (como el diseño), generará fotogramas descartados y menos devoluciones de llamada de rAF, y un menor FPS.
Cuando el subproceso principal se ralentiza, las actualizaciones visuales comienzan a trabarse. ¡Eso es jank!
Muchas herramientas de medición se han enfocado en gran medida en la capacidad del subproceso principal para ceder de manera oportuna y para que los fotogramas de animación se ejecuten sin problemas. Pero esa no es toda la historia. Consulta el siguiente ejemplo:
En el video anterior, se muestra una página que inyecta 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.
Y, 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 ser multiproceso y está controlado por completo por el compositor.
Este es un ejemplo que contiene simultáneamente muchos fotogramas descartados en el subproceso principal, pero que también tiene muchos fotogramas de desplazamiento entregados correctamente en el subproceso del compositor. Una vez que se completa la tarea larga, la actualización de pintura del subproceso principal no tiene ningún cambio visual que ofrecer. El sondeo de rAF sugirió una caída 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 la historia es más que solo requestAnimationFrame()
.
Entonces, ¿cuándo son importantes las actualizaciones y los fotogramas de animación? Estos son algunos criterios que estamos considerando y sobre los que nos gustaría recibir comentarios:
- Actualizaciones de los subprocesos principal y de composición
- Faltan actualizaciones de pintura
- Cómo detectar animaciones
- Calidad frente a cantidad
Actualizaciones de los subprocesos principal y de composición
Las actualizaciones de los 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 de forma parcial. En otras palabras, puede tener contenido desactualizado 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 sí tiene una nueva actualización del subproceso del compositor (como el ejemplo de desplazamiento con subprocesos de antes).
Una razón importante por la que se recomienda usar animaciones declarativas para animar propiedades compuestas es que esto permite que una animación se ejecute por completo en el subproceso del compositor, 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 no cumplir con 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, pero no todas, son fotogramas parciales. Los fotogramas parciales son bastante comunes. Lo ideal sería que las actualizaciones parciales incluyeran, 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 se produce cuando el contenido multimedia, como las imágenes, no termina de decodificarse y rasterizarse a tiempo para la presentación del fotograma.
O bien, incluso si una página es perfectamente estática, es posible que los navegadores se retrasen en la renderización de las actualizaciones visuales durante el desplazamiento rápido. Esto se debe a que las representaciones de píxeles del contenido más allá del viewport visible se pueden descartar para ahorrar memoria de la GPU. Renderizar píxeles lleva tiempo y puede tardar más de un fotograma renderizar todo después de un desplazamiento grande, como un deslizamiento con el dedo. Esto se conoce comúnmente como checkerboarding.
Con cada oportunidad de renderizar un fotograma, es posible hacer un seguimiento de cuántas de las actualizaciones visuales más recientes llegaron a la pantalla. La medición de la capacidad para hacerlo en muchos fotogramas (o durante un período) se conoce ampliamente como rendimiento de fotogramas.
Si la GPU está muy 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 velocidades de fotogramas efectivas. Si bien técnicamente esto puede reducir la cantidad de actualizaciones de fotogramas descartados, visualmente seguirá apareciendo como un rendimiento de fotogramas más bajo.
Sin embargo, no todos los tipos de rendimiento bajo de fotogramas son malos. Si la página está mayormente inactiva y no hay animaciones activas, una velocidad de fotogramas baja es tan atractiva visualmente como una velocidad de fotogramas 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 un trabajador), por lo que su actualización visual dependerá de que ese subproceso proporcione su actualización dentro de la fecha límite. Decimos que un subproceso determinado afecta la fluidez cuando 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 animaciones controladas por la entrada del usuario, son más claras de definir que las animaciones controladas por JavaScript que se implementan como actualizaciones periódicas de propiedades de diseño animables.
Incluso con requestAnimationFrame()
, no siempre puedes suponer que cada llamada a rAF produce necesariamente una actualización visual o una animación. Por ejemplo, usar el 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 actualizaciones visuales.
Calidad frente a cantidad
Por último, detectar animaciones y actualizaciones de fotogramas 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, es posible que veas una velocidad de fotogramas constante de 60 FPS mientras miras un video. Técnicamente, esto es perfectamente fluido, pero es posible que el video en sí tenga una tasa de bits baja o problemas con el almacenamiento en búfer de la red. Esto no se capta directamente con las métricas de fluidez de la animación, pero puede ser molesto para el usuario.
O bien, un juego que aprovecha <canvas>
(quizás incluso usando técnicas como canvas fuera de pantalla para garantizar una velocidad de fotogramas constante) puede ser técnicamente perfecto en términos de fotogramas de animación, pero no cargar recursos de alta calidad en la escena o mostrar artefactos de renderización.
Y, por supuesto, un sitio puede tener animaciones muy malas 🙂
Quiero decir, supongo que eran bastante geniales para su época.
Estados de un solo fotograma de animación
Dado que los fotogramas pueden presentarse de forma parcial o pueden omitirse de maneras que no afectan la fluidez, comenzamos a pensar que cada fotograma tiene una puntuación de integridad o fluidez.
Este es el espectro de formas en que interpretamos el estado de un solo fotograma de animación, ordenado de mejor a peor caso:
No se desea ninguna actualización | Tiempo de inactividad, 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. |
Se presentó de forma parcial | Solo el compositor; la actualización retrasada del subproceso principal no tuvo ningún cambio visual. |
Se presentó de forma parcial | Solo el compositor: El subproceso principal tuvo una actualización visual, pero esa actualización no incluyó una animación que afecte la fluidez. |
Se presentó de forma parcial | Solo el compositor: El subproceso principal tuvo una actualización visual que afecta la fluidez, pero llegó un fotograma previamente inactivo y se usó en su lugar. |
Se presentó de forma parcial | Solo el compositor; sin la actualización principal deseada, y la actualización del compositor tiene una animación que afecta la fluidez. |
Se presentó de forma parcial | Solo el compositor, pero la actualización del compositor no tiene una animación que afecte la fluidez. |
Fotograma perdido | Sin actualización. No se deseaba ninguna actualización del compositor, y se retrasó la rama principal. |
Fotograma perdido | Se deseaba una actualización del compositor, pero se retrasó. |
Fotograma inactivo | Se deseaba una actualización, el renderizador la produjo, pero la GPU aún no la presentó antes de la fecha límite de la sincronización vertical. |
Es posible convertir estos estados en una especie de puntuación. Y, tal vez, una forma de interpretar esta puntuación es considerarla una probabilidad de ser observable por el usuario. Es posible que un solo fotograma descartado no sea muy observable, pero una secuencia de muchos fotogramas descartados que afectan la fluidez sí lo es.
Cómo combinar todo: una métrica de porcentaje de fotogramas descartados
Si bien a veces puede ser necesario analizar en detalle el estado de cada fotograma de la animación, también es útil asignar una puntuación rápida "de un vistazo" a una experiencia.
Dado que los fotogramas pueden presentarse parcialmente y que incluso las actualizaciones de fotogramas que se omiten por completo pueden no afectar la fluidez, queremos enfocarnos menos en solo contar fotogramas y más en el grado en que el navegador no puede proporcionar actualizaciones visualmente completas cuando era importante.
El modelo mental debería pasar de lo siguiente:
- Fotogramas por segundo, a
- Detectar actualizaciones de animación importantes y faltantes
- Porcentaje de abandonos durante un período determinado
Lo que importa es la proporción del tiempo que se espera para recibir 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:
- Porcentaje promedio de fotogramas descartados: Para todos los fotogramas de animación que no están inactivos a lo largo de toda la línea de tiempo
- Peor caso de porcentaje de fotogramas descartados: Se mide en ventanas deslizantes de 1 segundo.
- Percentil 95 del porcentaje de fotogramas descartados: Según se mide en ventanas deslizantes de tiempo de 1 segundo.
Actualmente, puedes encontrar estas puntuaciones en algunas herramientas para desarrolladores de Chrome. Si bien estas métricas se enfocan solo en el rendimiento general de los fotogramas, también estamos evaluando otros factores, como la latencia de los fotogramas.
¡Pruébalo 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 tiempo real para elementos como las Métricas web esenciales y también algunas definiciones experimentales para la fluidez de la animación basadas en el porcentaje de fotogramas descartados a lo largo del tiempo.
Estadísticas de renderización de fotogramas
Habilita "Estadísticas de renderización de fotogramas" en Herramientas para desarrolladores a través de la configuración de Renderización para ver una vista en vivo de los nuevos fotogramas de animación, que se codifican por color para diferenciar las actualizaciones parciales de las actualizaciones de fotogramas completamente descartados. El FPS registrado es solo para los fotogramas completamente presentados.
Visualizador de fotogramas en las grabaciones del perfil de rendimiento de Herramientas para desarrolladores
El panel Rendimiento de Herramientas para desarrolladores siempre tuvo un visualizador de fotogramas. Sin embargo, se había desincronizado un poco con el funcionamiento real de la canalización de renderización moderna. Hubo muchas mejoras recientes, incluso en la versión más reciente de Chrome Canary, que creemos que facilitará en gran medida 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 la sincronización vertical y codificados por colores según el estado. Aún no se visualizan por completo todos los detalles mencionados anteriormente, pero planeamos agregar más en el futuro cercano.
Registro de Chrome
Por último, con Chrome Tracing, la herramienta ideal 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 analizar en detalle la canalización de gráficos de Chrome. Puede ser una tarea desalentadora, pero recientemente se agregaron algunas funciones a Chromium para facilitarla. Puedes obtener una descripción general de lo que está disponible en el documento Ciclo de vida de un fotograma.
A través de los eventos de registro, puedes determinar de forma definitiva lo siguiente:
- Qué animaciones se están ejecutando (con eventos llamados
TrackerValidation
) - Obtener la línea de tiempo exacta de los fotogramas de animación (con eventos llamados
PipelineReporter
) - En el caso de las actualizaciones de animación con interrupciones, descubre exactamente qué impide que la animación se ejecute más rápido (con los desgloses de eventos dentro de los eventos
PipelineReporter
). - En el caso de las animaciones controladas por entrada, consulta cuánto tiempo lleva obtener una actualización visual (con eventos llamados
EventLatency
).
¿Qué sigue?
La iniciativa de las Métricas web tiene como objetivo proporcionar métricas y orientación para crear excelentes experiencias del usuario en la Web. Las métricas basadas en el lab, como el Total Blocking Time (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 los datos de los 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 los usuarios reales en el campo y en el laboratorio. No te pierdas las novedades.
Comentarios
Nos entusiasman todas las mejoras recientes y las herramientas para desarrolladores que se lanzaron en Chrome para medir la fluidez de las animaciones. Prueba estas herramientas, compara tus animaciones y cuéntanos qué tal te va.
Puedes enviar tus comentarios al grupo de Google web-vitals-feedback con "[Métricas de fluidez]" en la línea de asunto. Esperamos con ansias conocer tu opinión.