DEV Community

Alexandra
Alexandra

Posted on

Repaint vs Reflow: A Simple Explanation

What's happening when a website loads?

When you visit a website, your browser reads the code, it creates the DOM, it reads the CSS, it builds the CSSOM, figures out where everything should go, and then draws it on your screen. This process includes two main concepts: repaint and reflow.

What is a repaint?

A repaint happens when you change the appearance of an element, but NOT the sizes or positions. Think it as changing a text or background color, opacity, borders or box shadows.

element.style.color = "blue";
element.style.backgroundColor = "yellow";
Enter fullscreen mode Exit fullscreen mode

When this happens, the browser just needs to redraw the pixels on screen. In general, this is somewhat fast.

What is a reflow?

A reflow (or "layout") happens when you change the size or position of an element. Think about it as a result of changing width, height, padding or margins, adding or removing elements from the page, showing/hiding elements with display property, or changing the font size.

newElement.style.width = "500px";
newElement.style.padding = "20px";
document.body.appendChild(newElement);
Enter fullscreen mode Exit fullscreen mode

When this happens, the browser has to:

  1. Recalculate where everything should be
  2. Figure out the new size of elements
  3. Update all the affected elements
  4. THEN repaint everything

That's why reflows are a bit expensive.

Why Should We Care?

Both repaints and reflows make the browser do work, which can make your website feel slow, especially when you trigger them often.

Imagine you're building a feature that updates a user's score:

for (let i = 0; i < 100; i++) {
  element.style.width = (100 + i) + "px";  // Reflow!
  element.textContent = i;                  // Reflow!
}
Enter fullscreen mode Exit fullscreen mode

Every loop iteration triggers a reflow because we're changing the width and content. That's 100+ potential reflows! Modern browsers do batch some of these automatically, but you still want to minimize layout recalculations.

element.textContent = 99;
element.style.width = "199px";
Enter fullscreen mode Exit fullscreen mode

Prefer to do all the changes at once. The browser will likely batch these into a single reflow cycle instead of triggering multiple sequential ones.

Tips to Avoid Performance Problems

  1. Batch your changes
   // Good
   element.style.cssText = "width: 100px; height: 100px; color: red;";

   // Not as good
   element.style.width = "100px";
   element.style.height = "100px";
   element.style.color = "red";
Enter fullscreen mode Exit fullscreen mode
  1. Avoid reading layout properties in loops
  // Bad — alternating reads and writes force recalculation
for (let i = 0; i < elements.length; i++) {
  const currentWidth = elements[i].offsetWidth;  // READ — forces layout recalculation
  elements[i].style.width = (currentWidth + 10) + "px";  // WRITE — invalidates layout
}

// Good — batch all reads first, then writes
const widths = Array.from(elements).map(el => el.offsetWidth);
widths.forEach((width, i) => {
  elements[i].style.width = (width + 10) + "px";
});
Enter fullscreen mode Exit fullscreen mode
  1. Use classes instead of inline styles (similar with 1)
   // Good — batches all CSS changes together and is more maintainable
element.classList.add("highlighted");

// Not as good — multiple individual property assignments can trigger separate reflows
element.style.color = "blue";
element.style.backgroundColor = "yellow";
element.style.fontWeight = "bold";
Enter fullscreen mode Exit fullscreen mode

CSS classes batch multiple properties into a single reflow cycle, and keep your styling logic separate from your JavaScript.

  1. Use transforms for animations
   // Good for animations
   element.style.transform = "translateX(100px)";

   // Causes reflow
   element.style.left = "100px";
Enter fullscreen mode Exit fullscreen mode

Transforms are cheaper because they skip the Layout and Paint phases of the rendering pipeline and only trigger Composite (which happens on the GPU). Position changes like left, top, width, and height require the browser to recalculate the entire layout.

  1. Use requestAnimationFrame for Coordinated Updates

When you need to perform multiple DOM reads and writes in animations, use requestAnimationFrame to ensure they're batched together in the browser's rendering cycle:

// Good — batches all changes into one frame
requestAnimationFrame(() => {
  elements.forEach(el => {
    el.style.transform = "translateX(100px)";
  });
});

// Less efficient — each update happens immediately, may cause multiple recalculations
elements.forEach(el => {
  el.style.transform = "translateX(100px)";
});
Enter fullscreen mode Exit fullscreen mode

Modern Browser Considerations

Browsers have become smarter about batching DOM operations. Modern engines like V8 (Chrome) and SpiderMonkey (Firefox) automatically defer and batch layout recalculations to some degree. However, this doesn't mean poor practices are harmless, you can still force synchronous reflows by reading layout properties like offsetWidth, clientHeight, or getBoundingClientRect() immediately after writing styles. Avoiding these patterns ensures your code stays performant across all browsers and circumstances.

The Bottom Line

☑️ Repaint = Change colors/appearance → relatively fast
☑️ Reflow = Change size/position/layout → slower, more expensive
☑️ Both slow down your site if you do too many
☑️ Group changes together when possible
☑️ Use CSS transforms for animations

Next time a website feels slow, there's a good chance it's because the browser is constantly doing reflows and repaints.

Further Reading

Top comments (0)