Explicación del uso de WebPageTest para identificar y corregir problemas de inestabilidad del diseño.
En una publicación anterior, escribí sobre la medición del cambio de diseño acumulado (CLS) en WebPageTest. El CLS es una agregación de todos los cambios de diseño, por lo que en esta publicación pensé que sería interesante profundizar e inspeccionar cada cambio de diseño individual en una página para tratar de comprender qué podría estar causando la inestabilidad y, en realidad, intentar solucionar los problemas.
Cómo medir los cambios de diseño
Con la API de Layout Instability, podemos obtener una lista de todos los eventos de cambio de diseño en una página:
new Promise(resolve => {
new PerformanceObserver(list => {
resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
}).observe({type: "layout-shift", buffered: true});
}).then(console.log);
Esto produce un array de cambios de diseño que no están precedidos por eventos de entrada:
[
{
"name": "",
"entryType": "layout-shift",
"startTime": 210.78500000294298,
"duration": 0,
"value": 0.0001045969445437389,
"hadRecentInput": false,
"lastInputTime": 0
}
]
En este ejemplo, hubo un solo cambio muy pequeño del 0.01% a los 210 ms.
Conocer el momento y la gravedad del cambio es útil para acotar lo que podría haberlo causado. Regresemos a WebPageTest para obtener un entorno de lab y realizar más pruebas.
Cómo medir los cambios de diseño en WebPageTest
Al igual que con la medición de CLS en WebPageTest, la medición de cambios de diseño individuales requerirá una métrica personalizada. Por suerte, el proceso es más fácil ahora que Chrome 77 es estable. La API de Layout Instability está habilitada de forma predeterminada, por lo que deberías poder ejecutar ese fragmento de JS en cualquier sitio web de Chrome 77 y obtener resultados de inmediato. En WebPageTest, puedes usar el navegador Chrome predeterminado y no tener que preocuparte por las marcas de línea de comandos ni por usar Canary.
Modifiquemos esa secuencia de comandos para producir una métrica personalizada para WebPageTest:
[LayoutShifts]
return new Promise(resolve => {
new PerformanceObserver(list => {
resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
}).observe({type: "layout-shift", buffered: true});
});
La promesa de esta secuencia de comandos se resuelve en una representación JSON del array en lugar del array en sí. Esto se debe a que las métricas personalizadas solo pueden producir tipos de datos primitivos, como cadenas o números.
El sitio web que usaré para la prueba es ismyhostfastyet.com, un sitio que creé para comparar el rendimiento de carga real de los hosts web.
Identifica las causas de la inestabilidad del diseño
En los resultados, podemos ver que la métrica personalizada LayoutShifts tiene este valor:
[
{
"name": "",
"entryType": "layout-shift",
"startTime": 3087.2349999990547,
"duration": 0,
"value": 0.3422101449275362,
"hadRecentInput": false,
"lastInputTime": 0
}
]
En resumen, hay un solo cambio de diseño del 34.2% que se produce a los 3,087 ms. Para ayudar a identificar el culpable, usemos la vista de tira de película de WebPageTest.
Si nos desplazamos hasta la marca de aproximadamente 3 segundos en la tira de película, se nos muestra exactamente cuál es la causa del cambio de diseño del 34%: la tabla colorida. El sitio web recupera de forma asíncrona un archivo JSON y, luego, lo renderiza en una tabla. La tabla está vacía al principio, por lo que esperar a que se llene cuando se carguen los resultados causa el cambio.
Pero eso no es todo. Cuando la página está completa visualmente a los ~4.3 segundos, podemos ver que el <h1>
de la página "¿Mi host ya es rápido?" aparece de la nada. Esto sucede porque el sitio usa una fuente web y no se ha tomado ninguna medida para optimizar la renderización. En realidad, el diseño no parece cambiar cuando esto sucede, pero sigue siendo una experiencia del usuario deficiente tener que esperar tanto tiempo para leer el título.
Cómo corregir la inestabilidad del diseño
Ahora que sabemos que la tabla generada de forma asíncrona hace que se desplace un tercio del viewport, es hora de solucionarlo. No conocemos el contenido de la tabla hasta que se cargan los resultados JSON, pero aún podemos propagar la tabla con algún tipo de datos de marcador de posición para que el diseño sea relativamente estable cuando se renderice el DOM.
Este es el código para generar datos de marcadores de posición:
function getRandomFiller(maxLength) {
var filler = '█';
var len = Math.ceil(Math.random() * maxLength);
return new Array(len).fill(filler).join('');
}
function getRandomDistribution() {
var fast = Math.random();
var avg = (1 - fast) * Math.random();
var slow = 1 - (fast + avg);
return [fast, avg, slow];
}
// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
var [fast, avg, slow] = getRandomDistribution();
window.data.push({
platform: getRandomFiller(10),
client: getRandomFiller(5),
n: getRandomFiller(1),
fast,
avg,
slow
});
}
updateResultsTable(sortResults(window.data, 'fast'));
Los datos de los marcadores de posición se generan de forma aleatoria antes de ordenarse. Incluye el carácter “█” repetido una cantidad aleatoria de veces para crear marcadores de posición visuales para el texto y una distribución generada aleatoriamente de los tres valores principales. También agregué algunos estilos para desaturar todo el color de la tabla y dejar en claro que los datos aún no se cargaron por completo.
La apariencia de los marcadores de posición que uses no es importante para la estabilidad del diseño. El propósito de los marcadores de posición es garantizarles a los usuarios que el contenido está disponible y que la página no está dañada.
Este es el aspecto de los marcadores de posición mientras se cargan los datos JSON:
Abordar el problema de las fuentes web es mucho más sencillo. Como el sitio usa Google Fonts, solo debemos pasar la propiedad display=swap
en la solicitud de CSS. Eso es todo. La API de Fonts agregará el estilo font-display: swap
en la declaración de la fuente, lo que permitirá que el navegador renderice el texto en una fuente de resguardo de inmediato. Este es el lenguaje de marcado correspondiente con la corrección incluida:
<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">
Cómo verificar las optimizaciones
Después de volver a ejecutar la página a través de WebPageTest, podemos generar una comparación antes y después para visualizar la diferencia y medir el nuevo grado de inestabilidad del diseño:
[
{
"name": "",
"entryType": "layout-shift",
"startTime": 3070.9349999997357,
"duration": 0,
"value": 0.000050272187989256116,
"hadRecentInput": false,
"lastInputTime": 0
}
]
Según la métrica personalizada, todavía se produce un cambio de diseño a los 3071 ms (aproximadamente el mismo tiempo que antes), pero la gravedad del cambio es mucho menor: 0.005%. Puedo vivir con esto.
También se ve claramente en la tira de película que la fuente <h1>
recurre inmediatamente a una fuente del sistema, lo que permite que los usuarios la lean antes.
Conclusión
Es probable que los sitios web complejos experimenten muchos más cambios de diseño que en este ejemplo, pero el proceso de solución sigue siendo el mismo: agrega métricas de inestabilidad del diseño a WebPageTest, realiza una verificación cruzada de los resultados con la película de carga visual para identificar los culpables y, luego, implementa una solución con marcadores de posición para reservar el espacio en pantalla.
(Una cosa más) Medición de la inestabilidad del diseño que experimentan los usuarios reales
Es bueno poder ejecutar WebPageTest en una página antes y después de una optimización y ver una mejora en una métrica, pero lo que realmente importa es que la experiencia del usuario mejore. ¿No es por eso que intentamos mejorar el sitio en primer lugar?
Por lo tanto, sería muy útil que comencemos a medir las experiencias de inestabilidad del diseño de los usuarios reales junto con nuestras métricas de rendimiento web tradicionales. Esta es una parte fundamental del ciclo de retroalimentación de la optimización, ya que tener datos del campo nos indica dónde están los problemas y si nuestras correcciones generaron una diferencia positiva.
Además de recopilar tus propios datos de inestabilidad del diseño, consulta el Informe de UX de Chrome, que incluye datos de cambio de diseño acumulativo de experiencias de usuarios reales en millones de sitios web. Te permite saber cómo te desempeñas tú (o tus competidores) o puedes usarlo para explorar el estado de inestabilidad del diseño en la Web.