Forced reflow in Lighthouse: wat het betekent en de fix
Een script dat de pagina aanpast en daarna om een afmeting vraagt, dwingt de browser om de layout direct opnieuw te berekenen. Wanneer dat tikken laat hangen, en wanneer het onschuldig is.
Wat betekent Forced reflow in Lighthouse?
Een forced reflow betekent dat een script je pagina aanpast en daarna om een afmeting vraagt, waardoor de browser de layout direct opnieuw moet berekenen. Lighthouse toont die scripts in het Forced reflow-inzicht ("A forced reflow occurs when JavaScript queries geometric properties"). Eén keer is normaal; in een loop blijven tikken hangen. Laat CSS het werk van het script doen, of lees eerst alle afmetingen uit voordat je iets aanpast.
Table of Contents!
Wat toont de Forced reflow-melding?
Lighthouse 13 en PageSpeed Insights omschrijven het zo: "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." De melding kleurt rood als scripts tijdens het laden van de pagina in één keer 30 ms of meer aan layout-werk forceren.
Het onderstaande rapport komt van een overzichtspagina voor vakantiehuisjes die ik heb gebouwd zoals een WordPress-verhuursite. Het thema-script kort elke beschrijving in tot drie regels en maakt alle kaarten even hoog.

Lighthouse 13.5 op mobiel, DevTools-throttling (Slow 4G, 4x CPU).
- Top function call: de buitenste functie die het layout-werk startte. Hover over het ingekorte bestandspad voor het volledige pad; dat noemt het thema, de plugin of de app. Een bestand op een ander domein is meestal een third-party tag, zoals een session recorder (Scripts die je niet kunt aanpassen).
- Source: elke regel code die om een afmeting vroeg.
- Total reflow time: de layout-tijd die die functie of regel veroorzaakte.
- Unscored: het inzicht telt niet mee voor je Performance-score. De long tasks erachter (periodes van meer dan 50 ms waarin de pagina niet kan reageren) verlagen de score via Total Blocking Time.
De bovenste rij (388 ms) is lager dan de Source-rijen bij elkaar (743 ms) doordat het cabin-script tijdens het laden twee keer draait, en de bovenste rij alleen de grootste run toont.
Waarom dwingt een script de browser om de layout opnieuw te berekenen?
Op het overzicht van vakantiehuisjes hierboven bevriest de pagina bij een tik op het filter "All" een derde van een seconde voordat de 48 kaarten verschijnen.
Layout is de stap waarin de browser berekent waar elk vlak komt en hoe groot het is. Normaal gesproken doet de browser dat één keer per frame, nadat de scripts zijn uitgevoerd. Past een script de pagina aan (een tekst, een class, een hoogte) en leest het daarna een afmeting uit, zoals offsetHeight, getBoundingClientRect(), scrollTop of getComputedStyle(), dan moet de browser de layout direct uitvoeren, midden in het script, om antwoord te geven. Paul Irish houdt de volledige lijst bij van alle reads die dit forceren.
Bij een enkele forced reflow gaat het meestal om layout-werk dat de browser een moment later toch al had gedaan. In een loop die telkens wijzigt en opnieuw leest, is het elke ronde een volledige layout: layout thrashing. Het thema van de huisjes kort elke beschrijving zo in:
while (el.offsetHeight > max && words.length > 1) {
words.pop();
el.textContent = words.join(' ') + '…';
} Elk woord dat het weghaalt verandert de tekst, waardoor de volgende offsetHeight-read een nieuwe layout forceert: één per woord, op elke kaart.
Hoeveel trager maakt een forced reflow een pagina?
Ik heb het overzicht met huisjes doorgemeten met het thema-script (Voor) en met CSS die de tekst inkort en de kaarten even hoog maakt (Na). Beide versies zien er hetzelfde uit.
| Voor | Na | |
|---|---|---|
| Lighthouse-score | 84 | 92 |
| Total Blocking Time | 360 ms | 0 ms |
| Total reflow time | 743 ms | geen |
| Een tik op "All" | 320 ms | 16 ms |

Voor

Na
Lighthouse 13.5 op mobiel, DevTools-throttling.
Die 8 punten komen door Total Blocking Time: de geforceerde layouts houden de pagina langer geblokkeerd. De tik is wat je bezoeker voelt, en telt mee voor INP (Interaction to Next Paint), de Core Web Vital voor hoe snel een pagina reageert op tikken en klikken. 320 ms zit boven de grens van 200 ms voor een goede INP, en 298 ms daarvan was layout die het script forceerde; 16 ms is een enkel frame. Lighthouse tikt zelf nooit, dus heb ik de tikken gemeten in Chrome met de CPU vertraagd naar telefoonsnelheid.
Wanneer is een forced reflow onschuldig?
- Eén kleine rij tijdens het laden. Een rij van net iets meer dan 30 ms is vaak de eerste layout van de pagina, net wat eerder uitgevoerd omdat een script om een afmeting vroeg. Het thema-script van het overzicht, herschreven om eerst alle hoogtes uit te lezen, toonde in één van de vier Lighthouse-runs een rij van 37 ms, en de tik op "All" duurde 16 ms.
- Een rij "[unattributed]". Er staat geen coderegel bij: draai Lighthouse opnieuw, en is de rij weg, laat het dan zo.
- Een script dat een animatie start. Modals in Bootstrap en sommige popup-plugins lezen met opzet een afmeting uit om hun CSS-transition te starten.

