Evita layout complessi e di grandi dimensioni e thrapping di layout

Il layout è la fase in cui il browser calcola le informazioni geometriche degli elementi, ovvero le loro dimensioni e la loro posizione nella pagina. Ogni elemento avrà informazioni sulle dimensioni esplicite o implicite in base al CSS utilizzato, ai contenuti dell'elemento o a un elemento principale. Questa procedura è chiamata Layout in Chrome.

Il layout è la fase in cui il browser calcola le informazioni geometriche degli elementi: le loro dimensioni e la loro posizione nella pagina. Ogni elemento avrà informazioni sulle dimensioni esplicite o implicite in base al CSS utilizzato, ai contenuti dell'elemento o a un elemento principale. Il processo è denominato Layout in Chrome (e nei browser derivati come Edge) e Safari. In Firefox si chiama Reflow, ma in realtà il processo è lo stesso.

Analogamente ai calcoli degli stili, i problemi immediati relativi ai costi del layout sono:

  1. Il numero di elementi che richiedono il layout, un sottoprodotto delle dimensioni del DOM della pagina.
  2. La complessità di questi layout.

Riepilogo

  • Il layout ha un effetto diretto sulla latenza dell'interazione
  • Il layout è in genere limitato all'intero documento.
  • Il numero di elementi DOM inciderà sulle prestazioni; se possibile, evita di attivare il layout.
  • Evita layout sincroni forzati e il thrashing del layout; leggi i valori degli stili e poi apporta modifiche allo stile.

Effetti del layout sulla latenza dell'interazione

Quando un utente interagisce con la pagina, le interazioni devono essere il più rapide possibili. Il tempo necessario per il completamento di un'interazione, ovvero quando il browser presenta il frame successivo per mostrare i risultati dell'interazione, è noto come latenza di interazione. Questo è un aspetto del rendimento della pagina misurato dalla metrica Interazione con il colore successivo.

Il tempo impiegato dal browser per presentare il frame successivo in risposta a un'interazione dell'utente è noto come ritardo nella presentazione dell'interazione. L'obiettivo di un'interazione è fornire un feedback visivo per segnalare all'utente che si è verificato qualcosa e gli aggiornamenti visivi possono comportare una certa quantità di lavoro di layout per raggiungere questo obiettivo.

Per ridurre il più possibile il valore INP del sito web, è importante evitare il layout, se possibile. Se non è possibile evitare del tutto il layout, è importante limitare il lavoro di layout in modo che il browser possa presentare rapidamente il frame successivo.

Se possibile, evita il layout

Quando modifichi gli stili, il browser controlla se una delle modifiche richiede il calcolo del layout e l'aggiornamento dell'albero di rendering. Le modifiche alle "proprietà geometriche", come larghezze, altezze, a sinistra o in alto, richiedono tutte un layout.

.box {
  width: 20px;
  height: 20px;
}

/**
  * Changing width and height
  * triggers layout.
  */

.box--expanded {
  width: 200px;
  height: 350px;
}

Il layout ha quasi sempre l'ambito dell'intero documento. Se hai molti elementi, capire dove si trovano tutti gli elementi e le loro dimensioni potrebbe richiedere molto tempo.

Se non è possibile evitare il layout, è fondamentale usare nuovamente Chrome DevTools per verificare quanto tempo richiede e determinare se il layout è la causa di un collo di bottiglia. Per prima cosa, apri DevTools, vai alla scheda Spostamenti, premi Registra e interagisci con il tuo sito. Quando interrompi la registrazione, viene visualizzata un'analisi dettagliata del rendimento del sito:

DevTools che mostra molto tempo in Layout.

Se analizziamo la traccia dell'esempio precedente, notiamo che per ogni frame vengono spesi oltre 28 millisecondi all'interno del layout, che, quando abbiamo 16 millisecondi per visualizzare un frame sullo schermo in un'animazione, è troppo alto. Puoi anche vedere che DevTools indica la dimensione della struttura (in questo caso 1618 elementi) e il numero di nodi che hanno bisogno di un layout (in questo caso 5).

