Forced reflow in Lighthouse: cosa significa e il fix

Uno script che modifica la pagina e poi richiede una dimensione costringe il browser a rifare subito il layout. Quando fa bloccare i tap e quando è innocuo.

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-10-26

Cosa significa Forced reflow in Lighthouse?

Un forced reflow si verifica quando uno script modifica la pagina e poi richiede una dimensione: il browser deve ricalcolare subito il layout. Lighthouse elenca questi script nell'insight Forced reflow ("A forced reflow occurs when JavaScript queries geometric properties"). Una volta sola è normale; in un ciclo fa bloccare i tap. Lascia il lavoro dello script al CSS, oppure leggi ogni dimensione prima di modificare qualsiasi cosa.

Cosa elenca la segnalazione Forced reflow?

Lighthouse 13 e PageSpeed Insights la descrivono così: "A forced reflow occurs when JavaScript queries geometric properties (such as offsetWidth) after styles have been invalidated by a change to the DOM state. This can result in poor performance. Learn more about forced reflows and possible mitigations." Diventa rossa quando gli script forzano 30 ms o più di lavoro di layout in una volta sola durante il caricamento della pagina.

Il report qui sotto proviene dalla pagina di annunci di baite che ho creato come un tipico sito WordPress per case vacanza: lo script del tema taglia ogni descrizione a tre righe e rende tutte le card della stessa altezza.

Report di Lighthouse 13.5, insight Forced reflow espanso con l'etichetta Unscored: Top function call cabins.js riga 46, 388 ms; righe Source cabins.js riga 10 3 ms, riga 12 733 ms, riga 23 7 ms

Lighthouse 13.5 su mobile, throttling di DevTools (Slow 4G, 4x CPU).

  • Top function call: la funzione più esterna che ha avviato il lavoro di layout. Passa il cursore sul percorso abbreviato del file per vedere quello completo, che indica il tema, il plugin o l'app. Un file su un altro dominio è di solito un tag di terze parti, come un registratore di sessione (Script che non puoi modificare).
  • Source: ogni riga di codice che ha richiesto una dimensione.
  • Total reflow time: il tempo di layout causato da quella funzione o riga.
  • Unscored: l'insight non ha peso nel punteggio Performance. I long task dietro di esso (intervalli superiori a 50 ms in cui la pagina non può rispondere) abbassano il punteggio attraverso il Total Blocking Time.

La prima riga (388 ms) è inferiore alla somma delle righe Source (743 ms) perché lo script delle baite viene eseguito due volte durante il caricamento, e la prima riga mostra solo l'esecuzione più pesante.

Perché uno script costringe il browser a rifare il layout?

Nell'elenco di baite visto sopra, un tap sul filtro "All" blocca la pagina per un terzo di secondo prima che compaiano le 48 card.

Il layout è la fase in cui il browser calcola la posizione e la dimensione di ogni riquadro. Di norma lo fa una volta per frame, dopo l'esecuzione degli script. Quando uno script modifica la pagina (un testo, una classe, un'altezza) e poi legge una dimensione, come offsetHeight, getBoundingClientRect(), scrollTop o getComputedStyle(), il browser deve eseguire il layout all'istante, all'interno dello script, per poter rispondere. Paul Irish tiene l'elenco completo delle letture che lo forzano.

Un singolo forced reflow è perlopiù un layout che il browser avrebbe comunque eseguito un istante dopo. In un ciclo che modifica e legge ripetutamente, si tratta invece di un layout completo a ogni iterazione: layout thrashing. Il tema delle baite taglia ogni descrizione in questo modo:

while (el.offsetHeight > max && words.length > 1) {
  words.pop();
  el.textContent = words.join(' ') + '…';
}

Ogni parola rimossa modifica il testo, quindi la successiva lettura di offsetHeight forza un nuovo layout: uno per parola, su ogni card.

Quanto rallenta la pagina un forced reflow?

Ho misurato la pagina delle baite con lo script del tema (Prima) e con il CSS che taglia il testo e rende le card della stessa altezza (Dopo). Entrambe le versioni hanno lo stesso aspetto.

PrimaDopo
Punteggio Lighthouse8492
Total Blocking Time360 ms0 ms
Total reflow time743 msnessuno
Un tap su "All"320 ms16 ms
Report Lighthouse a larghezza smartphone per la pagina delle baite prima della correzione: Performance 84, First Contentful Paint 2,7 s, Largest Contentful Paint 2,7 s, Total Blocking Time 360 ms, CLS 0

