Back

Rendering Content in the browser

MD Rashid Hussain
MD Rashid Hussain
Mar-2025  -  10 minutes to read
Image source attributed to: https://dbaron.github.io/browser-rendering

In an earlier article, we discussed how the web works. In this article, we will discuss how the browser renders the content that it receives from the server.

What exactly happens after you hit Enter on a URL?
How does code become a beautifully rendered page?

This article walks you through the full rendering pipeline of the browser — the unsung process that transforms HTML, CSS, and JavaScript into visible pixels.

We’ll explore how the DOM, CSSOM, Render Tree, Layout, Paint, and Compositing work together, and how to optimize them for performance.

When you hit Enter after typing a URL, your browser:

  1. Sends an HTTP request to the server.
  2. Receives a response containing HTML.
  3. Starts parsing HTML before the entire file is downloaded.

Parsing starts early and continues progressively. That's why <script> and <link> tags can delay rendering.

The browser parses the HTML markup and constructs the DOM Tree — a hierarchical in-memory representation of the page structure.

<html>
  <body>
    <h1>Hello, world!</h1>
    <p>This is rendered content.</p>
  </body>
</html>

becomes

Document
└── html
    └── body
        ├── h1
        └── p
  • Inline and external scripts can block DOM parsing unless marked with async or defer.
  • Errors in HTML are handled gracefully (browsers are forgiving).

Simultaneously, the browser parses all the CSS:

  • <link rel="stylesheet" />
  • <style> blocks
  • Inline style attributes

It builds the CSSOM, which maps selectors to their computed styles.

Note: CSSOM is also render-blocking. The browser needs complete style information before it can render anything.

The Render Tree combines:

  • DOM nodes
  • CSSOM rules
  • Filters out invisible elements (e.g. display: none)

For example:

<p style="display: none">This won't be rendered</p>

This paragraph will exist in the DOM, but not in the render tree.

The Render Tree contains only visual elements and their computed styles.

In the layout phase, the browser:

  • Calculates each render tree node’s geometry (position, size, padding, margins, etc.)
  • Accounts for flow, flex/grid layouts, viewport constraints

This is where units like %, em, vw, vh are resolved into exact pixels.

Layout is sometimes called reflow. Any DOM or style change that affects layout triggers a reflow.

Reflows Are Expensive

Avoid triggering frequent reflows with:

  • DOM mutations inside loops
  • Accessing layout properties (offsetTop, scrollHeight) before DOM settles
  • Layout-changing animations (e.g. top, width)

Now the browser paints each element onto a canvas (not <canvas>, but a raster surface):

  • Text, borders, background colors
  • Images, shadows, gradients

Each element is turned into draw commands — e.g., draw rectangle, draw text, draw image.

Painting large areas frequently is performance-intensive, especially with shadows, filters, or gradients.

Modern browsers use layers (like Photoshop) to allow parts of the page to be rendered independently.

  • These are composited together — often by the GPU — for better performance.
  • This allows fast effects like:
    • transform
    • opacity
    • will-change

Layer Promotion

Elements can be promoted to their own GPU layers to avoid costly repaints.

.will-animate {
  will-change: transform, opacity;
}

Too many promoted layers can exhaust GPU memory, causing jank or fallback to CPU compositing.

The full rendering pipeline is often referred to as the Critical Rendering Path:

HTML → DOM
CSS → CSSOM
DOM + CSSOM → Render Tree → Layout → Paint → Composite → Screen

Understanding this path is essential for improving:

  • First Paint (FP)
  • First Contentful Paint (FCP)
  • Largest Contentful Paint (LCP)

I have tried to cover the most important parts of the rendering pipeline. You can connect with me on X. I would love to hear from you and have a nice discussion.

Rendering Content in the browser