Reflow and Repaint: A Complete Guide to Slow Web
Reflow vs. Repaint — Factors That Really Impact Browser Rendering Performance

Recently, while reviewing rendering performance, I came across the distinction between Reflow and Repaint.
While these two terms often appear in web performance issues, there aren't many articles that clearly explain the difference between them.
These two terms inadvertently incur rendering costs when using React, RealGrid, or general DOM manipulation.
--
💡 What are Reflow and Repaint?
When a browser draws a page, it doesn't simply interpret HTML.
DOM → CSSOM → Render Tree is created, and Layout and Paint are performed based on this.
If any changes occur during this process, the browser must recalculate.
| Terminology | Description |
|---|---|
| Reflow (Layout) | Layout recalculation that occurs when an element's size or position changes. |
| Repaint | Repaint that occurs when only visual styles, such as color or background, change. |
In short, Reflow occurs when the structure changes, and Repaint occurs when the color changes.
🧩 For example:
<div id="box" style="width: 100px; height: 100px; background: red"></div>
<script>
const box = document.getElementById('box')
// 1️⃣ Reflow occurs
box.style.width = '200px' // Size or position change → Layout recalculation
// 2️⃣ Repaint occurs
box.style.backgroundColor = 'blue' // Color change → Only repaint
</script>In the above code, changing width causes both Reflow → Repaint.
However, changing only backgroundColor causes only Repaint.
Reflow is much more expensive than paint.
The browser must recalculate the layout of not only the changed element, but also all affected child and parent elements.
⚙️ Performance Impact
Reflow occurs more easily than you might think.
Here are some common situations that cause reflow:
| Cause | Explanation |
|---|---|
| DOM size changes | width, height, margin, padding, font-size, etc. |
| DOM structure changes | Adding/deleting nodes (appendChild, removeChild) |
| Position changes | top, left, position, display, etc. |
| Window size changes | resize event |
| Scroll/overflow changes | Layout reordering upon scrolling |
| Accessing offset, client, and scroll properties | Forces the browser to compute the latest layout |
If these changes become frequent, the browser must continuously repeat the Layout → Paint → Composite stages.
🔬 Common Practice Examples
1️⃣ Repeated DOM Manipulation
// ❌ Inefficient Method
for (let i = 0; i < 1000; i++) {
const el = document.createElement('div')
el.textContent = i
document.body.appendChild(el) // Causes a reflow every time
}This code causes 1000 reflows.
Because the browser recalculates the layout every time an element is appended.
✅ Solution: Add all at once using DocumentFragment
const frag = document.createDocumentFragment()
for (let i = 0; i < 1000; i++) {
const el = document.createElement('div')
el.textContent = i
frag.appendChild(el)
}
document.body.appendChild(frag) // Reflow only once2️⃣ Continuously changing style properties
// ❌ Multiple reflows
box.style.width = '200px'
box.style.height = '200px'
box.style.margin = '20px'✅ Solution: Use classList or CSS text Bundling
box.classList.add('expanded')
// or
box.style.cssText = 'width:200px;height:200px;margin:20px;'This allows the browser to refresh the rendering in one go.
3️⃣ Forced Reflow
This is something you really need to be careful about.
If the code that reads layout information and the code that modifies it are mixed, as shown below, the browser will force a reflow.
el.style.width = '200px'
console.log(el.offsetWidth) // 💥 Forced ReflowBecause when reading offsetWidth, the browser must ensure an "up-to-date layout,"
it will re-run all the calculations.
In other words, the "read-write-read" pattern is the enemy of performance.
🧠 Practical Optimization Tips
| Situation | Recommended Method |
|---|---|
| When multiple elements need to be modified | Process DocumentFragment / display:none and then make batch changes |
| When many style changes are required | Group and replace with a CSS class |
| Scroll and resize events | Control with Debounce / Throttle |
| Animation | Focus on transform and opacity properties (no reflow) |
| Avoiding forced reflow | Minimize access to offset and scroll properties |
Reflow can be reduced, but not completely eliminated.
However, understanding "when and why" it occurs can help prevent most performance issues.
⚡ CSS Tips for Avoiding Reflow
transformandopacitycan be animated without reflow.position: absoluteorfixedcan be used to reduce the scope of influence.will-changeprovides optimization hints to the browser in advance.containproperty ensures layout independence of child elements (CSS Containment).
You can check these properties in Chrome DevTools under the Rendering tab → “Paint flashing” option.
📊 Summary
| Category | Reflow | Repaint |
|------|--------|----------| | Trigger | When layout structure changes | When visual properties change |
| Cost | High | Medium |
| Trigger | Width, height, position, font-size, etc. | Color, background, etc. |
| Optimization Point | Minimize layout changes | Reduce unnecessary paints |
💬 In Conclusion
Reflow and repaint are invisible, but they directly impact browser performance.
Even if you use a virtual DOM like React or Vue, reflow is unavoidable when the real DOM update occurs at the final stage.
In other words, the virtual DOM is merely a "reflow reduction strategy," not a technology that eliminates it.
Understanding this difference and writing code accordingly will allow you to create much smoother and more efficient UIs.
Browsers are smarter than you think, but even small mistakes can be costly.
When writing code, always ask yourself, "Will this line cause a reflow?"
--
#Reflow #Repaint #BrowserRendering #RenderingPerformance #CSSPerformance #JavaScriptPerformance #WebOptimization #FrontEndPerformance #ReflowOptimization #VirtualDOM