Skip to content
intermediatePhase 34 · DOM

Reflow

Learn what triggers reflow and how to minimize layout thrashing.

30m
0 problems
Topic Progress0%

What Triggers Reflow

Reflow (layout) happens when the browser recalculates the geometry of elements.

Reflow Triggers

// 1. Reading layout properties
element.offsetWidth;
element.offsetHeight;
element.offsetTop;
element.offsetLeft;
element.clientHeight;
element.clientWidth;
element.scrollHeight;
element.scrollWidth;
element.getBoundingClientRect();
window.getComputedStyle(element);
element.getBoundingClientRect();

// 2. Writing layout properties
element.style.width = '100px';
element.style.height = '100px';
element.style.top = '10px';
element.style.left = '10px';
element.style.margin = '10px';
element.style.padding = '10px';
element.style.border = '1px solid black';
element.style.position = 'absolute';
element.style.display = 'block';
element.style.fontSize = '16px';
element.style.float = 'left';
element.style.clear = 'both';
element.style.flexDirection = 'row';
element.style.gridTemplateColumns = '1fr 1fr';

// 3. DOM manipulation
document.body.offsetWidth; // Triggers reflow!

What Doesn't Trigger Reflow

// These only trigger paint, not layout:
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.boxShadow = '0 0 5px black';
element.style.opacity = '0.5';
element.style.visibility = 'hidden';
element.style.transform = 'translateX(100px)';
element.style.backgroundImage = 'url(...)';
element.textContent = 'New text'; // May trigger if width changes

Reflow is Expensive

// Reflow affects:
// 1. The element itself
// 2. Its children
// 3. Its parents
// 4. Its siblings
// 5. Any elements that depend on it

// Example: changing width of body triggers reflow of everything

Layout Thrashing

Layout thrashing occurs when you force the browser to recalculate layout multiple times.

The Problem

// BAD: Alternating reads and writes
const elements = document.querySelectorAll('.item');

// This forces a reflow on EACH iteration!
for (let i = 0; i < elements.length; i++) {
  elements[i].style.width = `${elements[i].offsetWidth + 10}px`; // Read + Write
}

Why It's Bad

// 1. Read offsetWidth → triggers layout
// 2. Write style.width → invalidates layout
// 3. Read offsetWidth → triggers NEW layout
// 4. Write style.width → invalidates layout
// ... repeat 1000 times = 1000 layouts!

Solution: Batch Operations

// GOOD: Batch reads, then batch writes
const elements = document.querySelectorAll('.item');

// Read phase
const widths = Array.from(elements).map(el => el.offsetWidth);

// Write phase
for (let i = 0; i < elements.length; i++) {
  elements[i].style.width = `${widths[i] + 10}px`;
}
// Single reflow!

More Examples

// BAD
document.body.appendChild(newDiv);
const height = newDiv.offsetHeight; // Forces layout
document.body.appendChild(anotherDiv);
const width = anotherDiv.offsetWidth; // Forces layout

// GOOD
const fragment = document.createDocumentFragment();
fragment.appendChild(newDiv);
fragment.appendChild(anotherDiv);
document.body.appendChild(fragment); // Single reflow
const height = newDiv.offsetHeight; // Read after all writes
const width = anotherDiv.offsetWidth;

// BAD
element.style.width = '100px';
console.log(element.offsetWidth); // Forces layout
console.log(element.offsetHeight); // Forces layout

// GOOD
element.style.width = '100px';
element.style.height = '100px';
// Now read
console.log(element.offsetWidth, element.offsetHeight); // One layout

Detection

// Chrome DevTools: Performance tab
// 1. Record performance
// 2. Look for 'Layout' events
// 3. Check for 'Forced synchronous layout' warning

// Chrome DevTools: Rendering tab
// - Enable 'Layout boundaries' to see elements triggering layout

Optimization

Strategies to minimize reflows in your code.

Use CSS Classes

// BAD: Multiple style changes
element.style.width = '100px';
element.style.height = '100px';
element.style.margin = '10px';
element.style.padding = '5px';
element.style.display = 'block';

