QuestionsWeb Performance

Critical rendering path: what blocks first paint

Critical Rendering PathEasyWeb Performance

Walk through what the browser does between receiving HTML and painting the first pixel. What blocks that first paint?

What it tests

Whether you understand rendering as a pipeline with specific blocking points, not a black box.

Approach & answer

The browser turns bytes into pixels through a pipeline. It parses HTML into the DOM; as it hits <link rel=stylesheet> and <script>, it fetches those. CSS is parsed into the CSSOM. DOM + CSSOM combine into the render tree (only visible nodes, with computed styles). Then layout (a.k.a. reflow) computes the geometry of every box, and paint fills in pixels, composited into layers on screen. Two things block the FIRST paint. (1) CSS is render-blocking: the browser will not paint until the CSSOM is ready, because painting with no styles then restyling would flash unstyled content — so a slow stylesheet in <head> delays everything. (2) A synchronous <script> (no defer/async) is parser-blocking: when the parser reaches it, it stops building the DOM, downloads and executes the script, and only then continues — and because scripts can read styles, a script also waits for any pending CSS above it. The practical levers all target this path: keep critical CSS small and inline it, load non-critical CSS asynchronously, and get scripts off the parser with defer/async. First paint is gated by the slowest render-blocking resource in the <head>, so minimizing that set is the whole game for a fast start.

Use this technique when

Diagnosing slow first paint; explaining why a stylesheet or script in <head> delays render.

Code

<!-- Render-blocking: paint waits for this CSS to download + parse -->
<link rel="stylesheet" href="/app.css">

<!-- Parser-blocking: DOM build stops here until the script runs -->
<script src="/app.js"></script>

<!-- Better: inline the critical CSS, defer the rest -->
<style>/* above-the-fold rules only */</style>
<link rel="stylesheet" href="/rest.css" media="print" onload="this.media='all'">
<script src="/app.js" defer></script>

References