Suggest an editImprove this articleRefine the answer for “Reflow and repaint”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Reflow (layout) is the recalculation of element geometry: sizes, positions and spacing; repaint (paint) is redrawing the visible pixels without recalculating geometry.** Reflow is triggered by anything that affects layout: `width`, `height`, `margin`, `padding`, `font-size`, adding or removing DOM nodes, changing text, resizing the window, and also reading layout properties such as `offsetWidth` right after writing a style (a forced synchronous layout). Repaint is triggered by purely visual changes: `color`, `background-color`, `box-shadow`, `outline`. Almost every reflow drags a repaint along with it, but not every repaint needs a reflow. The cheapest category, composite, covers `transform` and `opacity`, which the GPU handles without touching layout or paint. ```javascript element.style.width = '400px'; // reflow + repaint element.style.backgroundColor = 'red'; // repaint only element.style.transform = 'translateX(10px)'; // composite only ``` **Key point:** reflow is the most expensive of the three because the layout tree is connected and changing one element can force the whole document to be recalculated, so animate `transform` and `opacity` only.Shown above the full answer for quick recall.Answer (EN)Image**Reflow is the recalculation of the page geometry (layout), and repaint is redrawing the pixels of elements whose geometry is already known (paint).** When you change the DOM or CSS, the rendering engine (Blink in Chrome) has to recompute how the page looks, and that work splits into exactly these stages. ## Theory ### TL;DR - Reflow (layout): recalculating sizes, positions and spacing; repaint (paint): redrawing visible pixels without changing geometry. - Almost every reflow causes a repaint, but not every repaint needs a reflow. - Reflow is caused by `width`, `height`, `margin`, `padding`, `font-size`, adding and removing nodes, changing text, resize, scroll. - Repaint is caused by `color`, `background-color`, `box-shadow`, `outline`, `visibility`. - Reading `offsetWidth`, `clientHeight` or `getComputedStyle()` right after writing a style forces the browser into a synchronous layout (a forced reflow). - The cheapest path is composite: animate `transform` and `opacity` only, they bypass layout and paint. ### Quick example ```javascript const el = document.querySelector('.box'); el.style.width = '400px'; // reflow + repaint: geometry changed el.style.backgroundColor = 'red'; // repaint only: appearance changed el.style.transform = 'scale(1.1)'; // composite only, work for the GPU // The worst pattern: write, then immediately read a layout property el.style.width = '500px'; console.log(el.offsetHeight); // forced synchronous layout right here ``` ### What the browser does at each stage | Term | What it does | When it happens | | --- | --- | --- | | **Reflow (layout)** | Recalculates element geometry: sizes, positions, spacing, height, width | When the DOM structure or CSS that affects layout changes | | **Repaint (paint)** | Redraws the visible pixels (colors, background, shadows, borders) without recalculating geometry | When only the appearance changes, not the size or the position | Under the hood the sequence is this. **Reflow** forces the browser to: 1. Recalculate sizes and positions of elements (the layout tree). 2. Determine which regions of the screen have to be redrawn. 3. Run the repaint. **Repaint** fills in the changed pixels, and then composite glues the layers together. > Almost every `reflow` causes a `repaint`, but not every `repaint` requires a `reflow`. ### What triggers reflow and what triggers repaint Reflow is triggered by: - size changes: `width`, `height`, `padding`, `margin`, `border`, `font-size`; - adding or removing DOM elements; - changing text; - reading properties that depend on layout: `offsetWidth`, `clientHeight`, `getComputedStyle()`; - changing a class that affects positioning or sizes; - resizing the browser window; - scrolling. ```javascript element.style.width = '400px'; // reflow + repaint ``` Repaint is triggered by: - color changes: `color`, `background-color`; - opacity changes via `opacity`; - shadows `box-shadow`; - `outline`; - `visibility`, when the element stays in place. ```javascript element.style.backgroundColor = 'red'; // repaint only ``` ### Why reflow is dangerous for performance Reflow is one of the most expensive operations in the browser, especially when it touches many elements. - The layout tree is connected: changing one element can force the whole document to be recalculated. - A single reflow on a complex layout can take tens of milliseconds. Do it in a loop or very often and the interface starts to stutter. Reflow and repaint happen in the frame rendering phase, between the macrotasks and microtasks of the event loop. For a smooth animation you must fit into 16.6 ms per frame (60 FPS). If layout takes longer, frames are dropped and the user sees freezes. ### How to reduce the number of reflows and repaints | Approach | What it gives | | --- | --- | | **Batch updates** | Change several properties at once, through `classList` or `cssText`, instead of separate assignments | | **DocumentFragment** | Build DOM elements outside the document and insert everything in one go | | **Cache the measurements** | `const height = el.offsetHeight;` once before the loop, not inside it | | **Do not animate layout properties** | Avoid animating `width`, `height`, `top`, `left` | | **CSS transform and opacity** | GPU animations do not cause a reflow | | **requestAnimationFrame()** | For animations instead of `setInterval` | | **will-change** | Tells the browser in advance which properties will change so it can promote the element to its own layer | An example of bad code where reflow happens hundreds of times: ```javascript for (let i = 0; i < 100; i++) { const el = document.createElement('div'); document.body.appendChild(el); // reflow every time el.style.width = i + 'px'; // reflow console.log(el.offsetHeight); // forced reflow } ``` The optimized version with a single reflow: ```javascript const fragment = document.createDocumentFragment(); for (let i = 0; i < 100; i++) { const el = document.createElement('div'); el.style.width = i + 'px'; fragment.appendChild(el); } document.body.appendChild(fragment); // one reflow ``` ### Summary table | Term | What it does | Example | Impact | | --- | --- | --- | --- | | **Reflow (layout)** | Recalculation of geometry and positions | changing `width`, `margin`, adding DOM | expensive operation | | **Repaint (paint)** | Redrawing the appearance | changing `color`, `background`, `opacity` | moderately costly | | **Composite** | Gluing the layers after paint | `transform`, `opacity` | cheap, runs on the GPU | | **Goal** | Minimize reflow, animate only `transform` and `opacity` | | maximum FPS | ### Common mistakes | Mistake | What happens | | --- | --- | | Changing style repeatedly with separate assignments | A new reflow is triggered every time | | Reading `offsetHeight` right after changing a style | The browser is forced into a synchronous layout | | Changing classes inside a loop | A reflow on every iteration | | Animating properties that affect layout (`width`, `top`, `margin`) | Layout is recalculated on every frame | | Appending DOM elements one by one | Every insert causes a recalculation of the tree | Two more classics. People assume `opacity` is always free, but it is cheap only when the element is already promoted to its own compositing layer; otherwise a repaint still happens. And slapping `will-change` on everything backfires: every layer costs memory, so redundant layers hurt performance instead of helping it.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.