Skip to main content

Critical Rendering Path Optimization

Answer

The Critical Rendering Path (CRP) is the sequence of steps the browser takes to convert HTML, CSS, and JavaScript into rendered pixels. Optimizing it reduces time to first meaningful paint.

Critical Rendering Path

Key Metrics

Optimization Strategies

1. Minimize Critical Resources

<!-- ❌ Render-blocking CSS -->
<link rel="stylesheet" href="all-styles.css" />

<!-- ✅ Split critical and non-critical CSS -->
<style>
/* Inline critical CSS */
.header {
...;
}
.hero {
...;
}
</style>
<link
rel="preload"
href="full-styles.css"
as="style"
onload="this.rel='stylesheet'"
/>

2. Defer Non-Critical JavaScript

<!-- ❌ Parser-blocking -->
<script src="analytics.js"></script>

<!-- ✅ Defer non-critical scripts -->
<script defer src="analytics.js"></script>
<script async src="third-party.js"></script>

3. Preload Critical Resources

<head>
<!-- Preload critical assets -->
<link rel="preload" href="hero-image.webp" as="image" />
<link rel="preload" href="main-font.woff2" as="font" crossorigin />
<link rel="preload" href="critical.css" as="style" />

<!-- Preconnect to required origins -->
<link rel="preconnect" href="https://api.example.com" />
<link rel="dns-prefetch" href="https://cdn.example.com" />
</head>

4. Optimize CSS Delivery

<!-- Critical CSS inline -->
<head>
<style>
/* Above-the-fold styles only */
body {
margin: 0;
font-family: system-ui;
}
.header {
height: 60px;
background: #333;
}
.hero {
min-height: 400px;
}
</style>
</head>

<!-- Load full 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>

Resource Priority

Measuring CRP

// Performance API
const timing = performance.getEntriesByType("navigation")[0];

console.log("TTFB:", timing.responseStart - timing.requestStart);
console.log("DOM Interactive:", timing.domInteractive);
console.log("DOM Complete:", timing.domComplete);

// Core Web Vitals
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log("LCP:", entry.startTime);
}
}).observe({ entryTypes: ["largest-contentful-paint"] });

Before vs After Optimization

MetricBeforeAfter
Render-blocking resources51
Critical CSS size150KB15KB
First Contentful Paint3.2s1.1s
Time to Interactive5.5s2.8s

Tools for Analysis

  • Lighthouse: Built into Chrome DevTools
  • WebPageTest: Detailed waterfall analysis
  • Chrome DevTools Coverage: Find unused CSS/JS
  • Critical: Extract critical CSS automatically

Key Points

  • Inline critical CSS, defer the rest
  • Use defer and async for JavaScript
  • Preload critical assets
  • Minimize render-blocking resources
  • Measure with Real User Monitoring (RUM)