Capita a tutti: si sta per toccare un link e, un attimo prima, il testo scivola verso il basso perché sopra è comparso un banner. Il Cumulative Layout Shift misura proprio questo fastidio. Un valore fino a 0,1 è considerato buono, oltre 0,25 è scarso. A differenza di LCP e INP, il CLS non è un tempo ma un punteggio senza unità, e si può quasi sempre portare vicino a zero con interventi di HTML e CSS, senza toccare il server.
Come si calcola, in breve
Ogni spostamento inatteso riceve un punteggio dato dal prodotto di due fattori: quanta parte del viewport è occupata dagli elementi instabili (frazione di impatto) e di quanto si sono spostati rispetto all'altezza o larghezza del viewport (frazione di distanza). Gli spostamenti vicini nel tempo vengono raggruppati in finestre, e il CLS della pagina è il valore della finestra peggiore, non la somma di tutta la visita.
Un dettaglio importante: gli spostamenti che avvengono entro mezzo secondo da un'interazione dell'utente, come l'apertura di una fisarmonica dopo un clic, non vengono conteggiati. Il CLS penalizza ciò che l'utente non si aspetta.
Causa 1: immagini e video senza dimensioni
Se un tag img non ha width e height, il browser non sa quanto spazio riservare finché il file non arriva, e tutto il contenuto sotto viene spinto in basso. La soluzione è indicare sempre le dimensioni intrinseche: i browser moderni le usano per calcolare il rapporto d'aspetto anche quando il CSS rende l'immagine fluida.
<img src="foto.webp" width="1600" height="900" alt="…">
img { max-width: 100%; height: auto; }
Per contenitori senza un'immagine nativa, come un iframe di una mappa o un riquadro video incorporato, si usa la proprietà aspect-ratio:
.video-incorporato { aspect-ratio: 16 / 9; width: 100%; }
Causa 2: contenuti inseriti sopra quelli esistenti
Banner per i cookie, avvisi di promozione, barre «scarica l'app» e messaggi di errore aggiunti in cima alla pagina dopo il caricamento spingono giù tutto. Ci sono tre strade:
- riservare lo spazio fin dall'inizio con un'altezza minima, se il contenuto arriverà sicuramente;
- mostrare il banner in sovrapposizione, con
position: fixed, così non altera il flusso del documento; - inserire i contenuti dinamici sotto la parte visibile, non sopra.
Per un banner dei consensi, la sovrapposizione in basso è la scelta più semplice e più stabile.
Causa 3: spazi pubblicitari e widget esterni
Gli annunci e i widget di terze parti hanno dimensioni variabili e arrivano tardi. La pratica corretta è assegnare al contenitore un'altezza minima pari alla dimensione più probabile. Se lo spazio resta vuoto, meglio un riquadro neutro che un collasso improvviso: anche far sparire uno spazio riservato genera uno spostamento.
Causa 4: font web che cambiano le metriche
Quando un font web sostituisce quello di ripiego, lettere più larghe o più alte possono far andare a capo le righe in punti diversi, e i paragrafi si allungano. Il fenomeno si attenua scegliendo un font di ripiego simile e regolandone le metriche con i descrittori di @font-face come size-adjust, ascent-override e descent-override, così che il cambio sia quasi invisibile.
@font-face {
font-family: "Ripiego Regolato";
src: local("Arial");
size-adjust: 104%;
ascent-override: 92%;
}
body { font-family: "FontDelSito", "Ripiego Regolato", sans-serif; }
I valori esatti si ricavano confrontando i due font; esistono strumenti che li calcolano automaticamente.
Causa 5: animazioni che muovono il layout
Animare top, left, margin o height sposta davvero gli elementi e può generare CLS. Le animazioni realizzate con transform, invece, non modificano il layout e non vengono conteggiate. Uno slider che scorre con transform: translateX() è stabile; uno che cambia margin-left non lo è.
Come trovare gli spostamenti
In DevTools, nel pannello Performance, la traccia «Layout shifts» evidenzia ogni spostamento e gli elementi coinvolti. Esiste anche un'opzione di rendering che colora di blu le aree che si spostano mentre si naviga. Sul campo, la libreria web-vitals con attribuzione riporta il selettore dell'elemento che si è spostato di più, informazione preziosa perché alcuni spostamenti si verificano solo con connessioni lente o in pagine lunghe dove l'utente scorre.
Attenzione a una differenza tra laboratorio e realtà: uno strumento come Lighthouse misura solo il caricamento iniziale, mentre i dati reali includono anche gli spostamenti che avvengono durante lo scorrimento, per esempio quando immagini caricate in modalità lazy non hanno dimensioni. Per questo un buon punteggio in laboratorio non garantisce un buon CLS sul campo.
Una lista di controllo
| Elemento | Verifica |
|---|---|
| Immagini | width e height sempre presenti |
| Iframe e video | aspect-ratio o altezza riservata |
| Banner | in sovrapposizione o con spazio riservato |
| Annunci | contenitore con altezza minima |
| Font | ripiego con metriche regolate |
| Animazioni | solo transform e opacity |
In sintesi
- Il CLS misura gli spostamenti inattesi; buono fino a 0,1, conta la finestra peggiore.
- Dimensioni esplicite e
aspect-ratiorisolvono la maggior parte dei casi. - Banner e avvisi vanno in sovrapposizione o in uno spazio già riservato.
- Font di ripiego regolati riducono i salti al cambio di carattere.
- Anima con
transforme verifica anche con dati reali, non solo in laboratorio.