HTML & CSS7 min read

How the Browser Renders a Web Page

Understand the browser rendering pipeline — DNS, HTML parsing, DOM, CSSOM, render tree, layout, paint, and compositing. Essential knowledge for every frontend developer.

browserrenderingperformancefundamentals

How the Browser Renders a Web Page

When you type a URL and press Enter, a fascinating chain of events happens in milliseconds. Understanding this pipeline helps you write faster websites and debug performance issues.

The Journey: URL to Pixels

Step 1: DNS Resolution

The browser needs to find the server's IP address. It checks:

  1. Browser cache
  2. OS cache
  3. Router cache
  4. ISP's DNS server
  5. Root DNS servers (if needed)

This lookup usually takes 20-120ms. DNS prefetching (<link rel="dns-prefetch">) can eliminate this delay for links your page will navigate to.

Step 2: TCP Connection + TLS

The browser establishes a connection with the server:

  • TCP handshake — 3-way: SYN → SYN-ACK → ACK
  • TLS handshake — for HTTPS, adds encryption negotiation

This takes another 50-200ms. HTTP/2 and HTTP/3 reduce this with connection reuse and QUIC protocol.

Step 3: HTTP Request/Response

The browser sends a GET request. The server responds with HTML. The browser starts processing bytes as they arrive — it doesn't wait for the complete response.

Building the DOM

The browser parses HTML from top to bottom, creating the DOM (Document Object Model) — a tree structure representing every element:

Document
├── html
│   ├── head
│   │   ├── title
│   │   └── link (stylesheet)
│   └── body
│       ├── header
│       │   └── nav
│       ├── main
│       │   ├── h1
│       │   └── p
│       └── footer

What Blocks DOM Construction?

  • <script> tags — The parser STOPS to download and execute JavaScript. This is why scripts go at the bottom or use defer/async.
    • defer — downloads in parallel, executes after DOM is complete
    • async — downloads in parallel, executes immediately when ready (can interrupt parsing)
  • CSS does NOT block DOM construction — but it blocks rendering (explained below)

Building the CSSOM

While building the DOM, the browser also processes all CSS into the CSSOM (CSS Object Model). The CSSOM contains every style rule applied to every element, including:

  • Your stylesheets
  • Browser default styles
  • Inline styles

CSS is render-blocking. The browser waits for ALL CSS to be loaded and parsed before rendering anything. This is why:

  • Put <link rel="stylesheet"> in the <head> — so it loads early
  • Minimize CSS file size — every byte delays first render
  • Consider critical CSS inlining for above-the-fold content

The Render Tree

The DOM and CSSOM combine into the Render Tree — only elements that will actually be painted:

  • Elements with display: none are excluded
  • Pseudo-elements (::before, ::after) are included
  • The <head> section is excluded
Render Tree
├── body (bg: white, font: 16px)
│   ├── header (h: 64px, bg: #1a1a2e)
│   │   └── nav (display: flex)
│   ├── main (padding: 24px)
│   │   ├── h1 (font-size: 2rem, font-weight: bold)
│   │   └── p (color: #333, line-height: 1.6)
│   └── footer (h: 48px, bg: #f5f5f5)

Layout (Reflow)

The browser calculates the exact position and size of every element in the render tree. This process is called Layout or Reflow.

Layout computes:

  • Width and height of each element
  • Position (x, y coordinates)
  • Margin, padding, border calculations
  • How elements affect each other's positions

Reflow is expensive. Changing one element's size can cascade changes through the entire tree.

What Triggers Reflow?

  • Adding/removing elements
  • Changing width, height, padding, margin
  • Changing font size
  • window.resize
  • Reading layout properties (offsetWidth, clientHeight, getBoundingClientRect())

Paint

After layout, the browser fills in pixels — colors, backgrounds, text, images, borders, shadows. This happens in layers.

What Triggers Repaint?

  • Changing color, background, border-color
  • Changing visibility
  • Changing box-shadow

Repaint is cheaper than reflow because it doesn't recalculate positions.

Compositing

Modern browsers paint content onto layers and composite them together. Elements that animate or change frequently can get their own layer, which makes updates much faster since only that layer needs to be repainted.

Properties that trigger layer promotion:

  • transform
  • opacity
  • will-change
  • position: fixed

This is why transform: translateX(100px) is faster than left: 100px for animations — transform only requires compositing, not layout + paint.

Performance Optimization Tips

1. Minimize Reflows

// Bad — triggers reflow on each read
for (let i = 0; i < 100; i++) {
  el.style.width = el.offsetWidth + 10 + "px"; // read + write in loop
}

// Good — batch reads and writes
const width = el.offsetWidth; // single read
for (let i = 0; i < 100; i++) {
  el.style.width = width + 10 * i + "px"; // writes only
}

2. Use transform for Animations

/* Expensive — triggers layout on every frame */
.animate { left: 0; transition: left 0.3s; }
.animate:hover { left: 100px; }

/* Cheap — only compositing */
.animate { transform: translateX(0); transition: transform 0.3s; }
.animate:hover { transform: translateX(100px); }

3. Use will-change Sparingly

.element-that-will-animate {
  will-change: transform;
}

This hints the browser to promote the element to its own layer. Don't overuse it — each layer uses memory.

4. Defer Non-Critical Resources

<link rel="stylesheet" href="critical.css">
<link rel="stylesheet" href="below-fold.css" media="print" onload="this.media='all'">

<script src="app.js" defer></script>

The Complete Pipeline

URL → DNS → TCP/TLS → HTTP → HTML bytes
                                  ↓
                               DOM Tree ──────┐
                                              ├── Render Tree → Layout → Paint → Composite → Pixels!
                               CSSOM Tree ────┘

Key Takeaways

  1. CSS is render-blocking, JS is parser-blocking — load both strategically
  2. Use defer for scripts and load CSS early
  3. Reflow (layout changes) is expensive — minimize it
  4. Use transform and opacity for animations — they skip layout and paint
  5. The render pipeline: DOM + CSSOM → Render Tree → Layout → Paint → Composite
  6. Every layout "read" (like offsetWidth) forces the browser to recalculate — batch your reads

🚀 Practice What You Learned

Apply these concepts with hands-on coding challenges: