Obtén información para optimizar la métrica Interacción a la siguiente pintura de tu sitio web.
La interacción a la siguiente pintura (INP) es una métrica de métricas web esenciales estable que evalúa la capacidad de respuesta general de una página ante las interacciones del usuario mediante la observación de la latencia de todas las interacciones que califican que se producen durante la visita del usuario a una página. El valor final de la INP es la interacción más larga observada (a veces, se ignoran los valores atípicos).
Para proporcionar una buena experiencia del usuario, los sitios web deben esforzarse por tener una Interaction to Next Paint de 200 milisegundos o menos. Para asegurarte de alcanzar este objetivo para la mayoría de los usuarios, un buen umbral para medir es el percentil 75 de las cargas de páginas, segmentadas entre los dispositivos móviles y las computadoras de escritorio.
Según el sitio web, es posible que haya pocas interacciones o ninguna, como páginas de imágenes y texto en su mayoría, con pocos elementos interactivos o sin ellos. O bien, en el caso de los sitios web, como editores de texto o juegos, podría haber cientos o incluso miles de interacciones. En cualquier caso, cuando hay un INP alto, la experiencia del usuario está en riesgo.
Mejorar el INP requiere tiempo y esfuerzo, pero la recompensa es una mejor experiencia del usuario. En esta guía, se explorará una ruta para mejorar la INP.
Determina qué está causando una INP deficiente
Antes de corregir las interacciones lentas, necesitarás datos que te indiquen si el INP de tu sitio web es bajo o necesita mejorarse. Una vez que tengas esa información, puedes ir al laboratorio para comenzar a diagnosticar las interacciones lentas y avanzar hacia una solución.
Cómo encontrar interacciones lentas en el campo
Lo ideal es que tu recorrido para optimizar la INP comience con los datos de campo. En el mejor de los casos, los datos de campo de un proveedor de supervisión de usuarios reales (RUM) te brindarán no solo el valor de INP de una página, sino también datos contextuales que destaquen qué interacción específica fue responsable del valor de INP en sí, si la interacción ocurrió durante o después de la carga de la página, el tipo de interacción (clic, presión de tecla o presión) y otra información valiosa.
Si no dependes de un proveedor de RUM para obtener datos de campo, la guía de datos de campo de INP recomienda usar el Informe sobre la experiencia del usuario en Chrome (CrUX) a través de PageSpeed Insights para ayudar a llenar los vacíos. CrUX es el conjunto de datos oficial del programa Métricas web esenciales y proporciona un resumen de alto nivel de las métricas de millones de sitios web, incluida la INP. Sin embargo, CrUX a menudo no proporciona los datos contextuales que obtendrías de un proveedor de RUM para ayudarte a analizar los problemas. Por este motivo, recomendamos que los sitios usen un proveedor de RUM siempre que sea posible o implementen su propia solución de RUM para complementar lo que está disponible en CrUX.
Cómo diagnosticar interacciones lentas en el lab
Lo ideal es que comiences a realizar pruebas en el laboratorio una vez que tengas datos de campo que sugieran que tienes interacciones lentas. En ausencia de datos de campo, existen algunas estrategias para identificar interacciones lentas en el lab. Estas estrategias incluyen seguir flujos de usuarios comunes y probar interacciones a lo largo del camino, así como interactuar con la página durante la carga (cuando el subproceso principal suele estar más ocupado) para mostrar interacciones lentas durante esa parte crucial de la experiencia del usuario.
Optimiza las interacciones
Una vez que hayas identificado una interacción lenta y puedas reproducirla de forma manual en el lab, el siguiente paso es optimizarla. Las interacciones se pueden dividir en tres fases:
- El retraso de entrada, que comienza cuando el usuario inicia una interacción con la página y finaliza cuando comienzan a ejecutarse las devoluciones de llamada de eventos para la interacción.
- La duración del procesamiento, que consiste en el tiempo que tardan las devoluciones de llamada de eventos en ejecutarse hasta completarse.
- La demora de presentación, que es el tiempo que tarda el navegador en presentar el siguiente fotograma que contiene el resultado visual de la interacción.
La suma de estas tres fases es la latencia de interacción total. Cada fase de una interacción contribuye con una cantidad de tiempo a la latencia total de la interacción, por lo que es importante saber cómo puedes optimizar cada parte de la interacción para que se ejecute durante el menor tiempo posible.
Identifica y reduce el retraso de entrada
Cuando un usuario interactúa con una página, la primera parte de esa interacción es el retraso de entrada. Según la otra actividad en la página, las demoras de entrada pueden ser considerables. Esto puede deberse a la actividad que se produce en el subproceso principal (quizás debido a la carga, el análisis y la compilación de secuencias de comandos), el manejo de recuperación, las funciones del temporizador o incluso a otras interacciones que se producen en rápida sucesión y se superponen entre sí.
Independientemente de la fuente de la demora de entrada de una interacción, te recomendamos que reduzcas la demora de entrada al mínimo para que las interacciones puedan comenzar a ejecutar devoluciones de llamada de eventos lo antes posible.
La relación entre la evaluación de secuencias de comandos y las tareas largas durante el inicio
Un aspecto fundamental de la interactividad en el ciclo de vida de la página es durante el inicio. A medida que se carga una página, se renderiza inicialmente, pero es importante recordar que el hecho de que una página se haya renderizado no significa que se haya terminado de cargar. Según la cantidad de recursos que requiera una página para funcionar por completo, es posible que los usuarios intenten interactuar con ella mientras aún se está cargando.
Una cosa que puede extender la demora de entrada de una interacción mientras se carga una página es la evaluación de secuencias de comandos. Después de que se recupera un archivo JavaScript de la red, el navegador aún tiene trabajo por hacer antes de que se pueda ejecutar. Ese trabajo incluye analizar una secuencia de comandos para garantizar que su sintaxis sea válida, compilarla en código intermedio y, por último, ejecutarla.
Según el tamaño de una secuencia de comandos, este trabajo puede introducir tareas largas en el subproceso principal, lo que retrasará la respuesta del navegador a otras interacciones del usuario. Para que tu página responda a las entradas del usuario durante la carga, es importante comprender qué puedes hacer para reducir la probabilidad de que se realicen tareas largas durante la carga de la página, de modo que esta siga siendo ágil.
Optimiza las devoluciones de llamada de eventos
El retraso de entrada es solo la primera parte de lo que mide la INP. También deberás asegurarte de que las devoluciones de llamada de eventos que se ejecutan en respuesta a una interacción del usuario se puedan completar lo más rápido posible.
Ceder el subproceso principal con frecuencia
El mejor consejo general para optimizar las devoluciones de llamada de eventos es hacer el menor trabajo posible en ellas. Sin embargo, es posible que tu lógica de interacción sea compleja y que solo puedas reducir marginalmente el trabajo que realizan.
Si crees que este es el caso de tu sitio web, lo siguiente que puedes intentar es dividir el trabajo en devoluciones de llamada de eventos en tareas independientes. Esto evita que el trabajo colectivo se convierta en una tarea larga que bloquee el subproceso principal, lo que permite que otras interacciones que, de otro modo, estarían esperando en el subproceso principal se ejecuten antes.
setTimeout
es una forma de dividir tareas, ya que la devolución de llamada que se le pasa se ejecuta en una tarea nueva. Puedes usar setTimeout
por sí solo o abstraer su uso en una función independiente para obtener resultados más ergonómicos.
Ceder de forma indiscriminada es mejor que no ceder en absoluto. Sin embargo, hay una forma más matizada de ceder al subproceso principal, que implica ceder solo inmediatamente después de una devolución de llamada de evento que actualiza la interfaz de usuario para que la lógica de renderización pueda ejecutarse antes.
Rendimiento para permitir que el trabajo de renderización se realice antes
Una técnica de renderización más avanzada implica estructurar el código en tus devoluciones de llamada de eventos para limitar lo que se ejecuta solo a la lógica necesaria para aplicar actualizaciones visuales para el siguiente fotograma. Todo lo demás se puede aplazar para una tarea posterior. Esto no solo mantiene las devoluciones de llamada ligeras y ágiles, sino que también mejora el tiempo de renderización de las interacciones, ya que no permite que las actualizaciones visuales se bloqueen en el código de devolución de llamada del evento.
Por ejemplo, imagina un editor de texto enriquecido que aplica formato al texto a medida que escribes, pero que también actualiza otros aspectos de la IU en respuesta a lo que escribiste (como el recuento de palabras, la identificación de errores ortográficos y otros comentarios visuales importantes). Además, es posible que la aplicación también deba guardar lo que escribiste para que, si sales y vuelves, no pierdas tu trabajo.
En este ejemplo, deben ocurrir los siguientes cuatro eventos en respuesta a los caracteres que escribe el usuario. Sin embargo, solo se debe completar el primer elemento antes de que se presente el siguiente fotograma.
- Actualiza el cuadro de texto con lo que el usuario escribió y aplica el formato necesario.
- Actualiza la parte de la IU que muestra el recuento de palabras actual.
- Ejecuta la lógica para comprobar si hay errores ortográficos.
- Guarda los cambios más recientes (ya sea de forma local o en una base de datos remota).
El código para hacer esto podría verse de la siguiente manera:
textBox.addEventListener('input', (inputEvent) => {
// Update the UI immediately, so the changes the user made
// are visible as soon as the next frame is presented.
updateTextBox(inputEvent);
// Use `setTimeout` to defer all other work until at least the next
// frame by queuing a task in a `requestAnimationFrame()` callback.
requestAnimationFrame(() => {
setTimeout(() => {
const text = textBox.textContent;
updateWordCount(text);
checkSpelling(text);
saveChanges(text);
}, 0);
});
});
En la siguiente visualización, se muestra cómo aplazar las actualizaciones no críticas hasta después del siguiente fotograma puede reducir la duración del procesamiento y, por lo tanto, la latencia de interacción general.
Si bien el uso de setTimeout()
dentro de una llamada a requestAnimationFrame()
en el ejemplo de código anterior es un poco esotérico, es un método eficaz que funciona en todos los navegadores para garantizar que el código no crítico no bloquee el siguiente fotograma.
Evita la hiperpaginación del diseño
La paginación excesiva de diseños, a veces llamada diseño sincrónico forzado, es un problema de rendimiento de renderización en el que el diseño se produce de forma síncrona. Ocurre cuando actualizas los estilos en JavaScript y, luego, los lees en la misma tarea. Además, hay muchas propiedades en JavaScript que pueden causar un aumento repentino del diseño.
La paginación excesiva de diseños es un cuello de botella de rendimiento porque, cuando se actualizan los estilos y, luego, se solicitan inmediatamente los valores de esos estilos en JavaScript, el navegador se ve obligado a realizar un trabajo de diseño síncrono que, de otro modo, podría haber esperado para realizar de forma asíncrona más adelante, después de que se hayan terminado de ejecutar las devoluciones de llamada de eventos.
Minimiza el retraso de la presentación
El retraso de presentación de una interacción abarca desde el momento en que terminan de ejecutarse las devoluciones de llamada de eventos de una interacción hasta el punto en el que el navegador puede pintar el siguiente fotograma que muestra los cambios visuales resultantes.
Minimiza el tamaño del DOM
Cuando el DOM de una página es pequeño, el trabajo de renderización suele terminar rápidamente. Sin embargo, cuando los DOM se vuelven muy grandes, el trabajo de renderización tiende a escalar con el aumento del tamaño del DOM. La relación entre el trabajo de renderización y el tamaño del DOM no es lineal, pero los DOM grandes requieren más trabajo para renderizarse que los DOM pequeños. Un DOM grande es problemático en dos casos:
- Durante la renderización inicial de la página, en la que un DOM grande requiere mucho trabajo para renderizar el estado inicial de la página.
- En respuesta a una interacción del usuario, en la que un DOM grande puede hacer que las actualizaciones de renderización sean muy costosas y, por lo tanto, aumente el tiempo que tarda el navegador en presentar el siguiente fotograma.
Ten en cuenta que hay instancias en las que los DOM grandes no se pueden reducir de forma significativa. Si bien existen enfoques que puedes adoptar para reducir el tamaño del DOM, como aplanar el DOM o agregar elementos al DOM durante las interacciones del usuario para mantener el tamaño inicial del DOM pequeño, esas técnicas pueden ser limitadas.
Usa content-visibility
para renderizar de forma diferida elementos fuera de la pantalla
Una forma de limitar la cantidad de trabajo de renderización durante la carga de la página y en respuesta a las interacciones del usuario es recurrir a la propiedad content-visibility
de CSS, que equivale a renderizar elementos de forma diferida a medida que se acercan al viewport. Si bien content-visibility
puede requerir práctica para usarlo de manera eficaz, vale la pena investigar si el resultado es un tiempo de renderización más bajo que puede mejorar el INP de tu página.
Ten en cuenta los costos de rendimiento cuando renderices HTML con JavaScript
Donde hay HTML, hay análisis de HTML, y después de que el navegador termina de analizar el HTML en un DOM, debe aplicarle estilos, realizar cálculos de diseño y, posteriormente, renderizar ese diseño. Este es un costo inevitable, pero cómo renderizas el HTML es importante.
Cuando el servidor envía HTML, llega al navegador como una transmisión continua. La transmisión significa que la respuesta HTML del servidor llega en fragmentos. El navegador optimiza la forma en que controla una transmisión a través del análisis incremental de fragmentos de esa transmisión a medida que llegan y su renderización bit a bit. Esta es una optimización del rendimiento en la que el navegador cede de forma implícita y automática durante la carga de la página, y lo obtienes de forma gratuita.
Si bien la primera visita a cualquier sitio web siempre implicará alguna cantidad de HTML, un enfoque común comienza con un fragmento inicial mínimo de HTML y, luego, se usa JavaScript para propagar el área de contenido. Las actualizaciones posteriores de ese área de contenido también se producen como resultado de las interacciones del usuario. Por lo general, se lo denomina modelo de aplicación de una sola página (SPA). Una desventaja de este patrón es que, cuando se renderiza HTML con JavaScript en el cliente, no solo se obtiene el costo del procesamiento de JavaScript para crear ese HTML, sino que el navegador no se entrega hasta que termina de analizar ese HTML y renderizarlo.
Sin embargo, es fundamental recordar que, incluso los sitios web que no son SPA probablemente involucren cierta cantidad de renderización de HTML a través de JavaScript como resultado de las interacciones. Por lo general, esto está bien, siempre y cuando no renderices grandes cantidades de HTML en el cliente, lo que puede retrasar la presentación del siguiente fotograma. Sin embargo, es importante comprender las implicaciones de rendimiento de este enfoque para renderizar HTML en el navegador y cómo puede afectar la capacidad de respuesta de tu sitio web a las entradas del usuario si renderizas mucho HTML a través de JavaScript.
Conclusión
Mejorar el INP de tu sitio es un proceso iterativo. Cuando corriges una interacción lenta en el campo, es probable que, en especial si tu sitio web proporciona mucha interactividad, comiences a encontrar otras interacciones lentas y también debas optimizarlas.
La clave para mejorar la INP es la persistencia. Con el tiempo, puedes lograr que la capacidad de respuesta de tu página sea tal que los usuarios estén conformes con la experiencia que les brindas. Es probable que, a medida que desarrolles nuevas funciones para tus usuarios, debas seguir el mismo proceso para optimizar las interacciones específicas para ellos. Esto llevará tiempo y esfuerzo, pero valdrá la pena.
Imagen hero de Unsplash, de David Pisnoy y modificada de acuerdo con la licencia de Unsplash.