Correggere l'instabilità del layout

Una procedura dettagliata sull'utilizzo di WebPageTest per identificare e risolvere i problemi di instabilità del layout.

In un post precedente ho parlato della misurazione del Cumulative Layout Shift (CLS) in WebPageTest. Il CLS è un'aggregazione di tutte le variazioni di layout, quindi in questo post ho pensato che sarebbe stato interessante approfondire e ispezionare ogni singola variazione di layout in una pagina per cercare di capire cosa potrebbe causare l'instabilità e provare a risolvere i problemi.

Utilizzando l'API Layout Instability, possiamo ottenere un elenco di tutti gli eventi di variazione del layout in una pagina:

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

Questo produce un array di variazioni del layout non precedute da eventi di input:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

In questo esempio si è verificato un singolo spostamento molto piccolo dello 0,01% a 210 ms.

Conoscere l'ora e la gravità del cambiamento è utile per restringere il campo delle possibili cause. Torniamo a WebPageTest per un ambiente di laboratorio per eseguire altri test.

Misurazione delle variazioni del layout in WebPageTest

Analogamente alla misurazione del CLS in WebPageTest, la misurazione dei singoli cambiamenti di layout richiede una metrica personalizzata. Fortunatamente, il processo è più semplice ora che Chrome 77 è stabile. L'API Layout Instability è attiva per impostazione predefinita, quindi dovresti essere in grado di eseguire lo snippet JS su qualsiasi sito web in Chrome 77 e ottenere risultati immediatamente. In WebPageTest, puoi utilizzare il browser Chrome predefinito e non preoccuparti dei flag della riga di comando o dell'utilizzo di Canary.

Modifichiamo quindi lo script per produrre una metrica personalizzata per 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 promessa in questo script si risolve in una rappresentazione JSON dell'array anziché nell'array stesso. Questo perché le metriche personalizzate possono produrre solo tipi di dati primitivi come stringhe o numeri.

Il sito web che utilizzerò per il test è ismyhostfastyet.com, un sito che ho creato per confrontare le prestazioni di caricamento reali degli host web.

Identificazione delle cause dell'instabilità del layout

In results possiamo vedere che la metrica personalizzata LayoutShifts ha questo valore:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

In sintesi, si verifica una singola variazione di layout del 34,2% a 3087 ms. Per aiutarti a identificare il colpevole, utilizziamo la visualizzazione sequenziale di WebPageTest.

Due celle nella sequenza di immagini che mostrano gli screenshot prima e dopo il cambiamento del layout.
Due celle nella sequenza che mostrano gli screenshot prima e dopo il cambiamento del layout.

Se scorri fino al segno di circa 3 secondi nella sequenza di immagini, vedrai esattamente qual è la causa del cambiamento del layout del 34%: la tabella colorata. Il sito web recupera in modo asincrono un file JSON, quindi lo esegue in una tabella. La tabella inizialmente è vuota, quindi attendere di riempirla quando vengono caricati i risultati causa il cambiamento.

Intestazione carattere web che appare dal nulla.
Intestazione del carattere web visualizzata all'improvviso.

Ma non solo. Quando la pagina è visivamente completata dopo circa 4,3 secondi, possiamo vedere che il <h1> della pagina "Il mio host è già veloce?" appare dal nulla. Questo accade perché il sito utilizza un carattere web e non è stato adottato alcun provvedimento per ottimizzare il rendering. In realtà, il layout non sembra cambiare quando si verifica questo problema, ma è comunque un'esperienza utente negativa dover attendere così a lungo per leggere il titolo.

Correggere l'instabilità del layout

Ora che sappiamo che la tabella generata in modo asincrono causa lo spostamento di un terzo dell'area visibile, è il momento di correggerla. Non conosciamo i contenuti della tabella finché i risultati JSON non vengono effettivamente caricati, ma possiamo comunque compilarla con una sorta di dati segnaposto in modo che il layout stesso sia relativamente stabile quando viene visualizzato il DOM.

Ecco il codice per generare i dati segnaposto:

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'));

I dati segnaposto vengono generati in modo casuale prima di essere ordinati. Include il carattere "█" ripetuto un numero di volte casuale per creare segnaposto visivi per il testo e una distribuzione generata in modo casuale dei tre valori principali. Ho anche aggiunto alcuni stili per desaturare tutti i colori della tabella per chiarire che i dati non sono ancora stati caricati completamente.

L'aspetto dei segnaposto che utilizzi non è importante per la stabilità del layout. Lo scopo dei segnaposto è rassicurare gli utenti che i contenuti sono in arrivo e che la pagina non è rotta.

Ecco l'aspetto dei segnaposto durante il caricamento dei dati JSON:

La tabella di dati viene visualizzata con dati segnaposto.
La tabella di dati viene visualizzata con dati segnaposto.

Risolvere il problema dei caratteri web è molto più semplice. Poiché il sito utilizza Google Fonts, dobbiamo solo passare la proprietà display=swap nella richiesta CSS. È tutto. L'API Fonts aggiungerà lo stile font-display: swap alla dichiarazione del carattere, consentendo al browser di visualizzare immediatamente il testo in un carattere di riserva. Ecco il markup corrispondente con la correzione inclusa:

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

Verifica delle ottimizzazioni

Dopo aver eseguito nuovamente la pagina tramite WebPageTest, possiamo generare un confronto prima e dopo per visualizzare la differenza e misurare il nuovo grado di instabilità del layout:

Pellicola WebPageTest che mostra entrambi i siti che vengono caricati affiancati con e senza ottimizzazioni del layout.
Filmato di WebPageTest che mostra il caricamento affiancato di entrambi i siti con e senza ottimizzazioni del layout.
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

Secondo la metrica personalizzata, esiste ancora una variazione del layout che si verifica a 3071 ms (più o meno nello stesso momento di prima), ma la gravità della variazione è molto inferiore: 0,005%. Posso accontentarmi di così.

Dalla sequenza risulta evidente anche che il carattere <h1> torna immediatamente a un carattere di sistema, consentendo agli utenti di leggerlo prima.

Conclusione

I siti web complessi probabilmente subiranno molti più cambiamenti di layout rispetto a questo esempio, ma la procedura di correzione rimane la stessa: aggiungi le metriche relative all'instabilità del layout a WebPageTest, esegui il confronto incrociato dei risultati con la sequenza di immagini del caricamento visivo per identificare i responsabili e implementa una correzione utilizzando i segnaposto per riservare lo spazio sullo schermo.

(Un'altra cosa) Misurazione dell'instabilità del layout riscontrata dagli utenti reali

È bello poter eseguire WebPageTest su una pagina prima e dopo un'ottimizzazione e vedere un miglioramento di una metrica, ma ciò che conta davvero è che l'esperienza utente stia effettivamente migliorando. Non è per questo che stiamo cercando di migliorare il sito?

Sarebbe quindi fantastico iniziare a misurare le esperienze di instabilità del layout degli utenti reali insieme alle nostre metriche tradizionali sulle prestazioni web. Si tratta di un elemento fondamentale del ciclo di feedback di ottimizzazione perché i dati sul campo ci indicano dove si trovano i problemi e se le nostre correzioni hanno fatto la differenza.

Oltre a raccogliere i tuoi dati sull'instabilità del layout, consulta il Report sull'esperienza utente di Chrome, che include i dati relativi allo spostamento cumulativo del layout delle esperienze utente reali su milioni di siti web. Ti consente di scoprire il tuo rendimento o quello dei tuoi concorrenti oppure puoi utilizzarlo per esaminare lo stato di instabilità del layout sul web.