Evita layout complessi e di grandi dimensioni e thrapping di layout

Il layout è il punto in cui il browser individua 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. La procedura si chiama 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 si chiama Layout in Chrome (e nei browser derivati come Edge) e Safari. In Firefox si chiama Reflow, ma il processo è sostanzialmente lo stesso.

Analogamente ai calcoli dello stile, i problemi immediati relativi al costo 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 di interazione
  • In genere, il layout è limitato all'intero documento.
  • Il numero di elementi DOM inciderà sulle prestazioni; se possibile, evita di attivare il layout.
  • Evita layout sincroni forzati e thrashing del layout; leggi i valori di stile e poi apporta le modifiche.

Effetti del layout sulla latenza di interazione

Quando un utente interagisce con la pagina, queste interazioni devono essere il più rapide possibile. Il tempo necessario per completare un'interazione, che termina quando il browser presenta il frame successivo per mostrare i risultati dell'interazione, è noto come latenza di interazione. Si tratta di un aspetto delle prestazioni della pagina misurato dalla metrica Interaction to Next Paint.

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 mantenere l'INP del tuo sito web il più basso possibile, è importante evitare il layout, se possibile. Se non è possibile evitare del tutto il layout, è importante limitarne il lavoro in modo che il browser possa presentare rapidamente il frame successivo.

Evita il layout, se possibile

Quando modifichi gli stili, il browser controlla se alcune delle modifiche richiedono il calcolo del layout e l'aggiornamento della relativa struttura di rendering. Le modifiche alle "proprietà geometriche", come larghezze, altezze, sinistra o in alto, richiedono tutte il layout.

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

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

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

Il layout è quasi sempre limitato all'intero documento. Se hai molti elementi, ci vorrà molto tempo per capire le posizioni e le dimensioni di tutti.

Se non è possibile evitare il layout, la soluzione è utilizzare di nuovo Chrome DevTools per vedere quanto tempo ci vuole e determinare se il layout è la causa di un collo di bottiglia. Innanzitutto, apri DevTools, vai alla scheda Spostamenti, fai clic su Registra e interagisci con il tuo sito. Quando interrompi la registrazione, viene visualizzato un'analisi del rendimento del tuo sito:

DevTools mostra un tempo lungo in Layout.

Se esaminiamo la traccia nell'esempio riportato sopra, vediamo che vengono impiegati oltre 28 millisecondi all'interno del layout per ogni frame, il che, se abbiamo 16 millisecondi per visualizzare un frame sullo schermo in un'animazione, è troppo elevato. Puoi anche vedere che DevTools ti indica le dimensioni dell'albero (1618 elementi in questo caso) e il numero di nodi che richiedono il layout (5 in questo caso).

Tieni presente che il consiglio generale è di evitare il layout se possibile, ma non sempre è possibile evitarlo. Se non puoi evitare il layout, tieni presente che il costo del layout è correlato alle dimensioni del DOM. Sebbene la relazione tra i due non sia strettamente associata, in genere i DOM più grandi comportano costi di layout più elevati.

Evita layout sincroni forzati

La spedizione di una cornice allo schermo avviene nel seguente ordine:

Utilizzo di flexbox come layout.

Innanzitutto viene eseguito il codice JavaScript, poi i calcoli degli stili e poi il layout. Tuttavia, è possibile forzare un browser a eseguire il layout in precedenza con JavaScript. Questo tipo di layout è chiamato layout sincrono forzato.

La prima cosa da tenere presente è che, quando viene eseguito il codice JavaScript, tutti i vecchi valori di layout del frame precedente sono noti e disponibili per le query. Quindi, se ad esempio vuoi scrivere l'altezza di un elemento (chiamiamolo "box") all'inizio del frame, puoi scrivere un 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);
}

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 non necessario 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 precedente sarà:

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

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

Per la maggior parte dei casi, non è necessario applicare gli stili e poi eseguire query sui valori. L'utilizzo dei valori dell'ultimo frame dovrebbe essere sufficiente. Eseguire i calcoli dello stile e il layout in modo sincrono e prima di quanto richiesto dal browser sono potenziali colli di bottiglia e non è un'attività che in genere vorrai fare.

Evitare il thrashing del layout

Esiste un modo per peggiorare ulteriormente i layout sincronizzati 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 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 accade in ogni singola iterazione.

La correzione per questo esempio consiste nel leggere e scrivere di nuovo 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, ti consigliamo di utilizzare FastDOM, che raggruppa automaticamente le letture e le scritture e dovrebbe impedirti di attivare accidentalmente layout sincronizzati forzati o il thrashing del layout.