The Critical Rendering Path (CRP) is the sequence of steps a browser follows to convert HTML, CSS, and JavaScript into pixels on the screen. It directly affects how quickly users see and interact with your webpage.
What Is a Browser?
A browser is a software application that retrieves resources from the network and presents interactive web content to the user.
Examples include:
- Chrome
- Firefox
- Edge
- Safari
A browser does much more than display HTML.
It has to:
Receive URL
↓
Find server
↓
Connect to server
↓
Download resources
↓
Parse HTML
↓
Build DOM
↓
Parse CSS
↓
Build CSSOM
↓
Calculate layout
↓
Paint pixels
↓
Execute JavaScript
↓
Respond to user interaction
↓
Update the page1 DNS Resolution
A URL is a Uniform Resource Locator.
Example:
https://www.example.com:443/products?id=10#reviewshttps://
│
└── Scheme / Protocol
www.example.com
│
└── Hostname
:443
│
└── Port
/products
│
└── Path
?id=10
│
└── Query string
#reviews
│
└── FragmentSo:
URL
├── Scheme
├── Host
│ ├── Subdomain
│ └── Domain
├── Port
├── Path
├── Query
└── FragmentDNS
The browser cannot normally communicate with:
example.comIt needs an IP address.
For example, conceptually:
URL
├── Scheme
├── Host
│ ├── Subdomain
│ └── Domain
├── Port
├── Path
├── Query
└── FragmentDNS means:
Domain Name System
It maps names to network addresses.
A simplified lookup:
Browser
│
│ "What is example.com?"
▼
DNS Resolver
│
▼
DNS Server
│
▼
IP AddressThere can be several layers of caching:
Browser DNS Cache
↓
OS DNS Cache
↓
Router / Local Resolver
↓
Recursive DNS Resolver
↓
Authoritative DNS ServerWhen we type a URL (https://example.com) and press Enter, the browser needs to figure out the IP address of the web server hosting the site. This happens through DNS Resolution.
- Check Browser Cache: The browser first checks its own cache for stored IP address.
- Check OS Cache: If not found, it asks the operating system's DNS cache.
- Query DNS Server: If still not found, it queries a recursive DNS server, which eventually resolves the domain name to an IP address.
Example:
URL: https://example.com -> IP Address: 97.143.216.55Once IP is found, the browser initiates the HTTP request to that server.
2 Establishing a Connection (TCP Handshake + TLS Handshake)
To communicate with the server, the browser performs:
TCP Handshake
A three-step process (SYN, SYN-ACK, ACK).
TCP provides reliable, ordered delivery.
It handles things such as:
- connection establishment
- sequencing
- retransmission
- flow control
- congestion control
A simplified TCP connection:
Client Server
SYN ────────────────>
<──────── SYN-ACK
ACK ────────────────>This is the famous TCP three-way handshake.
TLS Handshake (for HTTPS)
If you are using: https://
the connection is protected using TLS.
TLS provides properties including:
- encryption
- integrity
- server authentication
HTTP Request
Once connected, the browser sends an HTTP request to the server. A typical request includes:
- Method:
GET(for fetching resources) orPOST,PUTetc. - Headers: Metadata such as
User-Agent,Accept-Encoding, andCookies.
Example Request:
GET /products HTTP/1.1
Host: example.com
Accept: text/html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64)Server Response and Content Fetching
The server processes the request and sends back an HTTP response, containing:
- Status Code: (e.g.,
200 OK,404 Not Found) - Headers: Cache-Control, Content-Type, etc.
- Body: The actual HTML, CSS, or JavaScript content.
Example Response:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
<html>
...
</html>The browser now has the raw HTML content but needs additional assets (CSS, JS, images, etc.), so it makes more requests to fetch these resources.
3 Parsing HTML & Constructing the DOM
The HTML response is now parsed into a structured tree known as the DOM (Document Object Model).
Example:
Consider the HTML snippet:
<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello World</h1>
<p>Welcome!</p>
</body>
</html>The browser doesn't simply display this string. It parses it.
Conceptually:
HTML text
↓
HTML Parser
↓
DOMDocument
│
└── html
│
└── body
├── h1
│ └── "Hello"
│
└── p
└── "Welcome"This tree is the DOM. Each node in the DOM represents an HTML element and stores metadata about it.
HTML parse may encounter resources to fetch as it goes:
For instance:
<link rel="stylesheet" href="styles.css">These prompt the browser to request the CSS file over the network. This happen in parallel to parsing. The parser can keep going while those loads occur, with once big exception: scripts.
Handling <script> tags:
If the HTML parse comes across a <script> tag, it pauses parsing and must execute the script before continuing (by default). This is because script can use document.write() or other DOM manipulation that can alter the page structure or content that's still coming in. By executing immediately at that point, the browser preserves the correct order of operations relative to the HTML. The parser therefore hands off the script to the JavaScript engine for execution and only when the script finishes (and any DOM changes it did are applied) can HTML parsing resume. This script execution blocking behavior is why including large <script> files in the head can slow down page rendering – the HTML parsing can't continue until the script is downloaded and run.
However, developers ca modify this behvior with attributes: adding defer or async to a <script> tag. It changes how browser handles it.
defer:
<script src=app.js defer></script>HTML parsing continues while app.js downloads. Script executes after HTML parsing is finished. Deferred scripts execute in the order they appear. Execute before DOMContentLoaded. Best for scripts that depend on the DOM or on other scripts.
async:
<script src=analytics.js async></script>HTML parsing continues while the script downloads. The script executes as soon as it finishes downloading. Execution can happen while HTML is still being parsed. Multiple async scripts have no guaranteed execution order. It doesn't wait for DOMContentLoaded.
Example:
If you have:
<script src=jquery.js defer></script>
<script src=app.js defer></script>jquery.js will execute before app.js, even if app.js finishes downloading first.
But with:
<script src=jquery.js async></script>
<script src=app.js async></script>whichever finishes downloading first may execute first. So app.js cannot safely assume that jquery.js has already executed.
Rule of Thumb
Use defer by default for ordinary application JavaScript:
<script src=app.js defer></script>Use async for independent script where execution order doesn't matter, such as analytics or advertising scripts.
4 Parsing CSS & Constructing the CSSOM
Next, the browser processes CSS to build the CSSOM (CSS Object Model), which defines how elements should look.
Example:
<h1 >Hello</h1>.title {
color: blue;
font-size: 32px;
}The browser parses the CSS.
Conceptually:
CSS
↓
CSS Parser
↓
CSSOMRender-Blocking CSS
CSS can prevent the browser from painting the page until the CSS needed for that rendering is available.
But does CSS stop HTML parsing?
This is where it gets confusing.
Suppose:
<link rel="stylesheet" href="style.css">
<h1>Hello</h1>
<p>Welcome</p>While style.css is downloading, the browser can generally continue reading/parsing the HTML.
Read HTML
↓
Find CSS
↓
Download CSS ───────────┐
│
Continue reading HTML │
↓ │
<h1>Hello</h1> │
↓ │
<p>Welcome</p> │
↓
CSS arrives
↓
PAINTSo: CSS doesn't stop HTML parsing, but CSS can stop the browser from rendering/painting the page.
One sentence to remember:
CSS: “Don't paint until you know how things should look.”
Normal JS: “Stop reading HTML until I have downloaded and executed this JavaScript.”
5 Execute JavaScript
If the browser encounters:
<script src=app.js></script>JavaScript may:
- modify the DOM
- modify CSS
- create new elements
- remove elements
Because of this, JavaScript can block rendering unless it's loaded with defer or async.
Example:
document.querySelector("h1").textContent = "Welcome";6 Render Tree
The Render Tree is build by combining the DOM and CSSOM.
Example:
Render Tree
├── h1 (visible)
├── color: blue
├── font-size: 20pxOnly visible elements (excluding <head>, <meta, etc.) are included in the Render Tree.
Elements like:
display: none;are not included in the render tree because they won't be displayed.
7 Layout
Now the browser calculates exact positions and sizes for each element based on:
- CSS rules (like width, height, margin, etc.)
- Parent-child relationships.
- The viewport size.
8 Painting – Drawing Pixels on Screen
Now that the layout is determined, the browser paints each element onto the screen.
Steps in Painting:
- Backgrounds and borders are drawn first.
- Text and images are drawn next.
- Shadows, transformations, and effects are applied last.
9 Compositing & Final Rendering
Modern browsers often use multiple layers.
For example:
Layer 1
Background
Layer 2
Content
Layer 3
Animation
Layer 4
Fixed headerThese layers can then be composited.
GPU acceleration may be involved for some operations.
Where JavaScript Fits In
By default, JavaScript is a parser-blocking resource. When the browser is building the DOM and encounters a standard <script> tag, it completely pauses the HTML parsing, downloading the script, executes it and only then resumes building the DOM. This happens because JavaScript has the power to modify the DOM.
To prevent JavaScript from stalling your page load times, you have to use modern loading strategies:
Why You Should Care: Wrigint Browser-Friendly Code
Understanding the browser's architecture changes how you write frontend code. Once you know how the browser moves from HTML/CSS/JavaScript -> DOM/CSSOM -> Layout -> Paint -> Compositing, you can make decisions that reduce unnecessary work and improve perceived performance.
1 Optimize the Critical Rendering Path
When a browser loads a page, it needs to obtain and process resources before it can produce the initial rendering.
The simplified process looks like:
HTML
↓
DOM
↓
CSS
↓
CSSOM
↓
Render information
↓
Layout
↓
Paint
↓
Composite
↓
ScreenCSS can be render-blocking because the browser needs style information to correctly determine how elements should be displayed.
Therefore:
- Keep critical CSS small.
- Avoid unnecessarily large CSS files during initial loading.
- Load non-critical CSS when appropriate.
- Avoid unnecessary render-blocking resources.
- Optimize fonts and other resources required for the initial view.
2 Avoid Layout Thrashing
JavaScript can modify the DOM and CSS.
For example:
element.style.width = "500px";
element.style.height = "300px";
element.style.top = "100px";Changes like these can require the browser to recalculate element geometry.
That can trigger layout work.
The problem becomes worse when JavaScript repeatedly alternates between:
- changing layout
- reading layout information
- changing layout again
- reading layout again
3 Defer Non-Critical JavaScript
JavaScript can affect how quickly the browser parses and renders a page.
Consider:
<script src=analytics.js></script>Depending on how the script is loaded and where it appears, it can interfere with HTML parsing.
For scripts that aren't required immediately, you can use:
<script src=analytics.js defer></script>or
<script src=analytics.js async></script>But defer and async are not interchangeable.
defer
For classic scripts, defer generally means:
Download script
│
├── HTML parsing continues
│
▼
HTML parsing completes
│
▼
Deferred scripts executeDeferred scripts preserve their document order relative to other deferred classic scripts.
This makes defer useful for many application scripts that depend on the document being parsed.
async:
With async:
Download script
│
├── HTML parsing continues
│
▼
Download completes
│
▼
Script executesExecution occurs as soon as the script is ready, so ordering between independent async script should not be relied upon.
This makes asyncparticularly useful for independent scripts such as some analytics integrations.
Therefore:
defer
→ download without blocking parsing
→ execute after parsing
→ preserve order
async
→ download without blocking parsing
→ execute as soon as ready
→ execution order is not guaranteed


Join the discussion
Sign in with your account to post comments, reply to others, and participate in the conversation.
Login to Comment