1. What is Layout Thrashing (one sentence version)
In a JS execution, repeatedly alternate "write style → read layout", Forcing the browser to continuously synchronize the calculation of layout, resulting in a sharp decline in performance.
Keywords:
- ❌ Repeat Layout
- ❌ Synchronous blocking
- ❌ FPS plummets
2. The most typical Layout Thrashing code
for (let i = 0; i < 1000; i++) {
el.style.width = el.offsetWidth + 1 + 'px'
}It seems harmless, but what actually happened?
写 width → 布局脏了
读 offsetWidth → 强制 Layout
写 width → 布局脏了
读 offsetWidth → 强制 Layout
……👉 Repeated reads/writes can force Layout; the count depends on invalidation and browser optimization.
3. Why is this happening?(Underlying principles of browser)
1️⃣ Browser’s “lazy layout strategy”
The browser will not re-layout every time the style is changed:
Modify style → mark dirty
until:
- to render
- Or JS reads layout information
2️⃣ Which operations will "force synchronization of Layout"?
📏 Read geometric information (must memorize)
offsetWidth / offsetHeight
offsetTop / offsetLeft
clientWidth / clientHeight
scrollTop / scrollHeight
getComputedStyle()
getBoundingClientRect()Read these:
The browser must figure out the real layout immediately
4. DevTools in practice: See Layout Thrashing with your own eyes
1️⃣ Use this Demo
<button id="btn">Run</button>
<div id="box" style="width:100px;height:100px;background:red"></div>
<script>
const box = document.getElementById('box')
btn.onclick = () => {
for (let i = 0; i < 300; i++) {
box.style.width = box.offsetWidth + 1 + 'px'
}
}
</script>2️⃣Performance panel analysis
You will see:
Task
├── Function Call
│ ├── offsetWidth
│ ├── Layout
│ ├── offsetWidth
│ ├── Layout
│ ├── ...📌 Yellow JS + Purple Layout appear alternately
👉 This is the ironclad proof of Layout Thrashing
5. How to solve it?(Engineering level solution)
✅ Solution 1: Separation of reading and writing (the most important)
let width = box.offsetWidth
for (let i = 0; i < 300; i++) {
width += 1
}
box.style.width = width + 'px'👉 Separating reads/writes reduces repeated layout without guaranteeing exactly one Layout.
✅ Solution 2: Batch writing (DOM batch processing)
box.style.cssText += 'width:200px;height:200px'✅ Option 3: Use transform instead of layout attributes
// ❌
box.style.left = '200px'
// ✅
box.style.transform = 'translateX(200px)'✔️ Transforms can reduce Layout/Paint with reusable layers; verify actual behavior.
✅ Solution 4: requestAnimationFrame scheduling
let width = box.offsetWidth
function step() {
width += 1
box.style.width = width + 'px'
requestAnimationFrame(step)
}
step()📌 Spread multiple modifications to multiple frames
✅ Solution 5: Virtual DOM/batch update
This is one of the reasons why React/Vue is fast:
多次 setState
↓
合并
↓
一次真实 DOM 更新6. Advanced: How does the browser "account"?
Browser internal maintenance:
- Style dirty
- Layout dirty
- Paint dirty
Only if necessary:
- Style Recalc
- Layout
- Paint
👉 JS read layout = forced clearing
7. High-frequency interview questions
Q: What is Layout Thrashing?
During JS execution, layout information and styles are frequently read and modified alternately. As a result, the browser is forced to execute Layout multiple times synchronously, seriously affecting performance.
Q: How to avoid it?
- Read and write separation
- Merge DOM operations
- Use transform
- Using rAF (requestAnimationFrame)
- Using the framework’s batch update mechanism