skip to content

Loading and Critical Path

How bytes reach the browser, and in what order, decides your first paint. This group covers the critical rendering path and the levers that reorder the work: script attributes, resource hints, priorities, laziness and streaming.

on this pageshow

explore

questions

page 1 of 2

What is a web page's critical rendering path, and what does it mean for a resource to be render-blocking?

level: juniorimportance: must knowfreq 66%

answer

  1. blank screen until CSS arrives
  2. DOM plus CSSOM makes the render tree
  3. stylesheets and sync scripts, not images
  4. count blocking bytes and round-trip depth

basics

~20 s

The critical rendering path is everything a browser must fetch and process before it can paint: the HTML, the DOM built from it, and the CSS. A render-blocking resource is one the browser insists on having before that first paint.

solid answer

~50 s

The critical rendering path is the chain of work between the first byte of HTML arriving and the first pixels appearing. The browser parses HTML into the DOM, fetches and parses the CSS it finds into the CSSOM, combines the two into a render tree, then runs layout and paint. Anything it refuses to paint without is **render-blocking** — in practice external stylesheets, plus synchronous scripts, which additionally stop the HTML parser. Images, fonts and deferred scripts are *not* render-blocking: the page can paint without them. Optimising the path means reducing three things — how many blocking resources sit on it, how many bytes each costs, and how many round trips deep the chain is. That is why the standing advice is to keep the CSS small and discovered early, and to keep blocking scripts out of the `<head>`.

go deeper

for a junior

Be able to say plainly that stylesheets and synchronous scripts hold up the first paint while images and deferred scripts do not, and that the browser needs both the DOM and the CSS before it can draw.

for a middle

Walk the sequence out loud — HTML to DOM, CSS to CSSOM, render tree, layout, paint — and explain why a partially-loaded stylesheet makes painting unsafe rather than merely ugly.

for a senior

Show that you can identify the real path from a waterfall on a throttled connection and attribute a slow first paint to a specific blocking resource, rather than reciting generic advice.

for a principal

Frame the path as a budget the whole organisation spends: every team that adds a tag to the head is buying delay for every page, so the interesting question is who is allowed to put things there and how that is enforced.

