⚡ Prestazioni web

DOM troppo grande e content-visibility: pagine lunghe più leggere

Perché un DOM con troppi nodi rallenta stili, layout e interazioni, e come content-visibility, contain e la virtualizzazione degli elenchi riducono il lavoro.

Ogni elemento HTML di una pagina diventa un nodo del DOM, e ogni nodo ha un costo. Il browser deve calcolarne lo stile, posizionarlo nel layout, disegnarlo e tenerlo in memoria. Finché i nodi sono qualche centinaio non ci si accorge di nulla; quando diventano decine di migliaia, come accade con elenchi lunghi, tabelle estese, menu enormi o costruttori di pagine che annidano contenitori su contenitori, ogni operazione diventa più lenta.

Dove si paga un DOM grande

Il costo non si concentra in un solo momento:

  1. caricamento: più HTML da scaricare e analizzare, più nodi da costruire;
  2. calcolo degli stili: a ogni modifica il browser deve verificare quali regole CSS si applicano a quali elementi, e con selettori complessi il lavoro cresce con il numero dei nodi;
  3. layout: cambiare la dimensione di un elemento può costringere a ricalcolare la posizione di molti altri;
  4. interazioni: un clic che aggiunge una classe al body può innescare il ricalcolo degli stili dell'intera pagina, e questo tempo finisce nel ritardo di presentazione dell'INP;
  5. memoria: sui dispositivi con poca RAM, pagine molto grandi rischiano rallentamenti generali o il ricaricamento della scheda.

Lighthouse segnala un DOM eccessivo e indica il numero totale di elementi, la profondità massima e l'elemento con più figli: tre indizi utili per capire dove intervenire.

Ridurre i nodi alla fonte

L'intervento più efficace è non creare nodi inutili:

  • contenitori annidati: molti temi e costruttori visuali avvolgono ogni blocco in quattro o cinque div senza funzione. Con CSS Grid e Flexbox la stessa disposizione si ottiene quasi sempre con un solo livello;
  • contenuto nascosto: menu mobili, finestre modali, schede non attive e varianti di prodotto spesso sono presenti nel DOM fin dall'inizio, solo nascosti. Si possono generare al momento dell'apertura;
  • icone SVG ripetute: lo stesso SVG incollato cento volte moltiplica i tracciati; un elemento use che rimanda a un simbolo definito una volta sola è molto più leggero;
  • paginazione o caricamento progressivo: mostrare mille prodotti in una sola pagina raramente serve all'utente.

content-visibility: rimandare il lavoro fuori schermo

Quando il contenuto deve restare nella pagina, per esempio un articolo lungo o una pagina di documentazione, la proprietà CSS content-visibility permette al browser di saltare il rendering delle sezioni fuori dallo schermo:

.sezione {
  content-visibility: auto;
  contain-intrinsic-size: auto 600px;
}

Con auto, il browser calcola layout e disegno di una sezione solo quando si avvicina all'area visibile. Il contenuto resta nel DOM: è raggiungibile con la ricerca nella pagina, dai lettori di schermo e dalla navigazione con le ancore.

La seconda riga è importante. Una sezione saltata non ha dimensioni note, e senza indicazioni verrebbe trattata come alta zero: la barra di scorrimento cambierebbe continuamente e il contenuto salterebbe. contain-intrinsic-size fornisce una stima; con la parola chiave auto il browser ricorda la dimensione reale dopo il primo rendering e la riusa.

Quando usarla e quando no

Situazione Consiglio
Articoli lunghi divisi in sezioni Ottimo candidato
Elenchi di schede con altezza simile Buon candidato, con stima precisa
Contenuto nella parte iniziale della pagina Inutile, viene comunque disegnato
Elementi con altezza molto variabile Possibili salti di scorrimento

Va applicata a blocchi di una certa consistenza, non a ogni singolo paragrafo: su elementi minuscoli il beneficio è nullo e il rischio di salti aumenta.

La proprietà contain

Prima di content-visibility esisteva già contain, che dice al browser che un elemento è indipendente dal resto della pagina. Con contain: layout paint, per esempio, una modifica all'interno di un widget non costringe a ricalcolare il layout dell'intera pagina, e il disegno non esce dai suoi confini. È utile per componenti che si aggiornano spesso, come un orologio, un contatore o un pannello di notifiche.

Virtualizzare gli elenchi lunghi

Per elenchi con migliaia di righe, come una tabella di dati o un registro di eventi, la soluzione più radicale è la virtualizzazione: si creano nel DOM solo le righe visibili più un piccolo margine, e mentre l'utente scorre si riciclano gli stessi nodi cambiandone il contenuto. Il numero di nodi resta costante qualunque sia la lunghezza dell'elenco.

La virtualizzazione ha un prezzo: le righe non presenti non sono trovate dalla ricerca del browser e vanno gestite con attenzione per l'accessibilità. Per questo conviene riservarla alle interfacce applicative e preferire paginazione o content-visibility per i contenuti editoriali.

Misurare il risultato

Nel pannello Performance di DevTools, le voci Recalculate Style e Layout mostrano quanti elementi sono stati coinvolti in ogni ricalcolo. Confrontarle prima e dopo l'intervento, magari su un'interazione specifica come l'apertura di un menu, rende evidente il guadagno. Nel mio lavoro, ridurre l'annidamento di un tema e generare i menu solo all'apertura ha spesso migliorato l'INP più di qualsiasi ottimizzazione del JavaScript.

In sintesi

  • Ogni nodo del DOM costa in stili, layout, disegno e memoria.
  • Elimina contenitori inutili e genera contenuti nascosti solo quando servono.
  • content-visibility: auto con contain-intrinsic-size salta il rendering fuori schermo.
  • contain isola i componenti che si aggiornano spesso.
  • Per elenchi enormi nelle applicazioni, la virtualizzazione mantiene costante il numero di nodi.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche