The browser is a wondrous thing. We give it JS, HTML and CSS – and they are translated into visual wonders. It does it by running the same rendering cycle again and again. Sometimes, something in the cycle can go wrong. Layout reflow is one of those things.
I wrote about the Critical Rendering Path (CRP) in a former article. Here’s an egghead video that shows it in the browser. In a nutshell, the regular flow of the code in the browser is this:
A reflow looks more like this:
How does it happen and how can you avoid it?
When you query the DOM for size or position, the result is usually taken from former calculations. The browser knows how the DOM looks like, and if it knows it didn’t change, it just gets the correct value from the layout cache (created in the former calculation).
|Querying the DOM is called: Measure.|
Now, let’s assume you are changing the DOM. Appending elements, changing height/width or position of elements etc.
|Changing the DOM is called: Mutate.|
After you are changing the DOM, the browser flags its layout cache as invalid and schedules a recalculation. If you measure the size or position of an element at this stage, the browser needs to recalculate the whole DOM in order to give you the real answer.
element.style('height', 500); console.log(element.style('height'));
For instance, in the code above, we change the height of an element and then query its height.
Understanding by Touching
In this exercise you will see an example for reflow and how it looks in the DOM.
- Clone the following repository: https://github.com/YonatanKra/performanceWorkshop
git clone https://github.com/YonatanKra/performanceWorkshop
- Type: checkout layout-reflow-1
- Run yarn or npm i
- Run yarn demo or npm run demo
- Open the app in the browser: http://localhost:3000
- Query the server (just use the input field at the top)
- Start monitoring
- Click the sorting buttons
- Stop the recording
A short TL;DC (too long, didn’t clone) – the app queries a list of users from a server. It then allows you to sort the users by their ID or name.
Here’s the result of the sorting scenario described above:
Let’s compare it to the CRP recording of a reflow-free code:
The reflow in Figure 3 happens because a simple line that was added to the code. In the data-table.component.js file:
Line 40 in the code snippet #1 emits an event when we finish loading the data. Inside, it measures the DOM and sends the updated scrollHeight (line 41). Innocent product demand, right?
Layout reflow happens when we measure the DOM after we mutate it. It has severe performance implications and should be avoided as much as possible.
If watching short videos fits you, I’ve created several Egghead videos about the subject including solutions for layout reflow usecases. Each video is around 1-2 minutes, so you can definitely just check 🙂
Thanks a lot for Hod Bauer for his thorough review of this article!