Tieni presente che il consiglio generale in questo caso è di evitare l'utilizzo del layout quando è possibile, ma non sempre è possibile evitarlo. Nei casi in cui non è possibile evitare il layout, tieni presente che il costo del layout è correlato alle dimensioni del DOM. Sebbene la relazione tra i due non sia strettamente accoppiata, i DOM più grandi in genere comportano costi di layout più elevati.

Evita layout sincroni forzati

La spedizione di un frame sullo schermo ha questo ordine:

Utilizzo di Flexbox come layout.

Prima viene eseguito JavaScript, poi i calcoli di stile, quindi il layout. Tuttavia, è possibile forzare un browser a eseguire il layout prima con JavaScript. Questo è chiamato layout sincrono forzato.

La prima cosa da tenere a mente è che, poiché il codice JavaScript esegue, tutti i vecchi valori di layout del frame precedente sono noti e disponibili per l'esecuzione di query. Ad esempio, se vuoi scrivere l'altezza di un elemento (chiamiamolo "scatola") all'inizio del frame, puoi scrivere il codice seguente:

// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Se hai modificato gli stili della casella prima di richiederne l'altezza, si possono verificare dei problemi:

function logBoxHeight () {
  box.classList.add('super-big');

  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Per rispondere alla domanda sull'altezza, il browser deve prima applicare la modifica di stile (a causa dell'aggiunta della classe super-big) e quindi eseguire il layout. Solo a quel punto sarà in grado di restituire l'altezza corretta. Si tratta di un lavoro inutile e potenzialmente costoso.

Per questo motivo, devi sempre eseguire prima le letture dello stile in batch (dove il browser può utilizzare i valori di layout del frame precedente), quindi eseguire le scritture:

Se eseguita correttamente, la funzione riportata sopra sarebbe:

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);

  box.classList.add('super-big');
}

Nella maggior parte dei casi non è necessario applicare stili e poi eseguire query sui valori; dovrebbe essere sufficiente utilizzare i valori dell'ultimo frame. Eseguire i calcoli dello stile e il layout in modo sincrono e prima di quanto richiesto dal browser sono potenziali colli di bottiglia e in genere non è una cosa che si vuole fare.

Evita il layout thrashing

Esiste un modo per rendere i layout sincroni forzati ancora peggiori: eseguine molti in rapida successione. Dai un'occhiata a questo codice:

function resizeAllParagraphsToMatchBlockWidth () {
  // Puts the browser into a read-write-read-write cycle.
  for (let i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = `${box.offsetWidth}px`;
  }
}

Questo codice esegue il loop in un gruppo di paragrafi e imposta la larghezza di ogni paragrafo in modo che corrisponda a quella di un elemento chiamato "scatola". Sembra sufficientemente innocuo, ma il problema è che ogni iterazione del loop legge un valore di stile (box.offsetWidth) e quindi lo utilizza immediatamente per aggiornare la larghezza di un paragrafo (paragraphs[i].style.width). Nell'iterazione successiva del loop, il browser deve tenere conto del fatto che gli stili sono cambiati dall'ultima richiesta di offsetWidth (nell'iterazione precedente) e quindi deve applicare le modifiche di stile ed eseguire il layout. Questo succederà su ogni singola iterazione.

La correzione per questo esempio consiste nel leggere di nuovo i valori e poi scriverli:

// Read.
const width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth () {
  for (let i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = `${width}px`;
  }
}

Se vuoi garantire la sicurezza, valuta la possibilità di utilizzare FastDOM, che raggruppa automaticamente le letture e scritture per te e dovrebbe impedirti di attivare accidentalmente layout sincroni forzati o thrashing del layout.

Immagine hero da Unsplash, di Hal Gatewood.