## What the browser must do before it can paint A blank white screen is not the browser being lazy — it is the browser waiting for the inputs it needs to paint anything at all. Those inputs form a fixed sequence, and that sequence is what people mean by the *critical rendering path*. 1. **HTML arrives** and the parser starts turning bytes into a **DOM** — a tree of element nodes. 2. As it parses, it encounters references to other files: stylesheets, scripts, images. 3. **CSS is fetched and parsed into the CSSOM** — a parallel tree describing the computed style rules. 4. DOM and CSSOM are combined into a **render tree**: only the nodes that will actually be drawn, each with its resolved styles. 5. **Layout** computes the geometry of every box; **paint** fills in pixels. The crucial point is step 4. The browser cannot build a render tree from the DOM alone, because it does not yet know whether a given element is `display: none`, or red, or 400 pixels tall. So while a stylesheet the page has already referenced is still in flight, there is nothing safe to paint. Paint the DOM early and every user sees an unstyled flash, then a violent reflow — so browsers hold the paint instead. ## Render-blocking versus everything else A resource is **render-blocking** when the browser will not produce a first paint until that resource has been fetched *and* processed. In everyday pages that list is short: - **External stylesheets** referenced from the document — the canonical render-blocking resource. - **Synchronous scripts** (`<script src="...">` with no `defer` or `async`) — these are worse, because they also halt HTML parsing at the point they appear, so no further DOM is built until they have downloaded and executed. And what is *not* on the path is just as important to be able to name: - **Images** — the page paints without them; a missing image leaves a gap, it does not delay the paint. - **Web fonts** — text can render in a fallback face (or be briefly invisible) while the font loads. - **Deferred and async scripts** — they do not hold up the first paint. - **Anything fetched by JavaScript after load** — by definition it happens after the paint you care about. A useful sanity check: open the network waterfall, find the moment of first paint, and ask which requests started *and finished* before it. Those are your critical path. Everything else is noise for this particular question. ```html <head> <link rel="stylesheet" href="/app.css"> <!-- blocks the first paint --> <script src="/analytics.js"></script> <!-- blocks the parser AND the paint --> <script src="/app.js" defer></script> <!-- neither --> </head> <body> <img src="/hero.jpg" alt=""> <!-- neither --> </body> ``` ## The three levers Once you can see the path, there are only three things you can do to it, and being explicit about which one you are pulling is what separates a real answer from advice-by-slogan. **Fewer resources on the path.** Every blocking file is at minimum one extra round trip after its discovery. Merging two stylesheets, or removing a blocking third-party script from the head, removes a whole link. **Fewer bytes per resource.** A stylesheet carrying rules for every page on the site is paid for on the first paint of every page. Compression, minification and removing dead rules all shorten the same wait. **Fewer round trips of depth.** This is the one people miss. Ten resources requested at once cost roughly one round trip; three resources where each is discovered only after the previous one is parsed cost three. Depth, not count, is usually what makes a slow path pathological on a high-latency mobile connection. ## Why this framing pays off in an interview Interviewers ask this because it converts vague performance folklore into a causal model. "The page is slow" becomes "first paint waits on a 180 KB stylesheet that is discovered late, and a synchronous tag manager script in the head that also stops the parser." The metric that marks the end of this path is First Contentful Paint, and a poor Largest Contentful Paint very often has the same root cause, because the hero element cannot be painted until the path completes either. A final nuance worth having ready: the parser does not go completely idle while a blocking resource loads. Browsers run a **preload scanner** that reads ahead in the raw HTML for further `src`/`href` references and starts those downloads in parallel. That is why a stylesheet in the head does not serialize the rest of the page's downloads — and it is also why resources that are *not* visible in the raw HTML (injected by script, or referenced from inside a CSS file) are discovered late and hurt disproportionately.

  • If images are not render-blocking, why does a big hero image still show up as a performance problem?
    Because it is usually the Largest Contentful Paint element. The page can paint around it, but the metric that represents "the main content is visible" is not satisfied until it decodes. That makes it a *content* problem rather than a critical-path problem — the fix is discovery and priority for that one image, not removing blocking work.
  • Does the HTML parser stop completely while a render-blocking stylesheet downloads?
    No. The parser keeps building the DOM, and a preload scanner reads ahead in the raw markup to start other downloads in parallel. What is withheld is the *paint*, not the parse. The exception is a synchronous script, which genuinely halts the parser at its tag until it has run.
  • How would you show a colleague which resources are actually on the critical path of a page?
    Record a load in the network panel with cache disabled and throttling on, mark the First Contentful Paint line, and list the requests that both started and completed before it. Anything after that line is off the path for first paint. A Lighthouse run reports the same set as render-blocking resources.

saying these in an interview costs you the question

  • Says images and fonts block the first paint
  • Claims the browser paints the DOM before any CSS loads
  • Thinks the path ends at DOMContentLoaded or the load event
  • Believes moving scripts to the body end makes CSS non-blocking
  • Treats resource count as the only cost and ignores chain depth

context

open as a page

In web performance, what does deferring the download of a page's offscreen images and iframes until the user scrolls near them actually save, and what does it not make faster?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Deferring offscreen images and iframes saves bytes, requests and connection capacity for content the user never scrolls to, leaving more bandwidth for what is on screen first. It does not make the deferred content itself arrive faster — it arrives later, on demand.

open as a page

In an HTML page's head, what is the difference between <link rel="preload"> and <link rel="prefetch">, and which navigation does each one serve?

level: juniorimportance: must knowfreq 58%

basics

~20 s

preload fetches a resource the current page definitely needs, at high priority, during this navigation. prefetch fetches something a likely next navigation will need, at the lowest priority, using idle time. Same syntax, opposite intent.

