- Published on
How Browsers Work: From URL Input to Pixel Rendering — Essential Frontend Interview Knowledge
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- Introduction
- 1. From URL Input to Screen Display (Complete Interview Answer)
- 2. Network Phase
- 3. HTML Parsing
- 4. CSS Parsing
- 5. Render Tree
- 6. Layout (Reflow)
- 7. Paint and Compositing
- 8. Critical Rendering Path Optimization
- 9. Reflow vs Repaint
- 10. Event Loop and Task Queue
- 11. Web Workers and OffscreenCanvas
- 12. DevTools Performance Panel Guide
- 13. Interview Questions and Quiz
- References
Introduction
"What happens when you type a URL in the browser address bar?"
This is one of the most frequently asked frontend interview questions, and it tests your deep understanding of browser internals. A simple answer like "it fetches HTML and shows it on screen" will not suffice.
This guide covers every stage of browser operation systematically -- from DNS lookup, TCP connection, HTML/CSS parsing, DOM/CSSOM construction, render tree generation, layout, paint, compositing, and the event loop.
1. From URL Input to Screen Display (Complete Interview Answer)
1.1 Complete Flow Summary
User: Types URL + Enter
|
v
1. URL Parsing (protocol, domain, path)
|
v
2. DNS Lookup (domain → IP address)
|
v
3. TCP Connection (3-way handshake)
|
v
4. TLS Handshake (for HTTPS)
|
v
5. HTTP Request/Response
|
v
6. HTML Parsing → DOM Tree
|
v
7. CSS Parsing → CSSOM Tree
|
v
8. DOM + CSSOM → Render Tree
|
v
9. Layout (calculate position/size of each element)
|
v
10. Paint (draw pixels)
|
v
11. Composite (merge layers via GPU)
|
v
Displayed on screen!
2. Network Phase
2.1 DNS Lookup (Domain Name System)
The browser converts domain names to IP addresses.
Lookup order:
1. Browser DNS cache
2. OS DNS cache
3. Local hosts file
4. DNS Resolver (ISP)
5. Root DNS server
6. TLD DNS server (.com, .org, etc.)
7. Authoritative DNS server (returns actual IP)
Example: www.example.com lookup
Browser Cache → miss
OS Cache → miss
Router Cache → miss
ISP DNS Resolver → miss
Root Server → ".com is handled over here"
.com TLD Server → "example.com is handled over here"
example.com NS → "IP is 93.184.216.34"
Optimization techniques:
dns-prefetch: Pre-resolve DNS ahead of time
<link rel="dns-prefetch" href="//api.example.com" />
<link rel="preconnect" href="https://cdn.example.com" />
2.2 TCP 3-Way Handshake
Client Server
| |
|--- SYN (seq=x) ------->|
| |
|<-- SYN-ACK (seq=y, -----|
| ack=x+1) |
| |
|--- ACK (ack=y+1) ----->|
| |
Connection established!
2.3 TLS Handshake
Additional encryption process for HTTPS connections.
Client Server
| |
|-- ClientHello (TLS version, -->|
| cipher suites) |
| |
|<-- ServerHello, Certificate, ---|
| Server Key Exchange |
| |
|-- Client Key Exchange, -->|
| ChangeCipherSpec, |
| Finished |
| |
|<-- ChangeCipherSpec, ---|
| Finished |
| |
Encrypted communication begins!
2.4 HTTP Request/Response
GET / HTTP/2
Host: www.example.com
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, br
Connection: keep-alive
HTTP/2 200 OK
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
Cache-Control: max-age=3600
Content-Length: 12345
<!DOCTYPE html>
<html>...
3. HTML Parsing
3.1 Tokenizer and Tree Construction
The HTML parser converts the byte stream into tokens, then builds DOM nodes.
Bytes → Characters → Tokens → Nodes → DOM Tree
Example HTML:
<html>
<head>
<title>My Page</title>
</head>
<body>
<h1>Hello</h1>
<p>World</p>
</body>
</html>
DOM Tree:
Document
└─ html
├─ head
│ └─ title
│ └─ "My Page"
└─ body
├─ h1
│ └─ "Hello"
└─ p
└─ "World"
3.2 Script Blocking (Parser Blocking)
By default, encountering a script tag halts HTML parsing.
<!-- Parser-blocking: HTML parsing stops, script downloads + executes, then resumes -->
<script src="app.js"></script>
<!-- defer: Downloads parallel to parsing, executes after DOM is complete -->
<script defer src="app.js"></script>
<!-- async: Downloads parallel to parsing, executes immediately when downloaded -->
<script async src="analytics.js"></script>
defer vs async comparison:
Regular script:
HTML: ───████████████|████|████████
JS: |down|exec|
defer:
HTML: ───████████████████████████|exec|
JS: |████ download ████|
async:
HTML: ───████████|exec|████████████
JS: |████down|
defer: Preserves order, executes before DOMContentLoadedasync: No order guarantee, executes as soon as downloaded
3.3 Preload Scanner
Even when the parser is blocked, the preload scanner continues working to discover resources early.
<!-- preload: Pre-load critical resources -->
<link rel="preload" href="critical.css" as="style" />
<link rel="preload" href="hero.webp" as="image" />
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />
<!-- prefetch: Fetch resources for next navigation -->
<link rel="prefetch" href="/next-page.html" />
4. CSS Parsing
4.1 CSSOM Construction
CSS goes through a similar process as HTML.
Bytes → Characters → Tokens → Nodes → CSSOM Tree
CSS:
body { font-size: 16px; }
h1 { color: blue; font-size: 2em; }
p { color: #333; }
CSSOM Tree:
body (font-size: 16px)
├─ h1 (color: blue, font-size: 32px)
└─ p (color: #333)
4.2 CSS is a Render-Blocking Resource
The render tree cannot be built until CSS is loaded, making CSS a render-blocking resource.
<!-- Render-blocking: Rendering blocked until this CSS is loaded/parsed -->
<link rel="stylesheet" href="styles.css" />
<!-- Conditional: Print CSS does not block rendering -->
<link rel="stylesheet" href="print.css" media="print" />
<!-- Conditional: Only render-blocks at specific viewport -->
<link rel="stylesheet" href="mobile.css" media="(max-width: 768px)" />
4.3 Specificity Calculation
!important > inline styles > ID > class/attribute/pseudo-class > element/pseudo-element
Calculation: (a, b, c)
- a: Number of ID selectors
- b: Number of class, attribute, pseudo-class selectors
- c: Number of element, pseudo-element selectors
Examples:
#header .nav a → (1, 1, 1)
.nav .item.active → (0, 3, 0)
nav ul li a → (0, 0, 4)
#main #content p.text → (2, 1, 1)
4.4 Cascade Rules
Priority (highest first):
1. User-agent styles with !important
2. User styles with !important
3. Author styles with !important
4. Author styles (by specificity)
5. User styles
6. User-agent styles (browser defaults)
5. Render Tree
5.1 DOM + CSSOM = Render Tree
DOM Tree: CSSOM:
html body { font: 16px }
├─ head h1 { color: blue }
│ └─ title p { color: #333 }
├─ body .hidden { display: none }
│ ├─ h1
│ ├─ p
│ └─ div.hidden
│ └─ span (visibility: hidden)
Render Tree (visible elements only):
html
└─ body (font: 16px)
├─ h1 (color: blue)
├─ p (color: #333)
└─ span (visibility: hidden) ← included! Takes up space
[div.hidden excluded - display: none]
5.2 display: none vs visibility: hidden
| Property | In Render Tree | Takes Space | Triggers Reflow |
|---|---|---|---|
display: none | No | No | On add/remove |
visibility: hidden | Yes | Yes | No |
opacity: 0 | Yes | Yes | No |
5.3 Render Tree Construction Process
- Traverse from the root of the DOM tree
- Skip invisible nodes (script, meta, display: none)
- Match CSSOM rules for each visible node
- Add node to render tree with computed styles
6. Layout (Reflow)
6.1 Box Model
Every element is represented as a Box Model.
┌─────────────────────────────────────┐
│ margin │
│ ┌───────────────────────────────┐ │
│ │ border │ │
│ │ ┌───────────────────────┐ │ │
│ │ │ padding │ │ │
│ │ │ ┌─────────────────┐ │ │ │
│ │ │ │ content │ │ │ │
│ │ │ │ (width x height)│ │ │ │
│ │ │ └─────────────────┘ │ │ │
│ │ └───────────────────────┘ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
box-sizing: content-box (default)
width = content width only
actual width = width + padding + border
box-sizing: border-box (recommended)
width = content + padding + border
actual width = width
6.2 Block vs Inline
Block elements (div, p, h1...):
┌──────────────────────────────┐
│ Block 1 (takes full width) │
├──────────────────────────────┤
│ Block 2 │
├──────────────────────────────┤
│ Block 3 │
└──────────────────────────────┘
Inline elements (span, a, strong...):
[inline1][inline2][inline3]
[inline4 wraps to next line...]
Inline-block:
[inline-block1] [inline-block2]
(can set width/height like block, flows inline)
6.3 Layout Process
- Start from root: Determine viewport size
- Block layout: Stack blocks top to bottom
- Inline layout: Flow inline elements left to right
- Float handling: Adjust text flow
- Position calculation: Process relative, absolute, fixed, sticky
- Finalize sizes: Calculate final position and size of all elements
7. Paint and Compositing
7.1 Paint
After layout, each element is drawn as actual pixels.
Paint order (z-order):
1. Background color
2. Background image
3. Border
4. Children
5. Outline
Painting is performed across multiple layers.
7.2 Layer Creation Conditions
New compositing layers are created when:
transform: translate3d()ortranslateZ()will-change: transformorwill-change: opacityposition: fixed- CSS animation/transition applied to opacity, transform
- Video, canvas elements
filterproperty used
/* Force compositing layer creation */
.layer {
will-change: transform;
/* or */
transform: translateZ(0);
}
7.3 Compositing
The GPU merges all layers into the final output.
Compositing steps:
1. Split into layers (Layer Tree)
2. Divide each layer into tiles
3. Rasterize tiles (convert to bitmaps on GPU)
4. Generate draw quads (screen position info)
5. Create compositor frame (final composite)
6. Display on screen via GPU
Rendering pipeline comparison:
JS/CSS change
→ Style → Layout → Paint → Composite (full pipeline)
→ Style → Paint → Composite (skip Layout)
→ Style → Composite (fastest!)
7.4 GPU-Accelerated Properties
/* Composite-only properties (fastest) */
.fast {
transform: translate(10px, 20px); /* position */
transform: scale(1.2); /* size */
transform: rotate(45deg); /* rotation */
opacity: 0.5; /* transparency */
}
/* Paint triggers (medium) */
.medium {
color: red;
background-color: blue;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
/* Layout triggers (slowest) */
.slow {
width: 200px;
height: 100px;
margin: 10px;
padding: 20px;
font-size: 18px;
}
8. Critical Rendering Path Optimization
8.1 Eliminate Render-Blocking Resources
<!-- CSS: Inline Critical CSS -->
<style>
/* Only minimum CSS needed for first screen */
body { margin: 0; font-family: system-ui; }
.hero { background: #3b82f6; color: white; padding: 2rem; }
</style>
<!-- Load remaining CSS asynchronously -->
<link rel="preload" href="styles.css" as="style"
onload="this.onload=null;this.rel='stylesheet'" />
<noscript><link rel="stylesheet" href="styles.css" /></noscript>
<!-- JS: Prevent parser blocking -->
<script defer src="app.js"></script>
8.2 Resource Hints
<!-- DNS pre-lookup -->
<link rel="dns-prefetch" href="//api.example.com" />
<!-- Pre-connect (DNS + TCP + TLS) -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<!-- Preload critical resources -->
<link rel="preload" href="hero.webp" as="image" />
<link rel="preload" href="critical.js" as="script" />
<!-- Prefetch next navigation resources -->
<link rel="prefetch" href="/about" />
<!-- Pre-render entire next page -->
<link rel="prerender" href="/likely-next-page" />
8.3 Optimization Checklist
- Place CSS in head: Minimize render blocking
- Inline Critical CSS: Only CSS needed for first screen
- Use defer/async for JS: Prevent parser blocking
- Compress resources: gzip/brotli compression
- Optimize images: WebP/AVIF, lazy loading, srcset
- Optimize fonts: font-display: swap, preload
- Use HTTP/2: Multiplexing for parallel requests
9. Reflow vs Repaint
9.1 Reflow (Layout Recalculation)
An expensive operation that recalculates layout.
Reflow triggers:
- Adding/removing elements
- Changing element size (width, height, padding, margin, border)
- Font size changes
- Text content changes
- Window resize
- Reading computed styles (offsetWidth, getComputedStyle, etc.)
9.2 Repaint
A relatively cheaper operation that only changes visual properties.
Repaint-only triggers (no reflow):
- color, background-color
- visibility
- box-shadow
- outline
9.3 DOM Read/Write Batching
// Bad: Interleaved reads and writes cause forced reflow
const items = document.querySelectorAll('.item');
items.forEach(item => {
const width = item.offsetWidth; // Read → forced reflow!
item.style.width = width + 10 + 'px'; // Write
});
// Good: Batch all reads first, then all writes
const widths = [];
items.forEach(item => {
widths.push(item.offsetWidth); // All reads first
});
items.forEach((item, i) => {
item.style.width = widths[i] + 10 + 'px'; // All writes after
});
9.4 Why Virtual DOM Exists
Direct DOM manipulation:
Change 1 → Reflow → Repaint
Change 2 → Reflow → Repaint
Change 3 → Reflow → Repaint
Virtual DOM (React):
Calculate changes 1, 2, 3 in memory (diff)
→ Minimal actual DOM changes
→ 1 Reflow → 1 Repaint
10. Event Loop and Task Queue
10.1 JavaScript Runtime Structure
┌─────────────────────────┐
│ Call Stack │
│ (execution contexts) │
└───────────┬─────────────┘
│
┌───────────▼─────────────┐
│ Event Loop │
│ (checks queues when │
│ stack is empty) │
└───┬─────────────────┬───┘
│ │
┌───▼───┐ ┌────▼────┐
│Micro │ │ Macro │
│Task │ │ Task │
│Queue │ │ Queue │
└───────┘ └─────────┘
10.2 Macrotask vs Microtask
console.log('1: Sync');
setTimeout(() => {
console.log('2: Macrotask (setTimeout)');
}, 0);
Promise.resolve().then(() => {
console.log('3: Microtask (Promise)');
});
queueMicrotask(() => {
console.log('4: Microtask (queueMicrotask)');
});
console.log('5: Sync');
// Output order:
// 1: Sync
// 5: Sync
// 3: Microtask (Promise)
// 4: Microtask (queueMicrotask)
// 2: Macrotask (setTimeout)
Macrotask (Task Queue):
- setTimeout, setInterval
- I/O callbacks
- UI rendering
- requestAnimationFrame
Microtask (Microtask Queue):
- Promise.then/catch/finally
- queueMicrotask
- MutationObserver
10.3 Event Loop Execution Order
1. Execute all synchronous code in Call Stack
2. When Call Stack is empty:
a. Execute ALL tasks in Microtask Queue (until empty)
b. If rendering is needed, perform rendering
c. Take ONE task from Macrotask Queue and execute
3. Go back to step 2 and repeat
10.4 requestAnimationFrame (rAF)
// rAF: Executes callback right before next repaint
// Usually 60fps = ~16.67ms interval
function animate() {
// Animation logic
element.style.transform = `translateX(${position}px)`;
position += 2;
if (position < 500) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
rAF vs setTimeout:
// Bad: setTimeout for animation
// Frame drops, inconsistent intervals
setInterval(() => {
moveElement();
}, 16);
// Good: rAF
// Synced with browser refresh, smooth 60fps
function animate() {
moveElement();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
10.5 requestIdleCallback
// Executes when browser is idle
// Use for non-critical tasks
requestIdleCallback((deadline) => {
// Check remaining time with deadline.timeRemaining()
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
performTask(tasks.shift());
}
if (tasks.length > 0) {
requestIdleCallback(processRemainingTasks);
}
});
11. Web Workers and OffscreenCanvas
11.1 Web Worker
Execute JavaScript in the background without blocking the main thread.
// main.js
const worker = new Worker('worker.js');
worker.postMessage({ type: 'HEAVY_CALC', data: bigArray });
worker.onmessage = (event) => {
console.log('Result:', event.data.result);
};
// worker.js
self.onmessage = (event) => {
if (event.data.type === 'HEAVY_CALC') {
const result = heavyComputation(event.data.data);
self.postMessage({ result });
}
};
function heavyComputation(data) {
// CPU-intensive work (sorting, encryption, image processing, etc.)
return data.sort((a, b) => a - b);
}
11.2 Worker Types
// 1. Dedicated Worker: 1:1 relationship
const dedicated = new Worker('worker.js');
// 2. Shared Worker: Shared across tabs/iframes
const shared = new SharedWorker('shared.js');
shared.port.start();
shared.port.postMessage('hello');
// 3. Service Worker: Network proxy, offline support
navigator.serviceWorker.register('/sw.js');
11.3 OffscreenCanvas
Perform canvas rendering in a Worker.
// main.js
const canvas = document.getElementById('canvas');
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker('render-worker.js');
worker.postMessage({ canvas: offscreen }, [offscreen]);
// render-worker.js
self.onmessage = (event) => {
const canvas = event.data.canvas;
const ctx = canvas.getContext('2d');
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Complex rendering logic...
ctx.fillStyle = '#3b82f6';
ctx.fillRect(x, y, 50, 50);
requestAnimationFrame(draw);
}
draw();
};
12. DevTools Performance Panel Guide
12.1 Using the Performance Tab
1. Open DevTools (F12 or Cmd+Option+I)
2. Select Performance tab
3. Start recording (Ctrl+E)
4. Interact with page
5. Stop recording
Interpreting results:
- FPS chart: Green = 60fps, Red = frame drops
- CPU chart: Colors indicate work type
- Yellow: JavaScript execution
- Purple: Layout (reflow)
- Green: Paint
- Gray: Other
12.2 Key Metrics
Core Web Vitals:
- LCP (Largest Contentful Paint): under 2.5s → good
- INP (Interaction to Next Paint): under 200ms → good
- CLS (Cumulative Layout Shift): under 0.1 → good
Additional metrics:
- FCP (First Contentful Paint): first content rendered
- TTFB (Time to First Byte): server response time
- TBT (Total Blocking Time): main thread blocking
12.3 Common Performance Problem Patterns
1. Long Tasks:
- Main thread blocked for 50ms+
- Solution: Code splitting, Web Workers
2. Layout Thrashing:
- Forced reflows from interleaved reads/writes
- Solution: Batch reads/writes
3. Excessive Paint:
- Unnecessary area repaints
- Solution: will-change, use transform
4. Large DOM Tree:
- 1500+ nodes degrade performance
- Solution: Virtualization (react-virtualized, tanstack-virtual)
13. Interview Questions and Quiz
Top 10 Interview Questions
Q1: What happens when you type a URL in the browser address bar?
After URL parsing, DNS lookup resolves the IP address. TCP 3-way handshake establishes connection, plus TLS handshake for HTTPS. The HTTP response delivers HTML, which the parser builds into a DOM tree. CSS is parsed into CSSOM. DOM and CSSOM combine into a render tree, layout calculates position/size, paint draws pixels, and compositing merges layers via GPU for final display.
Q2: Explain Critical Rendering Path and how to optimize it.
CRP is the path from receiving HTML to rendering the first screen. CSS is render-blocking, so inline Critical CSS and defer non-critical CSS. Use defer/async on JS to prevent parser blocking. Preload critical resources and eliminate unnecessary CSS/JS.
Q3: What is the difference between Reflow and Repaint?
Reflow recalculates layout (position, size changes) and is expensive. Repaint only changes visual properties (color, shadow) and is relatively cheaper. Reflow always triggers repaint, but repaint can occur without reflow.
Q4: What is the difference between display: none and visibility: hidden?
display: none completely removes the element from the render tree -- it takes no space. Toggling triggers reflow. visibility: hidden keeps the element in the render tree, it takes up space, and only triggers repaint.
Q5: What is the execution order of Microtasks and Macrotasks in the Event Loop?
After synchronous code executes and the Call Stack empties, all Microtask Queue tasks are processed first. Once the Microtask Queue is empty, rendering occurs if needed, then one task from the Macrotask Queue executes. This repeats.
Q6: What is requestAnimationFrame and how does it differ from setTimeout?
rAF executes callbacks right before the next repaint, ensuring smooth 60fps animation. setTimeout does not guarantee exact timing and is not synced with the browser refresh rate, causing potential frame drops.
Q7: What is the difference between defer and async scripts?
Both download scripts in parallel with HTML parsing. defer executes after DOM completion in script order, before DOMContentLoaded. async executes immediately when downloaded with no order guarantee.
Q8: Which CSS properties benefit from GPU acceleration?
transform, opacity, and filter are the primary ones. These properties are handled at the Composite stage, skipping layout and paint. You can hint the browser with will-change.
Q9: What are Web Workers used for and what are their limitations?
Workers run CPU-intensive tasks (sorting, encryption, image processing) without blocking the main thread. Limitations include no direct DOM access and communication only through postMessage.
Q10: Explain why Virtual DOM is needed from a rendering pipeline perspective.
Directly manipulating DOM multiple times triggers reflow/repaint for each change. Virtual DOM diffs changes in memory, then performs minimal actual DOM updates, reducing the number of reflows.
5 Quiz Questions
Q1: What is the console output order of this code?
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');
Answer: A, D, C, B
Synchronous code (A, D) runs first, then Microtask Promise (C), then Macrotask setTimeout (B).
Q2: Which CSS property changes trigger only Compositing?
Answer: transform and opacity. These are processed by the GPU composite layer, skipping Layout and Paint stages. filter is also handled at the composite layer.
Q3: What is the difference between preload and prefetch?
Answer: preload loads critical resources needed for the current page with high priority. prefetch fetches resources expected for the next navigation with low priority.
Q4: What is Layout Thrashing?
Answer: When DOM reads (offsetWidth, etc.) and writes (style changes) are interleaved, the browser must perform a forced reflow each time to return accurate values. The solution is to batch all reads first, then all writes.
Q5: Explain the rendering differences between display: none, visibility: hidden, and opacity: 0.
Answer:
display: none: Completely removed from render tree, no space, triggers reflow on togglevisibility: hidden: Stays in render tree, takes space, triggers repaint onlyopacity: 0: Stays in render tree, takes space, can be handled by composite layer, still receives events
References
- Google - How Browsers Work
- MDN - Critical Rendering Path
- Chrome - Inside Look at Modern Web Browser
- web.dev - Rendering Performance
- MDN - Event Loop
- web.dev - Optimize LCP
- Chrome - Compositing
- MDN - Web Workers API
- web.dev - requestAnimationFrame
- Chrome DevTools - Performance
- web.dev - Core Web Vitals
- Philip Roberts - Event Loop Talk
- CSS Triggers