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.

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

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.

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 report, the Forced reflow insight expanded with the label Unscored: Top function call cabins.js line 46, 388 ms; Source rows cabins.js line 10 3 ms, line 12 733 ms, line 23 7 ms

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.

VoorNa
Lighthouse-score8492
Total Blocking Time360 ms0 ms
Total reflow time743 msgeen
Een tik op "All"320 ms16 ms
Lighthouse report at phone width for the cabin listing before the fix: Performance 84, First Contentful Paint 2.7 s, Largest Contentful Paint 2.7 s, Total Blocking Time 360 ms, CLS 0

Voor

The same report after the fix: Performance 92, First Contentful Paint 2.7 s, Largest Contentful Paint 2.7 s, Total Blocking Time 0 ms, CLS 0

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.
Forced reflow insight with one row: Top function call cabins.js line 29, 37 ms, and one Source row cabins.js line 8, 37 ms

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:

  1. Open DevTools (F12), ga naar Performance en zet de CPU op 4x slowdown, zodat je laptop zich gedraagt als een telefoon.
  2. Klik op Record, tik op wat traag aanvoelt en stop de opname.
  3. Open Forced reflow in de Insights-zijbalk. "Call frames that trigger reflow" noemt de functie en de regel.
Chrome DevTools Performance panel with one tap recorded: the Main track shows Event: click, filterCards, layoutCards and clampText over a long row of layout work; the Forced reflow insight in the sidebar lists 452 ms and the call frames clampText in cabins.js lines 10 and 12

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.

CoreDash INP subparts by LOAF: p75 INP per script, from 125 ms (good) to 0.65 s (poor), each split into input delay, processing and presentation.

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 useLayoutEffect en 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.

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.

 

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
Forced reflow in Lighthouse: wat het betekent en de fix Core Web Vitals Forced reflow in Lighthouse: wat het betekent en de fix