HTMLHow Browsers Render HTML

How Browsers Render HTML

You've already seen the big picture in How the Web Works: HTML arrives, and the browser turns it into pixels. This page zooms into that final stretch — the sequence of steps browsers call the critical rendering path. You don't need to memorize every detail yet; a dedicated advanced page revisits this later. For now, the goal is a solid mental model.

The six-step pipeline
  1. Parse HTML → DOM. The browser reads HTML tags and builds the DOM (Document Object Model), a tree of nodes representing every element and its position in the document.

  2. Parse CSS → CSSOM. Any CSS — from <code><style></code> blocks, <code><link></code> stylesheets, or inline <code>style</code> attributes — is parsed into the CSSOM (CSS Object Model), a tree of style rules.

  3. Combine → Render Tree. The DOM and CSSOM are merged into a render tree containing only the nodes that will actually be visible (elements with <code>display: none</code> are excluded).

  4. Layout (a.k.a. reflow). The browser calculates the exact size and position of every visible node on the page — a box for every element, in pixels.

  5. Paint. The browser fills in those boxes with actual pixels — text, colors, borders, shadows, images.

  6. Composite. Painted layers are combined in the correct order (accounting for overlapping elements, z-index, and transforms) into the final image shown on screen.

DOM: the tree HTML becomes

Take this small document:

HTML
<body>
  <h1>Title</h1>
  <p>Some <em>text</em>.</p>
</body>

The parser turns it into a tree: body has two children, h1 and p; p itself has two children — a text node ("Some ") and an em element, which in turn has its own text node ("text"). Every relationship in your markup — parent, child, sibling — becomes a relationship in this tree.

Parsing is incremental
The browser doesn't wait for the whole HTML file to download before starting. It parses and builds the DOM progressively as bytes arrive, which is why long pages can start showing content before they've fully loaded.
CSSOM: styles as a tree too

CSS rules are parsed into their own tree structure that captures the cascade — which rules apply to which elements, and which wins when rules conflict. Unlike HTML parsing, CSS parsing blocks rendering: the browser won't paint anything until it has the full CSSOM, because showing unstyled content and then suddenly restyling it would be a jarring experience.

Render tree: only what's visible

The render tree is built by walking the DOM and, for every visible node, attaching the matching styles from the CSSOM. Elements with display: none are left out entirely (they don't take up space or get painted) — but elements with visibility: hidden ARE included in the render tree, since they still occupy layout space, just invisibly.

Layout and paint

Step

Question it answers

Triggered by

Layout

Where exactly does each box go, and how big is it?

Adding/removing elements, changing dimensions, window resize

Paint

What color are the pixels inside each box?

Changing colors, backgrounds, shadows, visibility

Composite

How do overlapping, layered boxes combine into the final image?

Transforms, opacity, fixed/sticky positioning

Why this matters for performance
Layout is the most expensive of the three. Changing a property that only affects paint or composite (like opacity ortransform) is much cheaper than one that triggers layout (like changing width). This becomes very relevant once you start writing CSS animations.
Where JavaScript fits in

JavaScript can read and modify the DOM and CSSOM at any point. Because of this, the browser's HTML parser normally pauses when it hits a <script> tag without async or defer — it must run the script (which might change the page) before it can safely continue parsing the rest of the HTML. This is one of the main reasons scripts are traditionally placed at the bottom of <body>, or loaded with defer, so they don't block the initial render.

Putting it all together
  • HTML → parsed into the DOM (structure).

  • CSS → parsed into the CSSOM (style).

  • DOM + CSSOM → combined into the render tree (visible, styled structure).

  • Render tree → layout (geometry) → paint (pixels) → composite (final image).

  • JavaScript can jump in at any point and modify the DOM/CSSOM, causing some of these steps to re-run.

This pipeline runs every time you load a page, and partially re-runs every time something changes afterward. With this mental model in place, the rest of this HTML series will make it obvious why certain structures and practices (like avoiding deeply nested layouts, or writing valid markup) genuinely affect real-world performance and correctness — not just theoretical "best practices."