Prima

Lo stesso report dopo la correzione: Performance 92, First Contentful Paint 2,7 s, Largest Contentful Paint 2,7 s, Total Blocking Time 0 ms, CLS 0

Dopo

Lighthouse 13.5 su mobile, throttling di DevTools.

Gli 8 punti arrivano dal Total Blocking Time: i layout forzati tengono la pagina bloccata più a lungo. Il tap è ciò che percepisce il visitatore e incide sull'INP (Interaction to Next Paint), il Core Web Vital che misura la velocità con cui una pagina risponde a tap e clic. 320 ms superano la soglia di 200 ms per un buon INP, e 298 ms di questi erano layout forzati dallo script; 16 ms corrispondono a un singolo frame. Lighthouse non esegue tap, quindi ho misurato i tap in Chrome con la CPU rallentata alla velocità di uno smartphone.

Quando un forced reflow è innocuo?

  • Una sola riga breve durante il caricamento. Una riga di poco superiore a 30 ms è spesso il primo layout della pagina, eseguito con un leggero anticipo perché uno script ha richiesto una dimensione. Lo script del tema della pagina delle baite, riscritto per leggere prima tutte le altezze, ha mostrato una riga da 37 ms in una sessione di Lighthouse su quattro, e il tap su "All" ha richiesto 16 ms.
  • Una riga "[unattributed]". Non indica alcuna riga di codice: esegui di nuovo Lighthouse e, se la riga scompare, ignorala.
  • Uno script che avvia un'animazione. I modal di Bootstrap e alcuni plugin di popup leggono intenzionalmente una dimensione per far partire la transizione CSS.
Insight Forced reflow con una sola riga: Top function call cabins.js riga 29, 37 ms, e una riga Source cabins.js riga 8, 37 ms

Lighthouse 13.5 su mobile, throttling di DevTools.

Intervieni quando il tempo totale di reflow è nell'ordine delle centinaia di millisecondi, quando un file presenta molte righe o quando lo script viene eseguito anche sui tap: un filtro, un menu, uno slider.

Quale script causa il forced reflow su un tap?

Lighthouse si limita a caricare la pagina, quindi registra i tap che si bloccano nel pannello Performance:

  1. Apri DevTools (F12), vai su Performance e imposta il rallentamento della CPU su 4x (4x slowdown), così il portatile si comporta come uno smartphone.
  2. Fai clic su Record, fai tap sull'elemento che sembra lento e interrompi la registrazione.
  3. Apri Forced reflow nella barra laterale Insights. "Call frames that trigger reflow" indica la funzione e la riga.
Pannello Performance di Chrome DevTools con un tap registrato: la traccia Main mostra Event: click, filterCards, layoutCards e clampText sopra una lunga riga di operazioni di layout; l'insight Forced reflow nella barra laterale elenca 452 ms e i call frame clampText in cabins.js alle righe 10 e 12

Un tap su "All" nella pagina delle baite: clampText in cabins.js.

La console segnala la stessa cosa come "[Violation] Forced reflow while executing JavaScript took 38ms", dopo aver attivato il livello di log Verbose.

Quando Lighthouse indica soltanto jquery.min.js, significa che jQuery ha eseguito la lettura per conto di un tema o di un plugin. Registra un ricaricamento nel pannello Performance e fai clic su un blocco Layout con il triangolo rosso: sotto Function stack nel Summary, il file tra le righe di jQuery, con un percorso come /wp-content/plugins/<name>/, è il plugin.

I field data raccolgono i tap e i clic dei visitatori reali. In CoreDash, apri INP, Breakdown e raggruppa per LOAF: Chrome registra quali script sono stati eseguiti in ogni frame lento (Long Animation Frames), quindi ogni riga rappresenta uno script con l'INP delle interazioni in cui è intervenuto. Un forced reflow nel gestore di un clic o di un tap viene conteggiato come processing (la parte viola di ciascuna barra): parti quindi da uno script lento con la sezione viola più lunga.

Fasi dell'INP in CoreDash per LOAF: INP p75 per script, da 125 ms (buono) a 0,65 s (scarso), ciascuno suddiviso in input delay, processing e presentation.

INP per script in CoreDash, desktop, p75: il verde è l'input delay, il viola il processing, il blu la presentation.

Come si risolve un forced reflow?