open as a page

In an HTML page, what is the difference between a parser-blocking resource and a render-blocking one, and why does a synchronous <script> placed after a <link rel="stylesheet"> wait for that stylesheet before it runs?

level: middleimportance: must knowfreq 48%

basics

~20 s

Parser-blocking stops the HTML parser from building more DOM; render-blocking only withholds the first paint while parsing continues. A synchronous script waits for preceding stylesheets because it may read computed styles, which requires a complete CSSOM.

open as a page

Some teams apply lazy loading to every image, iframe and offscreen section on a page by default. What does that blanket policy cost, and how do you decide what is genuinely safe to defer?

level: middleimportance: must knowfreq 62%

basics

~20 s

Deferring everything delays content the user is already looking at, so the page starts slower rather than faster. Draw the line by viewport probability: anything that paints in the first screen loads eagerly, and only content the user may never reach is deferred.

open as a page

A product page loads twenty separate <script> tags — an application bundle, a polyfill file, an analytics tag, an A/B testing tag and a chat widget among them. How do you decide what loading treatment each one gets, and what does each decision actually move?

level: middleimportance: must knowfreq 65%

basics

~20 s

Triage every script by what depends on it: render-critical code stays inline and tiny, anything the first paint does not need is deferred, anything used only after an interaction loads on demand, and unused tags get deleted.

open as a page

A server-rendered page holds its whole HTML response until a 600 ms database query finishes, then sends it in one piece. What changes for the browser if the server instead streams the HTML in chunks, flushing the <head> before that query completes — and what does it not change?

level: middleimportance: must knowfreq 65%

basics

~20 s

Streaming sends the <head> immediately, so the browser parses it and starts downloading CSS, fonts and scripts while the server is still querying. The query time, the byte count and the work the browser must do are unchanged.

open as a page

A browser fetches a page's stylesheets, scripts and images in a different order from the one they appear in the HTML source. What is a request priority, and what does the browser do with it?

level: juniorimportance: should knowfreq 40%

basics

~20 s

A request priority is the browser's internal ranking of how urgently it thinks each resource is needed. Bandwidth and connections are limited, so the browser issues and services top-ranked requests first — download order follows that ranking, not markup order.

open as a page

Many apps show a grey skeleton layout — outlined boxes and bars in the shape of the coming content — while data loads, instead of a spinner or a blank area. What does that actually improve, and what does it not?

level: juniorimportance: should knowfreq 52%

basics

~20 s

A skeleton improves perceived speed: it shows the page's structure immediately, so the wait feels shorter and more predictable. It does not make data arrive any sooner, and a skeleton whose size differs from the real content causes the page to jump.

open as a page

For deferring offscreen images and iframes, when is the browser's built-in lazy loading enough, and what does driving the loading yourself with IntersectionObserver buy you?

level: middleimportance: should knowfreq 50%

basics

~20 s

Built-in lazy loading is free, needs no JavaScript and works before scripts run, so it is the default for ordinary offscreen images and iframes. A custom IntersectionObserver is worth it when you need your own trigger distance, placeholders, or to defer something the browser cannot — background images, video, components or data.

open as a page

Before you add any hint of your own, what does a browser use to decide a request's priority — and why does an image inside the initial viewport not automatically download ahead of one far below the fold?

level: middleimportance: should knowfreq 48%

basics

~20 s

Browsers rank a request first by resource type — render-blocking CSS and blocking scripts at the top, fonts high, images and async scripts low — and only afterwards by position. Viewport position is applied late, because the browser cannot know an image is visible until layout has run.

open as a page

A team marks about a dozen of a page's requests as high priority. The page gets no faster and one metric drifts slightly worse. Why does promoting everything fail, and what would you do instead?

level: middleimportance: should knowfreq 36%

basics

~20 s

Priority is a relative ranking, not extra bandwidth. Marking twelve requests urgent flattens the ordering back to roughly what it was, while discarding the browser's own sensible demotions — so nothing is served sooner and some genuinely low-value work now competes with the critical path.

