The browser rendering process can be divided into seven stages:
1. HTML Parsing
After receiving the HTML document from the server response, the browser first parses the HTML document to build a DOM tree. The DOM tree consists of DOM elements and attribute nodes, with the document object as the root of the tree.
2. Style Calculation
The browser parses CSS files and inline styles on elements to calculate the styles of DOM nodes. This process includes:
- Converting CSS into a structure that the browser can understand
- Calculating the specific styles of DOM nodes
3. Layout
The layout phase calculates the geometric positions of visible elements in the DOM tree, a process called layout or reflow.
4. Layering
The browser divides the DOM tree into multiple layers based on the layout. This process is mainly to handle complex effects in the page, such as 3D transformations and page scrolling.
5. Painting
Based on the layers, the browser generates a paint list for each layer and submits it to the compositing thread.
6. Tiling
The compositing thread divides the layers into tiles, which are typically 256x256 or 512x512 in size.
7. Rasterization
The compositing thread prioritizes generating bitmaps for tiles near the viewport, a process called rasterization. During rasterization, tiles are converted into bitmaps.
Reflow and Repaint
Reflow
When our modifications to the DOM cause changes in the geometric dimensions of DOM elements (such as modifying the width, height, or hiding elements), the browser needs to recalculate the geometric properties of the elements and then draw the results. This process is called reflow (also known as relayout).
Operations that trigger reflow include:
- Initial page rendering
- Changes in browser window size
- Changes in element dimensions or position
- Changes in element content (such as text quantity or image size)
- Changes in element font size
- Adding or removing visible DOM elements
- Activating CSS pseudo-classes (e.g., :hover)
- Querying certain properties or calling certain methods
Some commonly used properties and methods that cause reflow:
- clientWidth, clientHeight, clientTop, clientLeft
- offsetWidth, offsetHeight, offsetTop, offsetLeft
- scrollWidth, scrollHeight, scrollTop, scrollLeft
- scrollIntoView(), scrollIntoViewIfNeeded()
- getComputedStyle()
- getBoundingClientRect()
- scrollTo()
Repaint
When our modifications to the DOM cause style changes but do not affect its geometric properties (such as modifying color or background color), the browser does not need to recalculate the geometric properties of the element and directly draws the new style for the element. This process is called repaint.
Compared to reflow, repaint has a smaller performance overhead because repaint only redraws the appearance of the element without recalculating the position of the element.
Why Transform is Efficient
Transform is implemented by creating a new composite layer, which is drawn separately and then composited with other layers. This way, when we use transform for transformations, only this composite layer needs to be redrawn, not the entire page.
Using transform can avoid reflow and repaint because it does not affect the layout of the DOM, only the final rendering result. This is why using transform for animations is more efficient than directly modifying properties like top and left of elements.
Optimization Strategies
To reduce reflow and repaint, we can adopt the following strategies:
-
Batch DOM modifications: Use DocumentFragment or first set the element to display: none, then make multiple modifications, and finally display it.
-
Avoid frequent reading of properties that trigger reflow/repaint: If you must read multiple times, cache the values.
-
Use transform and opacity for animation effects: These two properties do not trigger reflow.
-
Use the will-change property: This property can inform the browser in advance of changes that will occur to the element, allowing the browser to prepare optimization work.
-
Use absolute or fixed positioning: Elements with absolute or fixed positioning only affect themselves when changed, not other elements.
By understanding browser rendering principles and optimization strategies, we can write more efficient frontend code and improve user experience.