Understanding the Browser Rendering Pipeline: From DOM to Pixels ๐
A beginner-friendly look at DOM, CSSOM, Render Tree, Layout, Paint, Compositing, Critical Rendering Path, and Layout Thrashing.
Introduction
While working on my Week 2 frontend tasks in my training, I wanted to understand what actually happens inside the browser when we load a webpage.
I had heard terms like DOM, CSSOM, reflow, repaint, and compositing, but I didn't fully understand how they were connected.
So I decided to learn the browser rendering pipeline and use Chrome DevTools Performance to see some of these concepts in practice.This post covers what I learned and the small experiment I performed on layout thrashing.
๐ What I Learned
In this learning session, I covered:
- DOM Construction
- CSSOM Construction
- Render Tree
- Style Calculation
- Layout / Reflow
- Paint / Repaint
- Compositing
- Critical Rendering Path
- Layout Thrashing
- Batching DOM Reads and Writes
- Chrome DevTools Performance
๐ Browser Rendering Pipeline
At a high level, the browser goes through something like this:
HTML
โ
DOM
โ
CSS
โ
CSSOM
โ
Style Calculation
โ
Render Tree
โ
Layout
โ
Paint
โ
Compositing
โ
Screen
Let's understand each stage.
Let's understand each stage.
1๏ธโฃ DOM Construction
DOM stands for Document Object Model.
When the browser receives HTML, it parses it and creates a tree-like structure.
For example:
<body>
<h1>Hello</h1>
<p>Welcome</p>
</body>
The browser creates something conceptually like:
Document
โโโ html
โโโ body
โโโ h1
โโโ p
This is the DOM tree.
Simple way to remember
DOM = What elements exist?
2๏ธโฃ CSSOM Construction
CSSOM stands for CSS Object Model.
The browser also parses CSS and creates a representation of the CSS rules.
For example:
h1 {
color: blue;
font-size: 32px;
}
p {
color: gray;
}
The CSSOM helps the browser understand how the elements should be styled.
Simple way to remember
DOM โ What exists?
CSSOM โ How should it look?
3๏ธโฃ Style Calculation
Now the browser needs to figure out which styles actually apply to each element.
It considers things such as:
- CSS selectors
- Cascade
- Specificity
- Inheritance
- Browser default styles
- Media queries
- CSS variables For example:
p {
color: red;
}
.article p {
color: blue;
}
4๏ธโฃ Render Tree
The browser combines the DOM and CSSOM to determine what actually needs to be rendered.
DOM + CSSOM
โ
Style Calculation
โ
Render Tree
The Render Tree isn't exactly the same as the DOM.
For example:
.hidden {
display: none;
}
The element still exists in the DOM, but it doesn't participate in the normal rendered layout.
Simple way to remember
Render Tree = What actually participates in rendering?
5๏ธโฃ Layout / Reflow
Once the browser knows what needs to be rendered, it needs to calculate the size and position of the elements.
This is the Layout stage.
It calculates things like:
- Width
- Height
- Position
- Margin
- Padding
- Text positioning For example:
.card {
width: 300px;
height: 200px;
}
The browser needs to calculate where the card is and how much space it occupies.
Simple way to remember
Layout = Where is everything and how big is it?
Layout is also commonly referred to as reflow.
6๏ธโฃ Paint / Repaint
After calculating the layout, the browser needs to draw the page.
This is the Paint stage.
Paint deals with things such as:
- Text
- Backgrounds
- Borders
- Images
- Shadows
- Gradients For example:
.card {
background: white;
border: 1px solid #ddd;
box-shadow: 0 4px 10px gray;
}
These visual details need to be painted.
Simple way to remember
Paint = Draw what the user should see.
If something visual changes, the browser may need to paint that area again. This is commonly called a repaint.
7๏ธโฃ Compositing
After painting, the browser may have different painted surfaces or layers that need to be combined.
That's where Compositing comes in.
Layer 1
+
Layer 2
+
Layer 3
โ
Compositing
โ
Screen
Properties such as:
transform
opacity
can often be handled efficiently by the compositor.
This is one reason these properties are commonly used for animations.
For example:
.box {
transform: translateX(100px);
}
8๏ธโฃ Critical Rendering Path
Now we can put everything together.
The simplified Critical Rendering Path looks like this:
HTML
โ
DOM
CSS
โ
CSSOM
DOM + CSSOM
โ
Style Calculation
โ
Render Tree
โ
Layout
โ
Paint
โ
Compositing
โ
Screen
JavaScript can modify the DOM or CSS, which may cause parts of this process to run again.
This is where frontend performance becomes important.
๐งช Practical Experiment With Chrome DevTools
Learning the theory was useful, but I wanted to actually see what was happening.
So I used my Week 2 responsive landing page and opened:
Chrome DevTools
โ Performance
I recorded the page load and inspected the Main thread.
I found rendering-related activities such as:
Recalculate Style
Layout
Paint
Composite / Commit
This helped me connect the theory with what the browser was actually doing.
Instead of just reading:
"The browser performs layout and paint."
I could actually see rendering activity in DevTools.
๐ฅ Layout Thrashing Experiment
The most interesting part of the experiment was layout thrashing.
I created a simple page with multiple boxes and used JavaScript to change their height and immediately read their height.
for (const box of boxes) {
box.style.height = "100px";
console.log(box.offsetHeight);
}
Here:
box.style.height = "100px";
is a write because I'm changing the style.
And:
box.offsetHeight
is a layout read because I'm asking the browser for the current height.
So the pattern becomes:
WRITE
โ
READ
โ
WRITE
โ
READ
When layout has been invalidated, reading layout information such as offsetHeight can require the browser to synchronously update layout.
Doing this repeatedly can lead to layout thrashing.
๐ค Why Is offsetHeight Important?
Some properties require the browser to provide up-to-date layout information.
Examples include:
element.offsetWidth
element.offsetHeight
element.clientWidth
element.clientHeight
element.getBoundingClientRect()
If we've just changed something that affects layout and then immediately request one of these values, the browser may need to perform layout work before returning the result.
โ The Problem: Layout Thrashing
The problematic pattern is:
for (const box of boxes) {
box.style.height = "100px";
console.log(box.offsetHeight);
}
Conceptually:
WRITE โ READ
WRITE โ READ
WRITE โ READ
This can cause unnecessary synchronous layout work
โ Fixing Layout Thrashing
The basic solution is to separate reads and writes.
Instead of:
WRITE โ READ
WRITE โ READ
WRITE โ READ
we can do:
READ
READ
READ
โ
WRITE
WRITE
WRITE
The optimized version:
// READ
for (const box of boxes) {
console.log(box.offsetHeight);
}
// WRITE
for (const box of boxes) {
box.style.height = "100px";
}
This gives the browser a better opportunity to batch the rendering work.
๐ Before vs After
โ Before
for (const box of boxes) {
box.style.height = "100px";
console.log(box.offsetHeight);
}
Pattern:
WRITE โ READ
WRITE โ READ
WRITE โ READ
โ After
for (const box of boxes) {
console.log(box.offsetHeight);
}
for (const box of boxes) {
box.style.height = "100px";
}
Pattern:
READ
READ
READ
โ
WRITE
WRITE
WRITE
๐ What I Observed in DevTools
I recorded both versions using the Performance panel.
I was able to inspect:
- JavaScript execution
- Recalculate Style
- Layout activity
- Paint
-
Compositing / Commit
One thing I learned during the experiment is that Chrome is heavily optimized, so we shouldn't expect to see one separate
Layoutevent for every single operation. The important part was understanding why alternating layout writes and reads can cause synchronous rendering work. --- # ๐ก Key Takeaways | Concept | What I learned | | --- | --- | | DOM | Represents the structure of the HTML document. | | CSSOM | Represents the CSS rules. | | Render Tree | Determines what participates in rendering. | | Layout | Calculates the size and position of elements. | | Paint | Draws the visual appearance. | | Compositing | Combines painted surfaces/layers into the final frame. | | Layout Thrashing | Can happen when layout-affecting writes and layout reads are repeatedly mixed. | | Performance Optimization | Batch DOM/layout reads and writes when possible. | | DevTools | Performance tools are useful for understanding what the browser is actually doing instead of simply guessing. | --- # ๐ฏ What I Learned From This Before doing this experiment, I mostly thought about HTML, CSS, and JavaScript as separate parts of frontend development. Now I have a better understanding of how they connect:
HTML
โ
DOM
โ
CSSOM
โ
Render Tree
โ
Layout
โ
Paint
โ
Compositing
โ
Screen
I also learned that the way JavaScript interacts with the DOM can affect browser rendering performance.
The layout-thrashing experiment was especially useful because I could see how a simple operation like reading offsetHeight can become important when it is repeatedly mixed with style changes.
๐ Conclusion
This was one of those topics that made much more sense after actually experimenting with it.
Instead of only reading about reflow, repaint, and compositing, I used Chrome DevTools to observe the browser's rendering work.
The biggest lesson I took from this experiment is:
Don't just learn how the browser works. Use DevTools to see it working.
This experiment gave me a better understanding of what happens behind the scenes when the browser turns our HTML, CSS, and JavaScript into pixels.
๐ ๏ธ Practical Work
As part of my Week 2 learning, I worked on:
- โ Responsive landing page
- โ Chrome DevTools Performance analysis
- โ Layout, Paint and Compositing investigation
- โ Layout thrashing experiment
- โ Batched DOM reads and writes
- โ Before/after performance comparison ## Tools Used
- HTML
- CSS
- JavaScript
- Chrome DevTools
- VS Code
๐ Final Note
I'm still learning frontend performance, but this experiment helped me understand that writing frontend code isn't only about making the page look correct โ it's also about understanding how the browser processes that code.
๐ My Handwritten Notes
I also made handwritten notes while learning these concepts. They helped me understand the browser rendering pipeline and remember the key points.
Here are my notes:
Handwritten notes - Browser Rendering Pipeline






Top comments (0)