How a Browser Actually Works.
A browser's only job is to turn a string of text — a URL — into a moving rectangle of pixels you can see, click, and trust. Everything below is the machinery that makes that possible.
From URL to bytes on the wire
Before a single pixel paints, the browser plays diplomat — translating a human-readable address into an IP, opening a secure pipe, and negotiating a conversation.
Fig. 1 — The browser as diplomat: round-trips before a single character of HTML arrives. With HTTP/3 (QUIC), the TCP and TLS handshakes fuse into one trip.
Two trees grow in parallel
As HTML bytes stream in, the parser tokenizes them into nodes — building the DOM. The moment a stylesheet is discovered, a second parser starts on the CSS, producing a CSSOM. They are siblings, racing.
<script> (without async or defer), parsing PAUSES. The script must be fetched, parsed, and executed before tree construction resumes. This is why script placement is a performance lever.
Fig. 2 — DOM and CSSOM grow side by side. They will be married in the next stage to form the render tree.
How trees become pixels
The DOM and CSSOM merge into a render tree. The browser computes geometry (layout), fills in pixels (paint), and the GPU stitches layers into a final frame (composite). Every UI update re-runs some portion of this path.
Which CSS properties trigger what?
| Property changed | Triggers | Cost |
|---|---|---|
width, height, top, left, padding, font-size |
Layout → Paint → Composite | expensive |
color, background, box-shadow, border-radius |
Paint → Composite | moderate |
transform, opacity, filter |
Composite only (GPU) | cheap |
Fig. 3 — Why transform: translateX(100px) beats left: 100px for animation: it skips two of the three most expensive stages.
JavaScript & the event loop
JavaScript runs on a single thread. The illusion of concurrency is choreography: synchronous code on a call stack, asynchronous work delegated to Web APIs, and a loop that pulls completed work back in — microtasks first, then one macrotask, then repeat.
See the full deep-dive in Event Loop & Async.
Why Chrome runs a process per tab
Modern browsers split work across OS processes for security, stability, and parallelism. A crashed renderer doesn't take down the browser; a compromised tab can't read another tab's memory.
Browser
One per browser. Handles UI chrome (address bar, tabs), networking, disk, and orchestrates everything else.
Renderer
One per site (roughly). Runs the parsing, JS engine, layout, paint. This is where your code lives.
GPU
Single process that handles compositing layers and accelerated graphics. Talks to the actual GPU hardware.
Network / Utility
Networking isolated from renderers. Extensions, audio, video decoding spawn their own utility processes.
Fig. 4 — Chrome's process model. Site Isolation (post-Spectre) goes further: even cross-origin iframes get their own renderer process.
The one-sentence summary you can repeat in an interview
"URL → DNS & TLS & HTTP → HTML streams in → parser builds DOM, CSS builds CSSOM in parallel → they merge into a render tree → layout computes geometry, paint fills pixels, composite stitches GPU layers — and JavaScript runs on the same main thread, coordinated by the event loop, which is why blocking JS blocks everything."
Three perf rules that fall out of this
- Animate
transformandopacity. They skip layout and paint — the GPU does all the work. - Don't block the main thread. JS, layout, paint, and event handling share one thread. A 200ms function = a 200ms frozen UI.
- Defer non-critical scripts. Render-blocking JS pauses HTML parsing, which delays first paint. Use
defer,async, or move scripts to the bottom.
Before you leave — how confident are you with this?
Your honest rating shapes when you'll see this again. No grades, no shame.
Comments
Loading comments…