// GOOD: Single class change
element.classList.add('expanded');

/* CSS handles the rest */
.expanded {
  width: 100px;
  height: 100px;
  margin: 10px;
  padding: 5px;
  display: block;
}

Use DocumentFragment

// BAD: Multiple DOM additions
for (let i = 0; i < 100; i++) {
  const li = document.createElement('li');
  li.textContent = `Item ${i}`;
  list.appendChild(li); // Reflow each time!
}

// GOOD: Fragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  const li = document.createElement('li');
  li.textContent = `Item ${i}`;
  fragment.appendChild(li);
}
list.appendChild(fragment); // Single reflow

Avoid Triggering Reflow

// BAD: Reading layout in loop
for (let i = 0; i < 100; i++) {
  const width = element.offsetWidth; // Triggers layout!
  element.style.width = `${width + 1}px`;
}

// GOOD: Read once
const width = element.offsetWidth;
for (let i = 0; i < 100; i++) {
  element.style.width = `${width + i}px`;
}

Use transform for Animations

// BAD: Triggers layout
element.style.left = '100px';
element.style.top = '100px';

// GOOD: Compositor only
inelement.style.transform = 'translate(100px, 100px)';

// Or use CSS animation
.element {
  transition: transform 0.3s ease;
}
.element.moved {
  transform: translate(100px, 100px);
}

Debounce Resize Handlers

// BAD: Fires many times during resize
window.addEventListener('resize', () => {
  recalculateLayout(); // Reflow!
});

// GOOD: Debounce
window.addEventListener('resize', debounce(() => {
  recalculateLayout();
}, 100));

Use will-change Wisely

/* Promote to compositor layer */
.animated {
  will-change: transform;
}

/* Don't overuse - each layer uses memory */
.animated:hover {
  will-change: transform; /* Bad! */
}

Practice Problems

0/3solved
Build Reflow Component

Create a reusable React component implementing Reflow. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Reflow Testing

Write unit and integration tests for Reflow using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Reflow Performance

Optimize Reflow for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What triggers a reflow?

Question 1 options

2. What is layout thrashing?

Question 2 options

3. How do you avoid layout thrashing?

Question 3 options

4. Which property is better for animations?

Question 4 options

Flashcards

Question

What triggers reflow?

Answer

Geometry changes: width, height, position, margins, padding, borders, display, font-size, etc.

Question

What is layout thrashing?

Answer

Alternating DOM reads and writes that force the browser to recalculate layout multiple times.

Question

How to avoid layout thrashing?

Answer

Batch all reads together, then all writes. Don't alternate between reading and writing layout properties.

Question

What properties don't trigger reflow?

Answer

color, opacity, visibility, transform, box-shadow, background-image - these only trigger paint.

Question

What is Reflow?

Answer

Reflow is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Reflow is triggered by geometry changes (width, height, position)
  • 2.Layout thrashing forces multiple reflows - avoid it
  • 3.Batch DOM reads and writes to minimize reflows
  • 4.Use transform instead of top/left for animations
  • 5.CSS classes are more performant than inline styles

Interview Tips

  • Explain what triggers reflow vs paint
  • Show how to identify and fix layout thrashing
  • Demonstrate batching DOM operations
  • Explain why transform is better than top/left for animations

Cheat Sheet

Reflow Cheat Sheet

What is Reflow?

Browser recalculates geometry of elements. Expensive operation.

Reflow Triggers

  • Reading: offsetWidth, clientHeight, getBoundingClientRect()
  • Writing: width, height, position, margin, padding
  • DOM: appendChild, removeChild, offsetWidth read

Layout Thrashing

Alternating reads and writes forces multiple reflows.

Prevention

  1. Batch reads, then writes
  2. Use CSS classes instead of inline styles
  3. Use DocumentFragment for batch updates
  4. Use transform for animations
  5. Debounce resize handlers

transform vs top/left

  • transform: composite only (fast)
  • top/left: triggers layout (slow)