Correggere l'instabilità del layout

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

In un post precedente ho scritto di misurare il 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.

Misurare le variazioni del layout

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

Viene generato un array di variazioni del layout che non sono 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 unico spostamento molto piccolo dello 0,01% a 210 ms.

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

Misurare le variazioni di layout in WebPageTest

Analogamente alla misurazione del CLS in WebPageTest, la misurazione delle singole variazioni di layout richiede una metrica personalizzata. Fortunatamente, la procedura è 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 immediati. In WebPageTest puoi utilizzare il browser Chrome predefinito e non devi 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

Nei risultati 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 identificare il problema, utilizziamo la visualizzazione a strisce di WebPageTest.

Due celle nella striscia di film, che mostrano screenshot prima e dopo lo spostamento del layout.
Due celle nella sequenza, che mostrano screenshot prima e dopo lo spostamento del layout.

Se scorriamo fino al segno di circa 3 secondi nella striscia, vediamo esattamente la causa dello spostamento del layout del 34%: la tabella colorata. Il sito web recupera in modo asincrono un file JSON, quindi lo visualizza in una tabella. La tabella è inizialmente vuota, quindi l'attesa per riempirla quando i risultati vengono caricati causa lo spostamento.

Intestazione del carattere web che appare dal nulla.
Intestazione del carattere web che appare dal nulla.

Ma non solo. Quando la pagina è visivamente completa a circa 4,3 secondi, possiamo vedere che il <h1> della pagina "Is my host fast yet?" appare dal nulla. Ciò accade perché il sito utilizza un carattere web e non ha adottato misure per ottimizzare il rendering. Il layout non sembra spostarsi quando si verifica questo problema, ma l'esperienza utente è comunque negativa se si deve attendere così a lungo per leggere il titolo.

Correzione dell'instabilità del layout

Ora che sappiamo che la tabella generata in modo asincrono causa lo spostamento di un terzo della finestra, è il momento di risolvere il problema. Non conosciamo i contenuti della tabella finché i risultati JSON non vengono caricati, ma possiamo comunque compilare la tabella con una sorta di dati segnaposto in modo che il layout sia relativamente stabile durante il rendering del DOM.

Ecco il codice per generare 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 casuale di volte 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 indicare chiaramente che i dati non sono ancora stati caricati completamente.

L'aspetto dei segnaposto che utilizzi non influisce sulla stabilità del layout. Lo scopo dei segnaposto è assicurare agli utenti che i contenuti arriveranno e che la pagina non è danneggiata.

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

La tabella dei 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 nella dichiarazione del carattere, consentendo al browser di eseguire il rendering del testo in un carattere di riserva immediatamente. Ecco il markup corrispondente con la correzione inclusa:

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

Verificare le ottimizzazioni

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

La striscia di WebPageTest mostra il caricamento dei due siti uno accanto all&#39;altro con e senza ottimizzazioni del layout.
La striscia di pellicola di WebPageTest mostra il caricamento di entrambi i siti affiancati 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, si verifica ancora uno spostamento del layout a 3071 ms (circa lo stesso tempo di prima), ma la gravità dello spostamento è molto inferiore: 0,005%. Posso conviverci.

Dalla striscia del filmato si evince 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ù spostamenti del layout rispetto a questo esempio, ma la procedura di correzione è sempre la stessa: aggiungi le metriche di instabilità del layout a WebPageTest, confronta i risultati con la striscia di 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 migliori effettivamente. Non è questo il motivo per cui stiamo cercando di migliorare il sito?

Sarebbe fantastico se iniziassimo a misurare le esperienze di instabilità del layout degli utenti reali insieme alle nostre tradizionali metriche sul rendimento web. Si tratta di un elemento fondamentale del ciclo di feedback sull'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 Chrome UX Report, che include i dati sul Cumulative Layout Shift relativi all'esperienza utente reale su milioni di siti web. Ti consente di scoprire il tuo rendimento (o quello dei tuoi concorrenti) oppure puoi utilizzarlo per esplorare lo stato dell'instabilità del layout sul web.