This page is not available in every language. Missing translations are disabled in the language selector.

Quick reference

Layout Thrashing & Forced Reflow Cheatsheet

A comprehensive reference guide for layout thrashing and forced reflow: DOM element properties, mouse events, window methods, and jQuery triggers that degrade rendering performance.

· Published

Layout thrashing (also known as forced synchronous layout or forced reflow) occurs when JavaScript repeatedly alternates between writing to the DOM and reading layout properties, forcing the browser to recalculate the page layout synchronously.

Layout Invalidation Triggers

The following DOM properties and methods force synchronous recalculation of computed geometry whenever the layout has been invalidated by earlier DOM mutations.

Element Properties & Methods

Box Geometry & Dimensions

  • clientHeight, clientWidth
  • clientLeft, clientTop
  • offsetHeight, offsetWidth
  • offsetLeft, offsetTop
  • offsetParent
  • scrollHeight, scrollWidth
  • scrollLeft, scrollTop

Querying Bounding Boxes

  • getBoundingClientRect()
  • getClientRects()

Scroll Actions

  • scrollIntoView()
  • scrollIntoViewIfNeeded()
  • scrollByLines()
  • scrollByPages()

Text & Focus

  • innerText
  • outerText
  • focus() (forces focus ring and scroll adjustments)

Mouse Event Properties

Querying specific coordinates on a MouseEvent instance can trigger layout computation in certain browser engines:

  • layerX, layerY
  • offsetX, offsetY

Window Methods & Properties

  • window.getComputedStyle() (when querying layout-dependent values such as width, height, margin, or transform)
  • window.scrollBy()
  • window.scrollTo()
  • window.scrollX, window.scrollY

Frame, Document & Image

  • Querying width or height on an image before layout stabilizes
  • Accessing document.body.scrollHeight

jQuery Operations

Many jQuery helper methods read computed layout values under the hood:

// Triggers reflow
$(elem).offset();
$(elem).offsetParent();
$(elem).position();
$(elem).scrollLeft();
$(elem).scrollTop();
$(elem).css('width');  // Any layout-dependent style calculation
$(elem).text();

// Pseudo-selectors that inspect geometric visibility
$(':hidden');
$(':visible');
$(':contains');

Best Practices to Prevent Layout Thrashing

1. Batch Reads and Writes

Always perform all DOM measurements first, then batch all DOM mutations together.

// BAD: Interleaved read and write causes forced layout per iteration
elements.forEach((el) => {
  const width = el.clientWidth; // READ (forces layout)
  el.style.width = width * 2 + 'px'; // WRITE (invalidates layout)
});

// GOOD: Batch reads, then batch writes
const widths = elements.map((el) => el.clientWidth); // BATCH READ
elements.forEach((el, index) => {
  el.style.width = widths[index] * 2 + 'px'; // BATCH WRITE
});

2. Use requestAnimationFrame

Schedule style writes in the next animation frame to let the browser optimize the render cycle:

const height = element.clientHeight; // Read during current phase

window.requestAnimationFrame(() => {
  element.style.height = height + 50 + 'px'; // Write in next frame
});

3. Use CSS Transforms & Opacity

Prefer animating CSS properties handled on the compositor thread (transform, opacity) instead of layout properties (top, left, width, height).


References

Related topics