open as a page

A page pulls resources from six third-party origins. Which of them would you give a <link rel="preconnect">, which are better served by <link rel="dns-prefetch">, and why is preconnecting all six a bad idea?

level: middleimportance: should knowfreq 48%

basics

~20 s

Preconnect the two or three origins that serve something needed early — it pays DNS, TCP and TLS up front. Use dns-prefetch for origins used later; it resolves DNS only and costs almost nothing. Preconnecting everything wastes connections and contends for bandwidth.

open as a page

A team adds <link rel="preload" href="/fonts/inter.woff2" as="font"> to their page head, and the browser ends up downloading that font file twice. Why, and what do the as and crossorigin attributes control on a preload?

level: middleimportance: should knowfreq 52%

basics

~20 s

Fonts are always fetched in anonymous CORS mode, so a preload without the crossorigin attribute produces a request the real font request cannot reuse, and the file downloads twice. The as attribute sets the request's destination, priority and Accept header.

open as a page

On a web page, when is putting JavaScript directly in an inline <script> block the right performance choice instead of linking a separate .js file, and what does inlining cost you?

level: middleimportance: should knowfreq 42%

basics

~20 s

Inline only code that must run before the first paint and is small enough that a separate request would cost more than the bytes — a few hundred bytes at most. Inlined code cannot be cached separately and ships with every HTML response.

open as a page

A server streams a product page's HTML, but a recommendations widget in the middle of the page takes 900 ms to load while everything below it is ready immediately. How do teams stop that one slow region from holding up the rest of the streamed document?

level: middleimportance: should knowfreq 45%

basics

~20 s

Stream a placeholder element where the slow widget belongs, continue writing the rest of the page, then send the widget's real markup in a later chunk with a small inline script that moves it into the placeholder.

open as a page

A team proposes inlining the above-the-fold CSS into the HTML <head> and loading the full stylesheet asynchronously. What does that buy for first paint, and what does it cost?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Inlining critical CSS removes the render-blocking stylesheet round trip, so the page can paint from the HTML response alone. The costs are uncacheable bytes on every response, extraction that drifts out of sync with the templates, restyling if the wrong rules were picked, and Content-Security-Policy friction.

open as a page

In a page-load waterfall, what is a critical request chain, and why is a deep chain worse than the same number of bytes fetched in parallel?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A critical request chain is a series of render-blocking requests where each one is discovered only after the previous response is parsed. Depth costs a round trip per link regardless of size, so the same bytes fetched in parallel arrive far sooner.

open as a page

A marketing page embeds a third-party video player, a map and a support chat widget, each pulling in its own iframe and scripts. How would you keep them off the initial load, and what does a click-to-load facade trade away?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Replace each embed with a lightweight facade — a static thumbnail or button that looks like the widget — and create the real iframe only when the user interacts or scrolls close. The trade is one extra interaction and a visible wait before the widget becomes usable.

open as a page

A page's main visual is applied as a CSS background-image from an external stylesheet, and it arrives late enough to delay the page's largest paint. Why does marking that request urgent not fix it on its own, and what actually shortens the delay?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Priority ranks requests the browser already knows about; it cannot rank one that has not been discovered. A CSS background image is invisible to the preload scanner and is requested only after the stylesheet downloads, parses, and an element matches — so the fix is shortening that discovery chain, with priority as the follow-up.

open as a page

A team added fourteen <link rel="preload"> tags to a page's head so that "everything arrives sooner", and the page's Largest Contentful Paint got worse. Explain how over-preloading slows a page down, and how you would decide which preloads to keep.

level: seniorimportance: should knowfreq 44%

basics

~20 s

Preload is a mandatory high-priority fetch, so fourteen of them jump the queue ahead of the resources that determine first paint and share the same finite bandwidth. Keep only hints for critical resources the browser would otherwise discover late.

