Browser reflow: wat het veroorzaakt en hoe het Core Web Vitals beïnvloedt
Reflow herberekent elementposities en blokkeert de main thread. Leer wat het veroorzaakt, hoe je het detecteert en hoe je het voorkomt.

Wat is browser reflow?
Reflow is wat er gebeurt wanneer de browser de positie en grootte van elementen op de pagina herberekent. Elke keer dat je de DOM wijzigt of een CSS-eigenschap aanpast die de lay-out beïnvloedt, moet de browser opnieuw uitzoeken waar alles precies thuishoort. Deze berekening blokkeert de main thread. Er gebeurt verder niets totdat dit is voltooid.
Een enkele reflow op een eenvoudige pagina duurt microseconden. Maar als je er honderden triggert tijdens een gebruikersinteractie, kijk je aan tegen honderden milliseconden aan geblokkeerde main thread-tijd. Dat is genoeg om te falen voor Interaction to Next Paint.
Laatst beoordeeld door Arjen Karel in maart 2026
Table of Contents!
De rendering pipeline
Om te begrijpen waarom reflow duur is, moet je weten hoe de browser een pagina rendert. Elke visuele verandering doorloopt maximaal vijf fasen:
JavaScript → Style → Layout → Paint → Composite
JavaScript (of CSS) triggert een visuele verandering. De browser herberekent welke stijlen van toepassing zijn. Vervolgens voert het layout (reflow) uit om de geometrie te berekenen. Daarna paints het de pixels. Ten slotte composites het de lagen samen.
Niet elke wijziging raakt alle vijf de fasen. Dat is het belangrijkste inzicht. Verander width of height en je triggert de volledige pipeline. Verander background-color en je slaat lay-out volledig over (alleen paint + composite). Verander transform of opacity en je slaat zowel lay-out als paint over, en gaat direct naar composite. De web.dev rendering performance gids behandelt deze pipeline in detail.
Composite-only wijzigingen zijn goedkoop. Lay-outwijzigingen niet. Bij 60fps heeft de browser 16,66ms per frame om alles te doen. Na de overhead van de browser, houd je ongeveer 10ms over voor jouw code. Besteed dat aan reflow en je krijgt jank (haperingen).
Wat veroorzaakt reflow
Twee categorieën van zaken veroorzaken reflow: wijzigingen die de huidige lay-out ongeldig maken, en JavaScript-leesacties die de browser dwingen om de lay-out onmiddellijk te berekenen.
CSS-eigenschappen die lay-out triggeren
Het wijzigen van een van deze eigenschappen dwingt de browser tot een reflow:
- Afmetingen:
width,height,padding,border,min-height,max-width - Positie:
top,right,bottom,left,margin - Lay-outmodus:
display,float,position,flex,grid - Tekst:
font-size,font-family,font-weight,line-height,text-align,white-space - Inhoud:
overflow,word-wrap
Eigenschappen zoals color, background-color, visibility en box-shadow triggeren een repaint maar geen reflow. Eigenschappen zoals transform, opacity en filter triggeren geen van beide. Dit zijn de eigenschappen die je wilt gebruiken voor animaties en transities.
JavaScript-eigenschappen die synchrone lay-out afdwingen
Dit is waar het duur wordt. Bepaalde JavaScript-eigenschappen dwingen de browser om de lay-out nu meteen synchroon te berekenen, wat je script blokkeert. Paul Irish onderhoudt een uitgebreide lijst (5.000+ sterren op GitHub). De meest voorkomende zijn:
offsetWidth,offsetHeight,offsetTop,offsetLeftclientWidth,clientHeight,clientTop,clientLeftscrollWidth,scrollHeight,scrollTop,scrollLeftgetBoundingClientRect()getComputedStyle()innerText(ja, het lezen vaninnerTextforceert lay-out)focus()scrollIntoView()
Het lezen van een van deze na het wijzigen van een lay-outeigenschap forceert een synchrone reflow. De browser kan de waarde niet retourneren zonder eerst de lay-out te berekenen. Chrome DevTools markeert geforceerde reflows die langer duren dan 30ms als een prestatieknelpunt.
Layout thrashing: het patroon om te vermijden
Layout thrashing gebeurt wanneer je code in een loop afwisselt tussen het lezen en schrijven van lay-outeigenschappen. Elke leesactie forceert een reflow omdat de vorige schrijfactie de lay-out ongeldig maakte. Ik zie dit patroon constant in carousel-scripts, accordion-plugins en analytics-code die elementposities meet.
// SLECHT: forceert reflow bij elke iteratie
for (const el of elements) {
el.style.width = box.offsetWidth + 'px'; // lezen + schrijven = forced reflow
}
Elke iteratie leest offsetWidth (forceert lay-out) en schrijft vervolgens style.width (maakt lay-out ongeldig). Met 100 elementen zijn dat 100 geforceerde reflows in plaats van één.
// GOED: batch de leesactie, batch daarna de schrijfacties
const width = box.offsetWidth; // enkele leesactie
for (const el of elements) {
el.style.width = width + 'px'; // alleen schrijfacties, geen forced reflows
}
Eén leesactie, één reflow, klaar. De web.dev gids over layout thrashing toont dit patroon in detail. Als je individuele elementgroottes moet aflezen, verzamel dan eerst alle leesacties en voer daarna alle schrijfacties uit.
Geforceerde reflow detecteren in Chrome DevTools
Open het Performance-paneel en neem een trace op. Geforceerde reflows verschijnen als paarse "Layout"-blokken in de flame chart. Als Chrome een forced synchronous layout detecteert, voegt het een rode waarschuwingsdriehoek toe. Zweef eroverheen en je ziet precies welke JavaScript-regel de reflow heeft getriggert.
De Console logt ook een waarschuwing: "Forced reflow while executing JavaScript took Xms". Alles boven de 30ms is een probleem. Ik heb sites gezien waarbij een enkele scroll event handler 40ms aan lay-outwerk triggert op elk frame.
Lighthouse markeert dit ook. Zoek naar de "Avoid forced reflow" waarschuwing in de Performance categorie.
Hoe reflow de Core Web Vitals beïnvloedt
Interaction to Next Paint (INP)
Reflow heeft op twee manieren direct invloed op INP. Als er al een geforceerde reflow bezig is wanneer de gebruiker klikt, neemt de input delay toe omdat de main thread geblokkeerd is. Als de click handler zelf lay-outwerk triggert, neemt de processing time toe. In beide gevallen groeit ook de presentation delay, omdat de browser de lay-out moet voltooien voordat het de reactie kan painten.
De "goed"-drempel voor INP is 200ms. Een enkele geforceerde reflow van 30ms verbruikt al 15% van dat budget. Layout thrashing in een event handler kan INP gemakkelijk voorbij de 500ms duwen.
Op sites die worden gemonitord door CoreDash, tonen pagina's die DOM-lees- en schrijfacties batchen ongeveer 18% betere INP-scores in vergelijking met pagina's met layout thrashing-patronen.
Largest Contentful Paint (LCP)
Tijdens het laden van de pagina concurreert reflow om main thread-tijd. Font loading is hiervan een veelvoorkomende bron: wanneer een webfont binnenkomt en de fallback tekst vervangt, voert de browser een reflow uit voor elk element dat dit font gebruikt. Op een pagina met veel tekst kan die reflow LCP 100ms of meer vertragen.
Afbeeldingen zonder expliciete width en height attributen veroorzaken hetzelfde probleem. Volgens de 2025 Web Almanac heeft 62% van de mobiele pagina's nog steeds minstens één afbeelding zonder afmetingen. Wanneer die afbeelding laadt, reflowt de browser de pagina om ruimte te maken voor de daadwerkelijke grootte.
Cumulative Layout Shift (CLS)
Reflow zelf veroorzaakt geen CLS. CLS treedt op wanneer zichtbare elementen verplaatsen nadat de gebruiker ze heeft gezien. Maar reflow door laat ladende content (geïnjecteerde advertenties, afbeeldingen zonder afmetingen, dynamisch ingevoegde elementen) is het mechanisme achter de meeste layout shifts. Los de reflow trigger op en de layout shift verdwijnt.
CSS transitions die lay-outeigenschappen animeren, zijn een andere bron. Het overvloeien (transitioning) van height of margin veroorzaakt een reflow op elk animatieframe.
Reflow voorkomen met moderne CSS
Composite-only animaties
Animeer transform en opacity in plaats van width, height, top of left. Deze draaien op de GPU compositor thread en slaan de lay-out volledig over. Wil je een element verplaatsen? Gebruik transform: translateX(). Wil je het visueel van grootte veranderen? Gebruik transform: scale(). De 2025 Web Almanac ontdekte dat 40% van de mobiele pagina's nog steeds non-composited animaties gebruikt. Dat is 40% van de pagina's die onnodig lay-outwerk uitvoeren op elk frame.
CSS containment
De contain eigenschap vertelt de browser dat de interne structuur van een element onafhankelijk is van de rest van de pagina. Wanneer er iets verandert binnen een contained element, reflowt de browser alleen die subtree in plaats van het hele document.
article {
contain: content;
}
Dit is vooral nuttig voor pagina's met een grote DOM. Hoe meer elementen de browser moet controleren tijdens een reflow, hoe langer het duurt. Containment beperkt de impact (blast radius).
content-visibility
content-visibility: auto vertelt de browser om layout, paint en style-berekeningen over te slaan voor elementen die buiten het scherm vallen. Toen Google dit testte op een reisblog-demo, daalde de renderingtijd van 232ms naar 30ms. Een 7x verbetering.
.section {
content-visibility: auto;
contain-intrinsic-size: auto 500px;
}
De contain-intrinsic-size geeft de browser een placeholder-hoogte zodat de schuifbalkberekeningen correct blijven. Deze eigenschap werd in september 2025 Baseline Newly Available, wat betekent dat het werkt in alle grote browsers.
Praktische checklist
- Batch DOM-leesacties voor schrijfacties. Wissel nooit af tussen het lezen van lay-outeigenschappen en het schrijven van stijlwijzigingen.
- Stel expliciete afmetingen in op afbeeldingen en embeds. Dit voorkomt reflow wanneer de resource laadt.
- Animeer alleen met
transformenopacity. Deze slaan lay-out en paint volledig over. - Gebruik
contain: contentop onafhankelijke secties. Dit beperkt reflow tot de gewijzigde subtree. - Voeg
content-visibility: autotoe aan below-the-fold secties. Dit slaat de lay-out over voor content buiten het scherm. - Geef de voorkeur aan flexbox boven floats. Flexbox lay-out is ongeveer 4x sneller dan float lay-out voor hetzelfde aantal elementen.
- Yield naar de main thread tussen zware DOM-operaties om de pagina responsief te houden.
- Stel scripts uit die de DOM wijzigen totdat de initiële render is voltooid.
Monitor de daadwerkelijke impact van deze wijzigingen met Real User Monitoring. Lab tools zoals Lighthouse tonen je de lay-outkosten in isolatie, maar veldgegevens (field data) laten zien of je gebruikers de verbetering ook echt ervaren.
Your Lighthouse score is not the full picture.
Lab tests run on fast hardware with a stable connection. I analyze what your actual visitors experience on real devices and real networks.
Analyze Field Data
