Evita layout complessi e di grandi dimensioni e thrapping di layout

Con Layout il browser determina le informazioni geometriche degli elementi (dimensioni e posizione nella pagina). Ogni elemento avrà informazioni di dimensionamento esplicite o implicite in base al CSS utilizzato, ai contenuti dell'elemento o a un elemento principale. Questa procedura è denominata Layout in Chrome.

Il layout è il punto in cui il browser determina le informazioni geometriche degli elementi: dimensioni e posizione nella pagina. Ogni elemento avrà informazioni di dimensionamento esplicite o implicite in base al CSS utilizzato, ai contenuti dell'elemento o a un elemento principale. Questa procedura è denominata Layout in Chrome (e nei browser derivati come Edge) e Safari. In Firefox si chiama "adattamento dinamico del contenuto", ma il processo è in effetti lo stesso.

Analogamente ai calcoli di stile, le preoccupazioni immediate per i costi del layout sono:

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

Riepilogo

  • Il layout influisce direttamente sulla latenza dell'interazione
  • L'ambito del layout è in genere limitato all'intero documento.
  • Il numero di elementi DOM influisce sulle prestazioni; se possibile, dovresti evitare di attivare il layout.
  • Evita l'applicazione forzata di layout sincroni e thrash del layout; leggi i valori di stile e poi apporta modifiche di stile.

Effetti del layout sulla latenza dell'interazione

Le interazioni di un utente con la pagina devono avvenire il più rapidamente possibile. Il tempo necessario per il completamento di un'interazione (che termina quando il browser presenta il frame successivo per mostrare i risultati dell'interazione) è noto come latenza dell'interazione. Si tratta di un aspetto delle prestazioni della pagina che viene misurato dalla metrica Interazione con la colorazione successiva.

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

Per fare in modo che l'INP del tuo sito web sia il più basso possibile, è importante evitare il layout, se possibile. Se non è possibile evitare del tutto il layout, è importante limitare il funzionamento del layout in modo che il browser possa presentare rapidamente il frame successivo.

Se possibile, evita il layout

Quando modifichi gli stili, il browser verifica se è necessario calcolare il layout e se è necessario aggiornare l'albero di rendering per l'albero di rendering. Le modifiche alle "proprietà geometriche", come larghezze, altezze, sinistra o parte superiore richiedono tutte il layout.

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

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

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

L'ambito del layout è quasi sempre l'intero documento. Se gli elementi sono molti, ci vorrà molto tempo per determinarne le posizioni e le dimensioni.

Se non è possibile evitare il layout, la chiave è utilizzare di nuovo Chrome DevTools per capire quanto tempo richiede e stabilire se questo è 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, vedrai un'analisi del rendimento del tuo sito:

DevTools che mostra molto tempo nel layout.

Analizzando la traccia dell'esempio sopra, vediamo che vengono spesi oltre 28 millisecondi all'interno del layout per ogni fotogramma, che, quando abbiamo 16 millisecondi per ottenere un frame sullo schermo in un'animazione, è troppo alto. Puoi anche vedere che DevTools ti dirà la dimensione dell'albero (in questo caso 1618 elementi) e il numero di nodi che avevano bisogno di layout (5 in questo caso).

Tieni presente che il consiglio generale è evitare quando è possibile, ma non sempre è possibile farlo. Nei casi in cui non sia possibile evitare di utilizzare il layout, tieni presente che il relativo costo ha una relazione con le dimensioni del DOM. Sebbene la relazione tra i due non sia strettamente accoppiata, i DOM più grandi di solito comportano costi di layout più elevati.

Evita layout sincroni forzati

Per la spedizione di un frame allo schermo è previsto questo ordine:

Utilizzo di Flexbox per il layout.

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

La prima cosa da tenere presente è che, poiché JavaScript esegue tutte le query di layout precedenti, sono note e disponibili per te. Quindi se, ad esempio, vuoi scrivere l'altezza di un elemento (lo chiameremo "box") all'inizio del frame, puoi scrivere codice come questo:

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

I problemi sono maggiori se hai cambiato gli stili della casella prima di chiederne l'altezza:

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

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

Ora, per rispondere alla domanda sull'altezza, il browser deve prima applicare la modifica dello stile (perché è stata aggiunta la classe super-big) e quindi eseguire il layout. Solo dopo potrà restituire l'altezza corretta. Si tratta di un lavoro non necessario e potenzialmente costoso.

Per questo motivo, devi sempre raggruppare le letture dello stile ed eseguirle per prime (in cui 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 quindi eseguire query sui valori; l'uso dei valori dell'ultimo frame dovrebbe essere sufficiente. Eseguire i calcoli di stile e il layout in modo sincrono e precedente rispetto al browser potrebbe costituire un problema di colli di bottiglia e non si tratta di un'azione che in genere si desidera eseguire.

Evita il thrashing del layout

Esiste un modo per peggiorare ulteriormente i layout sincroni forzati: eseguirne 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 si ripete su un gruppo di paragrafi e imposta la larghezza di ogni paragrafo in base a quella di un elemento chiamato "riquadro". Sembra abbastanza innocuo, ma il problema è che ogni iterazione del loop legge un valore di stile (box.offsetWidth) e 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), quindi deve applicare le modifiche di stile ed eseguire il layout. Questo succede a ogni singola iterazione.

La soluzione per questo esempio consiste nel leggere e quindi scrivere i valori:

// 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, potresti usare FastDOM, che raggruppa automaticamente le letture e le scritture per conto tuo e dovrebbe impedire l'attivazione accidentale di layout sincroni forzati o di thrash del layout.

Immagine hero di Unsplash, di Hal Gatewood.