Under The Hood
frontend browser Chromium rendering pipeline

HTML Parser, CSSOM Blocking, and RenderTree Construction

Last updated
Prerequisites:
HTML/CSS basics
Understanding of how browsers load a page
  • browser
  • html-parser
  • cssom
  • render-tree
  • rendering
  • critical-path

Read at your depth

The practical view

When a browser loads a page, it parses HTML into the DOM (a tree of elements) and CSS into the CSSOM (a tree of style rules). Both trees combine into the RenderTree: the visible nodes with their computed styles. A <style> or <link rel="stylesheet"> blocks rendering: the browser must build the CSSOM before painting, so CSS is a render-blocking resource. Scripts without async/defer also block parsing (they pause HTML parsing while executing). The RenderTree contains only visible elements (display:none elements are excluded). This pipeline (DOM + CSSOM → RenderTree → Layout → Paint) is the critical rendering path.

The same idea in other frameworks

react equivalent
React apps ship one CSS bundle typically; critical CSS extraction inlines render-blocking styles.

Legacy vs modern

Render-blocking stylesheet vs async-loaded critical CSS

A synchronous <link> blocks first paint until it loads; loading critical CSS inline and deferring the rest unblocks rendering.

before → after
Render-blocking stylesheet
<link rel="stylesheet" href="/app.css"> <!-- ❌ OLD: render-blocking — paint waits for this file -->
Inline critical CSS + deferred full CSS
<style>/* critical styles inline */</style>
<link rel="stylesheet" href="/full.css" media="print" onload="this.media='all'"> <!-- ✅ NEW -->

Interview gotchas

Context

This tests the critical rendering path — interviewers want the precise mechanics of which resource blocks which phase, not the vague 'CSS is slow'.

The mechanical answer

CSS is render-blocking because the browser will not paint without a complete-enough CSSOM: painting unstyled content would cause a flash of unstyled text (FOUC) and wasteful repaints. So the browser delays the first paint (and the first layout) until all render-blocking stylesheets are downloaded and parsed (subject to a timeout for some cases). HTML parsing itself continues incrementally while CSS loads — the parser keeps building the DOM — it's the RENDER (paint) that waits. Scripts, by contrast, block HTML parsing: a classic synchronous script must execute at its position because it may call document.write or read the partially-built DOM. This asymmetry (CSS blocks render, scripts block parse) is central to the critical path.

Trap

The naive answer is 'CSS blocks everything'. It blocks render, not parsing. Another trap: assuming all stylesheets block — media queries that don't match the current device (e.g. media=print) are non-blocking, which is the trick used for async loading. Candidates who distinguish parse-blocking vs render-blocking show real understanding.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.