Parti dal file indicato in Top function call e chiediti se il CSS può svolgere il compito di quello script. Il testo tagliato a tre righe (line-clamp), le card di uguale altezza (grid), un'intestazione che rimane fissa in alto (position: sticky) e un contenitore immagine che mantiene le proporzioni (aspect-ratio) non richiedono alcuno script. E senza script, nulla forza il layout.

Dopo aver applicato una delle soluzioni seguenti, registra di nuovo lo stesso tap: Forced reflow dovrebbe essere sparito dalla barra laterale Insights. Poi fai una verifica in Lighthouse e nei field data; Search Console richiede fino a 28 giorni.

Temi, plugin e page builder per WordPress

Il percorso in Top function call indica il tema (/wp-content/themes/) o il plugin (/wp-content/plugins/). Cerca prima di tutto un'impostazione. La funzione "Stretch Section" di Elementor allarga una sezione con JavaScript a ogni caricamento e ridimensionamento; il layout di pagina Elementor Full Width con un contenitore a larghezza intera lo fa invece in CSS. Uno slider Swiper con slide per vista impostate su "auto" misura ogni slide; con un numero fisso ne calcola la larghezza senza leggerla.

Ritardare JavaScript con WP Rocket o un plugin simile fa sparire la segnalazione, ma lo script verrà poi eseguito al primo tap o scroll del visitatore, causando gli stessi layout forzati. Modifica invece lo script, oppure segnalalo allo sviluppatore del plugin e sostituiscilo se non viene aggiornato.

Se il tema taglia il testo con JavaScript, fallo con il CSS nel child theme, usando la classe del tema assegnata al testo:

.cabin .desc {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

Poi disattiva lo script di clamp del tema: tramite un'impostazione del tema, oppure con wp_dequeue_script() usando il suo handle.

Temi e app per Shopify

Nell'editor del tema, sotto App embeds, disattiva le app una alla volta ed esegui nuovamente Lighthouse. Quando la segnalazione scompare, segnala l'app al suo sviluppatore oppure sostituiscila. Un percorso con /assets/ in Top function call è un file del tema, proveniente dal tema stesso o da un'app che vi ha inserito del codice. Dawn e i temi da esso derivati leggono perlopiù le dimensioni una volta sola raggruppando le modifiche, quindi controlla prima le app.

JavaScript personalizzato e React

Quando uno script deve effettuare delle misurazioni, leggi prima tutte le dimensioni e modifica il DOM solo dopo: in questo modo un unico layout risponde a tutte le letture. Ecco un accordion che imposta ogni pannello alla propria altezza:

const panels = [...document.querySelectorAll('.panel')];

// Un layout per ogni pannello: leggi, scrivi, leggi, scrivi
panels.forEach(p => { p.style.maxHeight = p.scrollHeight + 'px'; });

// Un solo layout: leggi tutte le altezze, poi scrivi tutto insieme
const heights = panels.map(p => p.scrollHeight);
panels.forEach((p, i) => { p.style.maxHeight = heights[i] + 'px'; });
  • Resize e scroll: ResizeObserver e IntersectionObserver forniscono le dimensioni dal layout appena calcolato dal browser. Usali invece di leggere le dimensioni in un gestore di resize o scroll.
  • React: misura una volta sola in useLayoutEffect e aggiorna lo state una volta sola. Esegui il mount di menu, popover e tooltip solo quando si aprono, evitando che da chiusi effettuino misurazioni durante il caricamento.

Script che non puoi modificare

I registratori di sessione e i tag per heatmap leggono le dimensioni intenzionalmente: all'avvio, Microsoft Clarity legge una dozzina di dimensioni della pagina e la posizione di qualsiasi elemento cliccato dal visitatore. Rimuovi il tag, registra solo un campione di visite oppure caricalo esclusivamente sulle pagine che stai analizzando.

Forced reflow in un plugin o in un'app che non puoi sostituire, o tap che si bloccano sui telefoni dei visitatori ma non sul tuo? In una Core Web Vitals power hour individuiamo lo script responsabile dei tap più lenti e decidiamo insieme se correggerlo, sostituirlo o rimuoverlo.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

 

Search Console si lamenta del tuo sito?

Ti mando una lista di fix in ordine di priorità, basata su dati reali. Non un PDF da 50 pagine.

Richiedi l'audit
Forced reflow in Lighthouse: cosa significa e il fix Core Web Vitals Forced reflow in Lighthouse: cosa significa e il fix