Skip to content
Created: November 20, 2022

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 ​

js
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) ​

js
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 ​

html
<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) ​

js
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) ​

js
box.style.cssText += 'width:200px;height:200px'

✅ Option 3: Use transform instead of layout attributes ​

js
// ❌
box.style.left = '200px'

// ✅
box.style.transform = 'translateX(200px)'

✔️ Transforms can reduce Layout/Paint with reusable layers; verify actual behavior.

✅ Solution 4: requestAnimationFrame scheduling ​

js
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