Mastering the Browser Performance: Reducing Reflows and Repaints
Reflows and repaints are among the most performance-hindering operations in a browser. This article dives into the intricate details of these two phenomena, demonstrates how to detect and reduce them, and presents real-world case studies that have successfully mitigated their impact.
Mastering the Browser Performance: Reducing Reflows and Repaints
Even after optimizing your bundle and API, your application's user interface (UI) may still exhibit lag, stutter, or a heavy feel. This sluggish behavior might not be due to JavaScript but rather the browser itself overworking — recalculating layout and repainting excessively.
These operations are known as reflows and repaints, and they’re some of the most computationally expensive tasks a browser performs. This article elucidates what reflows and repaints are, the conditions that trigger them, how to detect and reduce them, what causes layout thrashing, and best practices gleaned from real-world solutions.
Reflows: The Backdrop
A reflow, also known as a layout, occurs when the browser recalculates the geometry of the webpage. This encompasses the positions of elements, their widths and heights, box models, and stacking order. Modifications to the Document Object Model (DOM) size or position frequently instigate reflows.
Demystifying Repaints
On the other hand, a repaint occurs when parts of the screen are redrawn following a style change. These alterations can include color changes, shadows, and visibility. Although repainting is less costly than a reflow, it still demands significant resources, especially when dealing with large surfaces.
Triggers for Reflows
Several actions can trigger a reflow. These include:
- The addition or removal of DOM nodes
- Changes to styles that affect layout (e.g.,
display
,height
,margin
) - Calls to measurement APIs such as
offsetHeight
andgetBoundingClientRect
- Animation of properties that necessitate layout recalculations
Detecting Reflows and Repaints
To identify reflows and repaints, use Chrome DevTools' Performance tab to record interactions. Look for events like "Recalculate Style", "Layout", "Paint", and "Composite Layers". The Paint Flashing tool in the Rendering panel visualizes repaints.
Furthermore, you can use console.time()
to measure the execution time of critical paths. For instance:
console.time("layout");
element.offsetHeight;
console.timeEnd("layout");
The above code times how long it takes to calculate element.offsetHeight
.
Techniques to Mitigate Layout Thrashing
Read, then Write
Interleaving reading and writing operations can cause layout thrashing. Consider the following example:
el.style.width = "100px";
const h = el.offsetHeight;
el.style.border = "1px solid red";
In the above code, a write operation (el.style.width = "100px"
), followed by a read operation (const h = el.offsetHeight
), and then another write operation (el.style.border = "1px solid red"
) results in reflows.
A better approach is to bundle all read operations before write operations, as shown below:
const h = el.offsetHeight;
el.style.width = "100px";
el.style.border = "1px solid red";
Avoiding Layout-Affecting Animations
Animations that affect layout should be avoided. For instance, instead of animating properties like height
, animate properties like transform
:
transition: transform 0.3s;
Properties such as transform
and opacity
are GPU-accelerated and don't necessitate layout recalculations.
Utilizing CSS Containment
CSS Containment can help improve performance in dynamic UIs. It instructs the browser not to reflow beyond the defined boundary:
.card {
contain: layout paint;
}
Leveraging Virtualization
For large lists, virtualization techniques can be beneficial. They prevent the DOM from growing unbounded, which would otherwise increase the reflow cost for each frame. Libraries like react-window
and react-virtual
, or using intersection observers, can aid in implementing virtualization.
Anti-Patterns to Avoid
Several practices can exacerbate reflows and repaints. These include:
- Animating
width
,height
,top
,left
- Reading layout in the middle of an animation
- Manipulating the DOM inside
requestAnimationFrame
with layout reads - Synchronous style reads in scroll/resize handlers
Conclusion: Don’t Let Layout Be Your Bottleneck
Reflows and repaints are expensive — not just in CPU cycles, but in perceived fluidity. Users perceive them as jank, lag, or dropped frames. Therefore, to ensure a smooth and responsive UI, it is crucial to keep layout operations predictable and contained.
While it is impossible to avoid reflows entirely, with careful planning and good practices, you can certainly prevent them from disrupting your application's performance.
Subscribe for Deep Dives
Get exclusive in-depth technical articles and insights directly to your inbox.
Related Posts
In-depth Exploration of Performance API: Precision Metrics from the Browser
The Performance API offers refined, high-resolution timing data directly from the browser. This guide offers a deep dive into how to harness Navigation Timing, Resource Timing, and more to track user performance with accuracy.
Application Performance Monitoring (APM): Achieving Full-Stack Visibility
Exploring Application Performance Monitoring (APM) tools and how they provide end-to-end visibility into your stack, helping to trace performance, identify bottlenecks, and understand system behavior.
Real User Monitoring (RUM): A Comprehensive Guide to Measuring User Experiences in the Field
This article delves into the depth of Real User Monitoring (RUM), elucidating its significance, how it deviates from synthetic monitoring, its implementation, and applicable metrics. We'll also discuss its integration with modern web performance, providing a broad spectrum of understanding for seasoned developers.