open as a page

A team marks every <script> on a page as deferred. Lab First Contentful Paint improves, but real users report the page is unresponsive for about a second after it appears, and Total Blocking Time barely moved. Why did deferring not fix that, and what would?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Deferring changes when JavaScript runs, not how much runs. All that execution now lands in one burst right after the page paints, occupying the main thread exactly when the user starts interacting. Only shipping or running less code reduces blocking time.

open as a page

During a vendor outage, pages on your site stayed blank for twenty seconds; the vendor's tag is fetched from their domain by a plain <script> tag in the page's <head>. Why did a third-party script have that power over your page, and what containment would you put in place?

level: seniorimportance: should knowfreq 45%

basics

~20 s

A script the page must fetch and run before it renders makes your availability depend on the vendor's: if their server hangs, the browser waits until the request times out. Containment means never letting third-party code sit on the critical path, and capping anything that gates visible content.

open as a page

A team ships HTML streaming: locally the page's shell appears while the server is still working, but in production the browser gets nothing until the whole response is ready and the shell never appears early. How do you diagnose where the streaming is being lost?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Compare time to first byte with total transfer time for the document at each hop — browser, CDN, reverse proxy, origin. Whichever hop is the first to report them as nearly equal is the one buffering the response.

open as a page

A server-rendered page streams its HTML and paints in about 0.8 s, but clicking anything does nothing for another two seconds while the page's JavaScript boots up and attaches behaviour to the existing markup. What is happening in that gap, and what does hydrating progressively change about it?

level: seniorimportance: should knowfreq 36%

basics

~20 s

The gap is client-side JavaScript downloading, parsing and executing to attach behaviour to the server-rendered markup — work that occupies the main thread, so clicks queue. Hydrating progressively splits that work per region and defers most of it until each region is needed.

open as a page

You lead a large site with dozens of page templates, and a team proposes adding an automated critical-CSS extraction step to the build for every template. How would you evaluate that proposal?

level: principalimportance: should knowfreq 26%

basics

~20 s

Evaluate it by proving from field data that render-blocking CSS actually dominates first paint, sizing the ongoing maintenance of per-template extraction, comparing it against cheaper fixes such as per-route stylesheets, and deciding who owns it when it drifts.

open as a page

Marketing can add tags to your site through a tag manager without engineering review, and the number of scripts on each page keeps climbing. As the engineer accountable for page performance, what governance would you put in place, and what would you concede?

level: principalimportance: should knowfreq 33%

basics

~20 s

Set a per-page script budget expressed as a measured cost with a named owner and a real consequence when it is exceeded, require every tag to carry an owner, a stated purpose and a review date, and give marketing a fast approved path so governance does not become a queue.

open as a page

For an ES module entry point, what does <link rel="modulepreload" href="/app.js"> do that <link rel="preload" as="script" href="/app.js"> does not?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

modulepreload fetches the module, parses it and puts it in the module map ready to evaluate, and browsers may follow its static imports to fetch the dependency graph too. A plain script preload only stores raw bytes and never looks at the imports.

open as a page

On a page rendering thousands of DOM nodes in a long list, what does the CSS declaration content-visibility: auto change about the work the browser does, and why does it usually need contain-intrinsic-size alongside it?

level: seniorimportance: nice to knowfreq 34%

basics

~20 s

content-visibility: auto tells the browser to skip style, layout and paint work for a subtree while it is far offscreen, rendering it only when it nears the viewport. Without contain-intrinsic-size the skipped element measures as empty, so the page height and scrollbar jump as sections render.

open as a page

Your product page's origin needs about 400 ms to generate its HTML. What does an HTTP 103 Early Hints response let the browser do during that window, and how would you decide whether to adopt it?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

A 103 Early Hints response is sent before the real response and carries Link headers with preload or preconnect, so the browser starts fetching assets and warming connections while the origin is still generating HTML. It pays only when server think-time is genuinely long.

open as a page

showing 1–30 of 31