Lighthouse 13.5 op mobiel, DevTools-throttling.
Los het op als de totale reflow-tijd in de honderden milliseconden loopt, als één bestand veel rijen heeft, of als het script ook draait bij tikken: een filter, een menu, een slider.
Welk script veroorzaakt de forced reflow bij een tik?
Lighthouse laadt de pagina alleen, dus neem de tikken die blijven hangen op in het Performance-paneel:
- Open DevTools (F12), ga naar Performance en zet de CPU op 4x slowdown, zodat je laptop zich gedraagt als een telefoon.
- Klik op Record, tik op wat traag aanvoelt en stop de opname.
- Open Forced reflow in de Insights-zijbalk. "Call frames that trigger reflow" noemt de functie en de regel.

Eén tik op "All" op het overzicht met huisjes: clampText in cabins.js.
De console meldt hetzelfde als "[Violation] Forced reflow while executing JavaScript took 38ms", zodra je Verbose aanzet bij de logniveaus.
Noemt Lighthouse alleen jquery.min.js, dan deed jQuery het leeswerk voor een thema of plugin. Neem een reload op in het Performance-paneel en klik op een Layout-blok met een rood driehoekje: onder Function stack in de Summary is het bestand tussen de regels van jQuery, met een pad zoals /wp-content/plugins/<name>/, de plugin.
Je field data bevat de tikken en klikken van je echte bezoekers. Open in CoreDash INP, ga naar Breakdown en groepeer op LOAF: Chrome legt vast welke scripts draaiden in elk traag frame (Long Animation Frames), dus elke rij is een script met de INP van de interacties waarin het meedraaide. Een forced reflow in een click- of tap-handler telt als processing, het paarse deel van elke balk. Begin dus bij een traag script met een lang paars deel.

INP per script in CoreDash, desktop, p75: groen is input delay, paars processing, blauw presentation.
Hoe los je een forced reflow op?
Begin bij het bestand in Top function call en vraag je af of CSS het werk van dat script kan overnemen. Tekst afkappen op drie regels (line-clamp), kaarten van gelijke hoogte (grid), een header die bovenaan blijft staan (position: sticky) en een afbeeldingskader dat zijn vorm behoudt (aspect-ratio) hebben geen script nodig. En zonder script forceert niets een layout.
Neem na elke fix hieronder dezelfde tik opnieuw op: Forced reflow moet verdwenen zijn uit de Insights-zijbalk. Controleer het daarna in Lighthouse en in je field data; Search Console heeft tot 28 dagen nodig.
WordPress-thema's, plugins en pagebuilders
Het pad in Top function call noemt het thema (/wp-content/themes/) of de plugin (/wp-content/plugins/). Zoek eerst naar een instelling. Elementors "Stretch Section" verbreedt een sectie met JavaScript bij elke laadactie en resize; de Elementor Full Width-paginalayout met een container op volledige breedte doet dit in CSS. Een Swiper-slider die op "auto" slides per view staat meet elke slide op; bij een vast aantal berekent hij de breedtes zonder ze uit te lezen.
JavaScript uitstellen in WP Rocket of een vergelijkbare plugin laat de melding verdwijnen, maar het script draait dan bij de eerste tik of scroll van de bezoeker, met dezelfde geforceerde layouts. Fix liever het script zelf, of meld het bij de developer van de plugin en vervang de plugin als er niets verandert.
Kort het thema tekst in met JavaScript, doe dit dan met CSS in je child theme, met de class van je thema voor de tekst:
.cabin .desc {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
} Zet daarna het clamp-script van het thema uit: via een thema-optie, of met wp_dequeue_script() via de handle.
Shopify-thema's en apps
Zet in de theme editor onder App embeds de apps één voor één uit en draai Lighthouse opnieuw. Verdwijnt de melding, meld die app dan bij de developer, of vervang hem. Een pad met /assets/ in Top function call is een thema-bestand, afkomstig uit het thema zelf of van een app die er code aan heeft toegevoegd. Dawn en thema's die daarop zijn gebouwd lezen een afmeting meestal maar één keer uit en batchen hun wijzigingen. Kijk dus eerst naar de apps.
Je eigen JavaScript en React
Moet een script meten, lees dan eerst alle afmetingen en pas daarna dingen aan, zodat één layout antwoord geeft op elke read. Een accordion die elk paneel op zijn eigen hoogte instelt:
const panels = [...document.querySelectorAll('.panel')];
// A layout for every panel: read, write, read, write
panels.forEach(p => { p.style.maxHeight = p.scrollHeight + 'px'; });
// One layout: read every height, then write them all
const heights = panels.map(p => p.scrollHeight);
panels.forEach((p, i) => { p.style.maxHeight = heights[i] + 'px'; }); - Resize en scroll: ResizeObserver en IntersectionObserver geven je de afmetingen uit de layout die de browser net heeft gedaan. Gebruik die in plaats van afmetingen uit te lezen in een resize- of scroll-handler.
- React: meet één keer in
useLayoutEffecten update de state één keer. Mount menu's, popovers en tooltips pas zodra ze openen, zodat gesloten elementen niets meten tijdens het laden.
Scripts die je niet kunt aanpassen
Session recorders en heatmap-tags lezen met opzet afmetingen uit: Microsoft Clarity leest bij de start een tiental pagina-afmetingen uit en de positie van alles waar een bezoeker op klikt. Verwijder de tag, neem een steekproef van bezoeken op, of laad hem alleen op pagina's die je onderzoekt.
Een forced reflow in een plugin of app die je niet kunt vervangen, of tikken die blijven hangen op telefoons van je bezoekers en niet op die van jou? In een Core Web Vitals power hour vinden we het script achter je traagste tikken en bepalen we samen of we het fixen, vervangen of verwijderen.
Zoek uit wat echt traag is.
Ik leg je critical rendering path bloot met echte data. Je krijgt een fix-lijst op prioriteit, geen Lighthouse-rapport.
Boek een audit