CrackFrontendCF
Resources
Practice
CrackFrontend

Your guide to mastering frontend interviews

Resources

LibraryPracticeDonate

Company

About UsContact

Legal

Privacy PolicyTerms of Service

Built with โค๏ธ by Tushar Khanna

CrackFrontendCF
Resources
Practice

๐ŸŽฏ Critical Rendering Path: Deep Dive into Browser Rendering Cycle

Optimize web performance by understanding the critical rendering path, including resource prioritization, async loading, and reducing render-blocking.

Understanding how browsers render web pages is essential for performance optimization. This guide explains the Critical Rendering Path (CRP), rendering stages, performance metrics, and practical optimization strategies. -- ๐Ÿ’ก What is the Critical Rendering Path? The Critical Rendering Path is the sequence of steps a browser takes to: 1. Parse HTML and CSS 2. Construct the DOM and CSSOM 3. Create the render tree 4. Calculate layout 5. Paint pixels on screen The CRP directly impacts First Contentful Paint (FCP) and Largest Contentful Paint (LCP), which are key Web Vitals metrics. Why it matters: Any resource that blocks the CRP delays when your page becomes visible and interactive. -- โš ๏ธ What is Render-Blocking? Render-blocking means the browser pauses or delays rendering while waiting for a resource to be fetched and processed. Critical Render-Blocking Resources: Blocks Rendering Impact โœ… Yes Highest priority JavaScript (default) Can modify DOM/CSSOM/styles โŒ No Ideal for most JavaScript (async) Runs independently โš ๏ธ Partial Use Images Loaded separately *May execute before rendering completes, but doesn't intentionally block it. Render-Blocking Impact on Performance: -- ๐Ÿง  The Complete Rendering Pipeline Stage 1: Network & Resource Loading Key Points: DNS lookup translates domain to IP address TCP connection established HTTP headers sent with conditional caching info HTML bytes start streaming to browser Optimization: -- Stage 2: HTML Parsing -DOM Tree Process: Browser receives HTML as a stream HTML Parser tokenizes (, text, attributes) Tokens converted to nodes Parent-child relationships established Example: Results in DOM tree: Key Point: Parsing is streamlined visible content can render before entire HTML is parsed. -- Stage 3: CSS Parsing -CSSOM Tree Process: CSS from or tags triggers download CSS Parser processes selectors and rules Cascade and specificity applied CSSOM (CSS Object Model) constructed Example: Results in CSSOM tree: Critical Detail: CSS is render-blocking. The browser waits for CSS before rendering because it needs all styles to avoid re-rendering. Why CSS Blocks Rendering: Timeline comparison: Mitigation Strategies: -- Stage 4: JavaScript Execution โš ๏ธ RENDER-BLOCKING (by default) JavaScript can significantly impact the rendering pipeline. This is one of the most critical optimizations. โŒ Default Behavior: RENDER-BLOCKING Flow: Impact: Every second of JS execution delays First Contentful Paint. โœ… With Attribute: NOT RENDER-BLOCKING Flow: Order guaranteed: Multiple scripts run in order. When to use: For application framework (React, Vue, etc.), main app code. โš ๏ธ With Attribute: NOT RENDER-BLOCKING PARSING, but may interrupt rendering Flow: Order NOT guaranteed: Multiple scripts run independently. When to use: Analytics, third-party ads, non-critical tracking. Modern: (ES6 Modules) JavaScript's Render-Blocking Cost: Common Render-Blocking JavaScript Patterns to AVOID: -- Stage 5: Render Tree Construction (DOM CSSOM) Process: Browser combines DOM structure with CSS styles Invisible elements removed: (completely hidden) and tags Hidden meta tags Visibility elements retained: (reserved in layout) (still part of render tree) (still rendered) Example: Resulting Render Tree: Key Point: Each render tree node = box with CSS computed styles. -- Stage 6: Layout Calculation (Reflow) Process: Browser calculates exact position and size for each element Considers viewport dimensions Applies box model (margin, border, padding, content) Hierarchical calculation (parent -children) Example: Common Reflow-Triggering Operations: Optimization Example: -- Stage 7: Painting Process: Convert layout information to actual pixels Draw backgrounds, borders, text, shadows Create paint records for each visual element May involve multiple paint layers Example: Paint Performance Layers: -- Stage 8: Compositing Process: Combines multiple paint layers Applies z-index and stacking context GPU blends and transforms layers Final bitmap sent to screen Optimize for Compositing: -- ๐Ÿ“Š Complete CRP Timeline -- ๐Ÿ”„ JavaScript Event Loop & Rendering The JavaScript event loop is intrinsically connected to the browser's rendering cycle. Understanding this relationship is crucial for performance optimization. How Event Loop Interacts with Rendering Microtasks vs Macrotasks vs Rendering requestAnimationFrame's Special Role (RAF) is not a microtask or macrotaskโ€”it's scheduled during the rendering phase: Why RAF timing matters: Rendering Occurs BETWEEN Macrotasks The browser checks for rendering work between every macrotask: Microtasks Block Rendering All microtasks must complete before rendering can occur: Optimization: Use macrotasks for heavy work to allow rendering: Event Loop & Performance Monitoring Complete Event Loop Timing Example Key Implications for Rendering Queue Timing Main Immediate โŒ No Microtask Immediate (before render) N/A Microtask Immediate (before render) Metric Target FCP (First Contentful Paint) < 1.8s LCP (Largest Contentful Paint) < 2.5s CLS (Cumulative Layout Shift) < 0.1 FID (First Input Delay) < 100ms TTFB (Time to First Byte) < 600ms | JavaScript Timing Events -- ๐ŸŽฏ Optimization Strategies 1. Minimize Render-Blocking CSS Impact: Inline critical CSS: FCP reduced by 0.5-2 seconds Media queries: Non-blocking for unused device types Preload: Starts CSS download earlier 2. Eliminate JavaScript Render-Blocking Impact on FCP: 3. CSS Optimization 4. Use Resource Hints for Critical Resources 5. Optimize Font Loading 6. Defer Non-Critical Images 4. Minimize Reflows & Repaints 5. Use GPU Acceleration 6. Image & Font Optimization -- ๐Ÿ› ๏ธ Browser DevTools: Identifying Render-Blocking Resources Chrome DevTools Performance Tab Network Tab Analysis Lighthouse Audit -- ๐Ÿ“Š Measuring Render-Blocking Impact Performance API: Track CRP Metrics Real User Monitoring (RUM) -- ๐ŸŽฏ Framework-Specific Render-Blocking Strategies React Applications Vue.js Applications Angular Applications -- ๐Ÿ“ฑ Mobile-Specific Considerations Mobile Render-Blocking Challenges Mobile Optimization Strategies -- ๐Ÿ”ฎ Advanced Techniques Critical Resource Hints Service Worker Caching Progressive Loading with Intersection Observer -- ๐Ÿ“ˆ Real-World Case Studies Case Study 1: E-commerce Site (2.1s -0.8s FCP) Before: After: Results: FCP: 2.1s -0.8s (62% improvement) LCP: 3.2s -1.5s (53% improvement) Total blocking time: 1.8s -0.2s (89% reduction) Case Study 2: News Website (3.5s -1.2s FCP) Problem: Heavy third-party scripts blocking rendering. Solution: Results: FCP: 3.5s -1.2s (66% improvement) User engagement: +40% Bounce rate: -25% -- ๐Ÿ” Summary CRP is fundamental to page performance understanding it is essential for optimization CSS is render-blocking by default use inline critical CSS, defer non-critical JavaScript blocks HTML parsing by default use for most scripts, for analytics Render-blocking resources directly impact FCP/LCP minimize their count and size Third-party scripts are highest risk always load with , consider loading at end of page Reflows are expensive batch DOM changes and use CSS for animations GPU acceleration use transform and opacity for smooth animations Prioritize above-the-fold inline critical CSS, defer non-critical resources, preload important files Measure performance use DevTools, Lighthouse, and Web Vitals APIs to track improvements Test on real devices performance varies significantly across devices and networks Monitor third-party impact track which resources are render-blocking and for how long -- ๐ŸŒ Related Resources Browser Rendering Basics () Visual flow of rendering stages Promises and Async Patterns () Understand async JavaScript patterns JavaScript Event Loop () Deep understanding of microtasks, macrotasks, and rendering synchronization Performance API and Monitoring Web Vitals Google's performance metrics Chrome DevTools Performance MDN: Event Loop MDN: queueMicrotask -- ๐Ÿš€ Future Standards & Modern APIs Speculation Rules API (Chrome 121+) Priority Hints Content Visibility API CSS Cascade Layers (Chrome 99+) -- ๐Ÿ“‹ Summary -- <!-quiz-start --Q1: What is the primary reason CSS is considered render-blocking? [ ] CSS files are always larger than JavaScript files [x] The browser needs all styles before creating the render tree to avoid FOUC [ ] CSS must be downloaded before HTML can be parsed [ ] CSS blocks all network requests Q2: Which approach is recommended for optimizing JavaScript render-blocking? [ ] Use for all scripts including the main application bundle [ ] Place all scripts in the without any attributes [x] Use for application code and for non-critical scripts like analytics [ ] Inline all JavaScript to avoid network requests Q3: What happens when microtasks (like Promise.then callbacks) are processing in the event loop? [ ] Rendering can occur between each microtask [ ] Microtasks are processed after rendering [x] All microtasks must complete before rendering can occur [ ] Microtasks and rendering happen simultaneously <!-quiz-end --
Browser & Patterns
๐ŸŒ Browser Rendering: How Browsers Display Web Pages
hard
๐ŸŽฏ Critical Rendering Path: Deep Dive into Browser Rendering Cycle
hard
๐ŸŽญ The Facade Pattern in JavaScript โ€“ Simplifying Complex Systems
medium
๐Ÿญ The Factory Pattern in JavaScript โ€“ A Practical Guide
medium
๐Ÿ“˜ Most Important Design Patterns in JavaScript
medium
๐Ÿง  When to Use Which Design Pattern in JavaScript
medium
๐Ÿ“ฆ The Module Pattern in JavaScript โ€” A Deep Dive
medium
๐Ÿงญ MVC (Modelโ€‘Viewโ€‘Controller) โ€” A Frontโ€‘End Deep Dive
medium
๐Ÿ‘€ Observer Pattern โ€” React to Change Automatically
medium
๐Ÿ”’ Singleton โ€” Oneโ€ฏInstance to Rule Them All
medium
๐ŸŽฏ Frontend Interview Preparation Guide: 15 Years of Experience (Staff/Principal Engineer Level)
hard
๐ŸŽฏ 1-Month Interview Preparation Guide: 2 Hours Daily Strategy
hard
๐ŸŽฏ 1-Month Staff-Level Interview Preparation Guide: 2 Hours Daily Strategy
hard
๐ŸŽฏ Web Rendering Strategies: Complete Guide to CSR, SSR, SSG, ISR & Hydration
hard
2 of 14
LibraryBrowser & Patterns2 of 14

๐ŸŽฏ Critical Rendering Path: Deep Dive into Browser Rendering Cycle

generalhard

Understanding how browsers render web pages is essential for performance optimization. This guide explains the Critical Rendering Path (CRP), rendering stages, performance metrics, and practical optimization strategies.


๐Ÿ’ก What is the Critical Rendering Path?

The Critical Rendering Path is the sequence of steps a browser takes to:

  1. Parse HTML and CSS
  2. Construct the DOM and CSSOM
  3. Create the render tree
  4. Calculate layout
  5. Paint pixels on screen

The CRP directly impacts First Contentful Paint (FCP) and Largest Contentful Paint (LCP), which are key Web Vitals metrics.

Why it matters: Any resource that blocks the CRP delays when your page becomes visible and interactive.


โš ๏ธ What is Render-Blocking?

Render-blocking means the browser pauses or delays rendering while waiting for a resource to be fetched and processed.

Critical Render-Blocking Resources:

ResourceBlocks RenderingWhyImpact
CSSโœ… YesNeeded for styles before paintingHighest priority
JavaScript (default)โœ… YesCan modify DOM/CSSOM/stylesMust be optimized
JavaScript (defer)โŒ No*Deferred until DOM readyIdeal for most
JavaScript (async)โŒ No*Runs independentlyBest for non-critical
Fontsโš ๏ธ PartialText may be invisible (FOIT)Use font-display: swap
ImagesโŒ NoLoaded separatelyLazy load below fold

*May execute before rendering completes, but doesn't intentionally block it.

Render-Blocking Impact on Performance:

Without Optimization:
[CSS Download] -> [Parse CSS] -> [Render] = Delayed FCP

With defer/async JS:
[JS Download] -> [HTML Parse] -> [CSS] -> [Render] = Early FCP + JS runs later

With Critical CSS:
[Critical CSS inline] -> [Render quickly] + [Non-critical async] = Optimized FCP

๐Ÿง  The Complete Rendering Pipeline

Stage 1: Network & Resource Loading

Browser -> DNS Lookup -> TCP Handshake -> HTTP Request -> Server Response

Key Points:

  • DNS lookup translates domain to IP address
  • TCP connection established
  • HTTP headers sent with conditional caching info
  • HTML bytes start streaming to browser

Optimization:

// Use DNS prefetch for external domains
<link rel="dns-prefetch" href="//cdn.example.com">

// Preconnect for critical resources
<link rel="preconnect" href="//fonts.googleapis.com">

// Preload critical resources
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

Stage 2: HTML Parsing -> DOM Tree

HTML Bytes -> Tokenization -> Tree Construction -> DOM Tree

Process:

  • Browser receives HTML as a stream
  • HTML Parser tokenizes (<tag>, text, attributes)
  • Tokens converted to nodes
  • Parent-child relationships established

Example:

<html>
  <head>
    <title>Page</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <h1>Hello</h1>
    <p>Content</p>
  </body>
</html>

Results in DOM tree:

Document
+-- html
|   +-- head
|   |   +-- title: "Page"
|   |   +-- link (stylesheet reference)
|   +-- body
|       +-- h1: "Hello"
|       +-- p: "Content"

Key Point: Parsing is streamlined - visible content can render before entire HTML is parsed.


Stage 3: CSS Parsing -> CSSOM Tree

CSS Bytes -> Tokenization -> Parse Rules -> CSSOM Tree

Process:

  • CSS from <link> or <style> tags triggers download
  • CSS Parser processes selectors and rules
  • Cascade and specificity applied
  • CSSOM (CSS Object Model) constructed

Example:

/* In styles.css */
body { font-size: 16px; }
h1 { color: blue; font-size: 32px; }
p { color: gray; }

Results in CSSOM tree:

StyleSheetList
+-- body
|   +-- font-size: 16px
|   +-- margin: 0 (inherited default)
|   +-- padding: 0 (inherited default)
+-- h1
|   +-- color: blue
|   +-- font-size: 32px
|   +-- (inherits font-size override)
+-- p
    +-- color: gray
    +-- (inherits font-size from body)

Critical Detail: CSS is render-blocking. The browser waits for CSS before rendering because it needs all styles to avoid re-rendering.

// CSS render-blocking flow:
// 1. <link rel="stylesheet"> tag encountered
// 2. CSS file requested
// 3. HTML parsing continues (non-blocking download)
// 4. BUT: Rendering blocked until CSS parsed
// 5. Why? To prevent FOUC (Flash of Unstyled Content)

Why CSS Blocks Rendering:

<!-- CSS blocks rendering to prevent FOUC (Flash of Unstyled Content) -->

<!-- WITHOUT CSS blocking: -->
<!-- User sees unstyled HTML (terrible UX) -->
<!-- Then CSS loads and page "snaps" into place -->

<!-- WITH CSS blocking (default browser behavior): -->
<!-- Browser waits for CSS before rendering -->
<!-- Page appears styled correctly on first render -->

Timeline comparison:

โŒ WITHOUT CSS blocking:
[HTML Parse] -> [Render unstyled] -> [CSS arrives] -> [Paint with styles]
                ^ FOUC (Flash) - bad experience

โœ… WITH CSS blocking (current approach):
[HTML Parse] -> [Wait for CSS] -> [CSS arrives] -> [Render with styles]

Mitigation Strategies:

<!-- โœ… Inline critical CSS (no wait) -->
<style>
  /* Only styles needed above-the-fold */
  body { margin: 0; font-family: Arial; }
  header { background: #333; }
  h1 { color: white; }
</style>

<!-- โœ… Load non-critical CSS with media queries -->
<link rel="stylesheet" href="desktop.css" media="(min-width: 1024px)">

<!-- โœ… Preload critical resources -->
<link rel="preload" href="critical.css" as="style">

Stage 4: JavaScript Execution โš ๏ธ RENDER-BLOCKING (by default)

JavaScript can significantly impact the rendering pipeline. This is one of the most critical optimizations.

โŒ Default Behavior: RENDER-BLOCKING

<!-- HTML parsing STOPS until JS is fetched & executed -->
<!-- Rendering also blocked because DOM may not be ready -->
<script src="app.js"></script>

Flow:

Parsing -> <script> tag -> [STOP PARSING]
          v
          Download app.js
          v
          Execute app.js (can modify DOM/styles)
          v
          Resume parsing

Impact: Every second of JS execution delays First Contentful Paint.

โœ… With defer Attribute: NOT RENDER-BLOCKING

<!-- HTML parsing continues; JS runs after parsing completes -->
<!-- Rendering happens as planned, then JS runs -->
<script src="app.js" defer></script>

Flow:

[Parsing continues] -> [CSS done] -> [Render happens] -> [defer scripts run]
                                        v
                          DOMContentLoaded fired

Order guaranteed: Multiple defer scripts run in order.

When to use: For application framework (React, Vue, etc.), main app code.

โš ๏ธ With async Attribute: NOT RENDER-BLOCKING PARSING, but may interrupt rendering

<!-- HTML parsing continues; JS runs as soon as downloaded -->
<!-- May execute before rendering if downloaded quickly -->
<script src="analytics.js" async></script>

Flow:

[Parsing continues] -> Downloaded -> [STOP & Execute] -> [Resume rendering]

Order NOT guaranteed: Multiple async scripts run independently.

When to use: Analytics, third-party ads, non-critical tracking.

Modern: type="module" (ES6 Modules)

<!-- Treated like defer by default (deferred execution) -->
<!-- Maintains order with other modules -->
<script type="module" src="app.js"></script>

JavaScript's Render-Blocking Cost:

// โŒ BLOCKS RENDERING (default script tag)
// Page invisible while heavy-calculation.js is downloaded & executed
<script src="heavy-calculation.js"></script>
// Impact: FCP delayed by entire JS execution time

// โœ… BETTER: Defer execution
<script src="heavy-calculation.js" defer></script>
// Impact: HTML parsed + rendering starts, THEN JS runs
// FCP appears much sooner

// โœ… BEST: For non-critical analytics/tracking
<script src="analytics.js" async></script>
// Impact: Minimal impact on FCP
// Analytics runs whenever it finishes downloading

// โœ… MODERN: Use Web Workers for heavy computation
<script>
  const worker = new Worker('expensive-task.js');
  // Main thread stays free for rendering
  worker.postMessage(data);
  worker.onmessage = (e) => {
    // Update UI with results, doesn't block rendering
    updateUI(e.data);
  };
</script>

// โœ… BEST PRACTICE: Inline critical bootstrap only
<script>
  // Minimal code: just app initialization
  window.config = { version: '1.0' };
  // Heavy app logic loads via defer/async
</script>
<script src="app.js" defer></script>

Common Render-Blocking JavaScript Patterns to AVOID:

<!-- โŒ Multiple blocking scripts (each one blocks rendering) -->
<script src="lib1.js"></script>
<script src="lib2.js"></script>
<script src="app.js"></script>
<!-- FCP delayed by: lib1 + lib2 + app execution time -->

<!-- โœ… Use defer for all non-critical scripts -->
<script src="lib1.js" defer></script>
<script src="lib2.js" defer></script>
<script src="app.js" defer></script>
<!-- FCP appears while these download in parallel -->

<!-- โŒ Large inline scripts (parse + execute blocks rendering) -->
<script>
  // 100KB of JavaScript here... page frozen
  const heavyComputation = () => { /* ... */ };
  heavyComputation();
</script>

<!-- โœ… Keep inline scripts minimal, move rest to external files -->
<script>
  // Only initialization code (< 1KB)
  window.appConfig = { /* ... */ };
</script>
<script src="app.js" defer></script>

Stage 5: Render Tree Construction (DOM + CSSOM)

DOM Tree + CSSOM Tree -> Render Tree

Process:

  • Browser combines DOM structure with CSS styles
  • Invisible elements removed:
    • display: none (completely hidden)
    • <head> and <title> tags
    • Hidden meta tags
  • Visibility elements retained:
    • visibility: hidden (reserved in layout)
    • opacity: 0 (still part of render tree)
    • position: absolute (still rendered)

Example:

<style>
  .hidden { display: none; }
  .invisible { visibility: hidden; }
</style>

<div>Visible</div>
<div class="hidden">Not in render tree</div>
<div class="invisible">In render tree, but hidden</div>

Resulting Render Tree:

Render Tree
+-- div: "Visible"
+-- div: (invisible, space reserved)
    // .hidden div is NOT in render tree

Key Point: Each render tree node = box with CSS computed styles.


Stage 6: Layout Calculation (Reflow)

Render Tree -> Calculate Positions & Sizes -> Layout Boxes

Process:

  • Browser calculates exact position and size for each element
  • Considers viewport dimensions
  • Applies box model (margin, border, padding, content)
  • Hierarchical calculation (parent -> children)

Example:

// Triggers layout calculation (Reflow)
const height = element.offsetHeight;
const width = element.clientWidth;
const rect = element.getBoundingClientRect();
element.style.width = '100px'; // Layout recalculation

// Why? Browser must calculate actual dimensions
console.log(height); // Can't just guess, must measure

Common Reflow-Triggering Operations:

// Reading layout properties (forces layout calculation)
element.offsetWidth          // Triggers reflow
element.offsetHeight         // Triggers reflow
element.getBoundingClientRect() // Triggers reflow
element.scrollHeight         // Triggers reflow
window.getComputedStyle(el)  // Triggers reflow (sometimes)

// Modifying layout properties (triggers reflow)
element.style.width = '100px'       // Reflow
element.classList.add('resize')     // Reflow (if CSS changes layout)
element.innerText = 'New Text'      // Reflow (if height changes)

Optimization Example:

// โŒ BAD: Multiple reflows
for (let i = 0; i < 100; i++) {
  element.style.width = (i * 10) + 'px'; // Reflow each iteration
  console.log(element.offsetWidth); // Reflow each iteration
}

// โœ… GOOD: Batch reflows
element.style.transition = 'width 1s';
element.style.width = '1000px'; // Single reflow + animation

// โœ… BETTER: DocumentFragment for DOM additions
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  const div = document.createElement('div');
  div.textContent = i;
  frag.appendChild(div); // No reflow yet
}
container.appendChild(frag); // Single reflow

// โœ… BEST: Use requestAnimationFrame for reads/writes
function optimizedUpdate() {
  requestAnimationFrame(() => {
    // All reads
    const heights = Array.from(elements).map(el => el.offsetHeight);

    requestAnimationFrame(() => {
      // All writes
      elements.forEach((el, i) => el.style.height = heights[i] + 'px');
    });
  });
}

Stage 7: Painting

Layout Boxes -> Rasterization -> Paint Records -> Display List

Process:

  • Convert layout information to actual pixels
  • Draw backgrounds, borders, text, shadows
  • Create paint records for each visual element
  • May involve multiple paint layers

Example:

// These operations trigger painting (but not reflow)
element.style.backgroundColor = 'red';  // Paint
element.style.color = 'blue';          // Paint
element.style.opacity = 0.5;           // Paint
element.style.boxShadow = '0 0 10px black'; // Paint

// BUT: These CSS properties are paint-efficient
// (handled by GPU compositing, not CPU painting)
element.style.transform = 'translate(10px, 10px)'; // Composite only
element.style.opacity = 0.5; // Composite only (with will-change)

Paint Performance Layers:

Expensive (triggers paint):
  - background-color changes
  - border changes
  - text-shadow changes

Less Expensive (composite-only):
  - transform changes
  - opacity changes (with GPU acceleration)
  - filter changes (modern browsers optimize)

Stage 8: Compositing

Paint Records + Layers -> Composite -> GPU Rendering -> Display

Process:

  • Combines multiple paint layers
  • Applies z-index and stacking context
  • GPU blends and transforms layers
  • Final bitmap sent to screen

Optimize for Compositing:

// โœ… EFFICIENT: Transform (composite-only, GPU accelerated)
element.style.transform = 'translate(100px, 100px)';

// โœ… EFFICIENT: Opacity (composite-only with GPU)
element.style.opacity = 0.5;

// โœ… EFFICIENT: Filter (GPU accelerated in modern browsers)
element.style.filter = 'blur(5px)';

// โŒ EXPENSIVE: Left/top (triggers layout + paint)
element.style.left = '100px';
element.style.top = '100px';

// โœ… TIP: Force GPU compositing with will-change
element.style.willChange = 'transform, opacity';

๐Ÿ“Š Complete CRP Timeline

1. Parse HTML
   +- Stream tokenization
   +- Create DOM nodes
   +- Encounter <link> (CSS) and <script> (JS)

2. Fetch & Parse CSS
   +- Download stylesheet
   +- Parse selectors, rules, cascade
   +- Build CSSOM
   +- โš ๏ธ Blocks rendering until complete

3. Fetch & Execute JavaScript (depends on attributes)
   +- Default: Blocks HTML parsing
   +- defer: Executes after parsing
   +- async: Executes when ready

4. Construct Render Tree
   +- Combine DOM + CSSOM
   +- Remove display:none elements
   +- Include computed styles

5. Layout (Reflow)
   +- Calculate positions & sizes
   +- Build box model
   +- Compute viewport constraints

6. Paint
   +- Rasterize layout into pixels
   +- Create paint records
   +- Build display list

7. Composite
   +- Blend layers
   +- GPU acceleration
   +- Final display bitmap

8. Display on Screen
   +- First Contentful Paint (FCP)
   +- Largest Contentful Paint (LCP)

๐Ÿ”„ JavaScript Event Loop & Rendering

The JavaScript event loop is intrinsically connected to the browser's rendering cycle. Understanding this relationship is crucial for performance optimization.

How Event Loop Interacts with Rendering

+---------------------------------------------------------+
|           Browser Event Loop & Render Cycle            |
+---------------------------------------------------------+

1. Execute JavaScript
   +- Call Stack processes synchronous code
   +- setTimeout, Promises, event listeners queued

2. Execute Microtasks (โšก High Priority)
   +- Promise.then()
   +- Promise.catch()
   +- Promise.finally()
   +- queueMicrotask()
   +- MutationObserver callbacks
   +- Process all until queue empty

3. Check for Rendering Opportunity
   +- Is there visual update needed?
   +- If YES: Proceed to rendering
   +- If NO: Skip to next task

4. Rendering Phase (if needed)
   +- recalcStyle() - Apply CSS
   +- layout() - Reflow
   +- paint() - Rasterize
   +- composite() - GPU blend

5. Execute Macrotasks (Lower Priority)
   +- setTimeout callbacks
   +- setInterval callbacks
   +- I/O operations
   +- UI events (click, scroll)
   +- requestAnimationFrame (actually executes BEFORE rendering)

6. Back to Step 1

Microtasks vs Macrotasks vs Rendering

console.log('1: Script start'); // Synchronous (main thread)

// Macrotask: setTimeout
setTimeout(() => {
  console.log('6: Macrotask (setTimeout)');
}, 0);

// Microtask: Promise
Promise.resolve()
  .then(() => {
    console.log('3: Microtask (Promise.then)');
  })
  .then(() => {
    console.log('4: Microtask (Promise.then 2)');
  });

// Macrotask alternative: setImmediate (Node.js only)
// Microtask: queueMicrotask
queueMicrotask(() => {
  console.log('5: Microtask (queueMicrotask)');
});

console.log('2: Script end'); // Synchronous (main thread)

/* Output Order:
   1: Script start
   2: Script end
   3: Microtask (Promise.then)
   4: Microtask (Promise.then 2)
   5: Microtask (queueMicrotask)
   6: Macrotask (setTimeout)
*/

requestAnimationFrame's Special Role

requestAnimationFrame (RAF) is not a microtask or macrotaskโ€”it's scheduled during the rendering phase:

console.log('1: Start');

setTimeout(() => console.log('4: setTimeout'), 0);

requestAnimationFrame(() => console.log('3: RAF'));

Promise.resolve().then(() => console.log('2: Promise'));

/* Output Order:
   1: Start
   2: Promise (microtask)
   3: RAF (scheduled before rendering)
   4: setTimeout (macrotask)
*/

Why RAF timing matters:

// โŒ BAD: DOM changes with setTimeout (batches with next frame)
setTimeout(() => {
  element.style.transform = 'translateX(100px)';
  // Browser may have already rendered, causing extra work
}, 0);

// โœ… GOOD: DOM changes with RAF (synchronized with rendering)
requestAnimationFrame(() => {
  element.style.transform = 'translateX(100px)';
  // Guaranteed to be before rendering
});

// โœ… BEST: Use RAF for animation loop
let x = 0;
function animate() {
  x += 5;
  element.style.transform = `translateX(${x}px)`;

  if (x < 500) {
    requestAnimationFrame(animate);
  }
}
animate();

Rendering Occurs BETWEEN Macrotasks

The browser checks for rendering work between every macrotask:

// Task 1: Macrotask
setTimeout(() => {
  console.log('Task 1');
  element.style.backgroundColor = 'red';
  // After this macrotask -> Browser checks for rendering
  // -> Rendering happens (if needed)
}, 0);

// Task 2: Macrotask
setTimeout(() => {
  console.log('Task 2');
  element.style.backgroundColor = 'blue';
  // After this macrotask -> Browser checks for rendering again
  // -> Rendering happens (if needed)
}, 0);

/* Timeline:
   1. Execute Task 1
   2. Check rendering -> Render with red background
   3. Execute Task 2
   4. Check rendering -> Render with blue background
*/

Microtasks Block Rendering

All microtasks must complete before rendering can occur:

// Heavy computation in microtask
Promise.resolve()
  .then(() => {
    // This runs BEFORE rendering
    let sum = 0;
    for (let i = 0; i < 1000000000; i++) {
      sum += i; // Long computation
    }
    // Rendering is BLOCKED until this completes
  });

element.style.backgroundColor = 'red';
// Red background delayed by microtask computation

Optimization: Use macrotasks for heavy work to allow rendering:

// โœ… BETTER: Break work into macrotasks
function heavyComputation() {
  // Do work in chunks, yield to rendering
  setTimeout(() => {
    // Process chunk 1
    processChunk(0, 100);

    if (hasMoreWork) {
      heavyComputation(); // Continue after rendering
    }
  }, 0);
}

Event Loop & Performance Monitoring

// Measure time spent in different phases
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(`${entry.name}: ${entry.duration}ms`);
  }
});

observer.observe({ entryTypes: ['measure', 'navigation'] });

// Mark event loop phases
performance.mark('script-start');
// ... heavy JS work ...
performance.mark('script-end');
performance.measure('script', 'script-start', 'script-end');

// Rendering performance
performance.mark('render-start');
element.style.width = '100px';
performance.mark('render-end');
performance.measure('render', 'render-start', 'render-end');

Complete Event Loop Timing Example

console.log('=== PHASE 1: Synchronous Code ===');
console.log('1. Start');

setTimeout(() => {
  console.log('=== PHASE 3: Macrotask (after microtasks) ===');
  console.log('5. setTimeout');
}, 0);

Promise.resolve()
  .then(() => {
    console.log('=== PHASE 2: Microtask ===');
    console.log('3. Promise');
    return Promise.resolve();
  })
  .then(() => {
    console.log('4. Promise chained');
  });

queueMicrotask(() => {
  console.log('2. queueMicrotask (after Promise, same phase)');
});

console.log('End of script');

/* Actual Output:
   1. Start
   End of script
   3. Promise
   2. queueMicrotask (after Promise, same phase)
   4. Promise chained
   [RENDERING HAPPENS HERE]
   5. setTimeout
*/

Key Implications for Rendering

ActionQueueBlocks RenderingTiming
Sync codeMainโœ… YesImmediate
setTimeoutMacrotaskโŒ NoAfter current + render
Promise.then()Microtaskโœ… YesImmediate (before render)
requestAnimationFrameAnimationN/ARight before render
MutationObserverMicrotaskโœ… YesImmediate (before render)

โฑ๏ธ Performance Metrics & Timing

Key Web Vitals

MetricWhat It MeasuresTarget
FCP (First Contentful Paint)First pixel painted< 1.8s
LCP (Largest Contentful Paint)Largest element visible< 2.5s
CLS (Cumulative Layout Shift)Unexpected layout shifts< 0.1
FID (First Input Delay)Time to respond to input< 100ms
TTFB (Time to First Byte)Server response time< 600ms

JavaScript Timing Events

// DOMContentLoaded: DOM ready, before all resources
document.addEventListener('DOMContentLoaded', () => {
  console.log('DOM ready, rendering complete, but images may still load');
});

// load: All resources loaded (images, CSS, etc.)
window.addEventListener('load', () => {
  console.log('Page fully loaded, all resources fetched');
});

// Performance API for custom measurements
const perfData = performance.getEntriesByType('navigation')[0];
console.log('Time to First Byte:', perfData.responseStart - perfData.requestStart);
console.log('DOM Content Loaded:', perfData.domContentLoadedEventEnd - perfData.fetchStart);
console.log('Page Load Time:', perfData.loadEventEnd - perfData.fetchStart);

๐ŸŽฏ Optimization Strategies

1. Minimize Render-Blocking CSS

<!-- โŒ Default: Blocks rendering -->
<link rel="stylesheet" href="all-styles.css">
<!-- Page won't render until this CSS is downloaded & parsed -->

<!-- โœ… BEST: Inline critical CSS -->
<head>
  <style>
    /* Only above-the-fold styles (< 10KB) */
    body { margin: 0; font-family: Arial; }
    header { background: #333; color: white; }
    .hero { width: 100%; height: auto; }
  </style>
  <!-- Defer non-critical CSS -->
  <link rel="stylesheet" href="non-critical.css" media="print">
</head>

<!-- โœ… Split CSS by media query (non-blocking for other devices) -->
<link rel="stylesheet" href="desktop.css" media="(min-width: 1024px)">
<link rel="stylesheet" href="mobile.css" media="(max-width: 1023px)">

<!-- โœ… Preload critical CSS with higher priority -->
<link rel="preload" href="critical.css" as="style">
<link rel="stylesheet" href="critical.css">

<!-- โœ… Load non-critical CSS asynchronously -->
<link rel="preload" href="secondary.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="secondary.css"></noscript>

Impact:

  • Inline critical CSS: FCP reduced by 0.5-2 seconds
  • Media queries: Non-blocking for unused device types
  • Preload: Starts CSS download earlier

2. Eliminate JavaScript Render-Blocking

<!-- โŒ WORST: Multiple blocking scripts (each delays rendering) -->
<script src="jquery.min.js"></script>
<script src="bootstrap.js"></script>
<script src="app.js"></script>
<!-- FCP delayed by: jQuery load + parse + exec + Bootstrap load + parse + exec + app load + parse + exec -->

<!-- โœ… GOOD: Single async-able scripts for non-critical -->
<script src="analytics.js" async></script>
<script src="ads.js" async></script>

<!-- โœ… BETTER: Defer all non-critical scripts -->
<script src="jquery.min.js" defer></script>
<script src="bootstrap.js" defer></script>
<script src="app.js" defer></script>
<!-- All load in parallel; rendering not blocked -->

<!-- โœ… BEST: Minimal inline + defer everything else -->
<script>
  // Only essential initialization (< 1KB)
  window.appConfig = { apiUrl: '/api' };
  window.ready = false;
  document.addEventListener('DOMContentLoaded', () => {
    window.ready = true;
  });
</script>

<!-- Load frameworks & app code deferred -->
<script src="react.min.js" defer></script>
<script src="app.js" defer></script>

<!-- Non-critical (tracking, ads) as async -->
<script src="google-analytics.js" async></script>
<script src="ads.js" async></script>

Impact on FCP:

Scenario 1 - Blocking Scripts:
JS Download (2s) + Parse (0.5s) + Execute (0.5s) = 3s before rendering

Scenario 2 - All defer:
[HTML parse] (0.5s) + [JS downloads in parallel] + [Render in 0.2s]
= FCP at 0.7s (then JS executes)

Benefit: 4x faster FCP!

3. CSS Optimization

<!-- โœ… Minimize CSS size -->
<!-- Minify to reduce parse time -->
<link rel="stylesheet" href="styles.min.css">

<!-- โœ… Reduce CSS specificity -->
/* โŒ High specificity (slower to parse & apply) */
body > div.container > section > div > p.intro { color: blue; }

/* โœ… Lower specificity (faster) */
.intro-text { color: blue; }

<!-- โœ… Remove unused CSS -->
<!-- Use PurgeCSS, UnCSS, or Tailwind to eliminate unused styles -->

4. Use Resource Hints for Critical Resources

<!-- โœ… DNS Prefetch for external domains -->
<link rel="dns-prefetch" href="//cdn.example.com">
<link rel="dns-prefetch" href="//fonts.googleapis.com">

<!-- โœ… Preconnect for critical servers -->
<link rel="preconnect" href="//cdn.example.com">
<link rel="preconnect" href="//fonts.googleapis.com" crossorigin>

<!-- โœ… Prefetch for likely navigation -->
<link rel="prefetch" href="//next-page.com">

<!-- โœ… Preload for critical resources -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="app.js" as="script">

5. Optimize Font Loading

<!-- โŒ Default: Text invisible until font loads (FOIT) -->
<style>
  body { font-family: 'MyFont'; }
</style>
<link href="//fonts.googleapis.com/css?family=MyFont" rel="stylesheet">

<!-- โœ… Font-display swap: Show fallback immediately -->
<style>
  @font-face {
    font-family: 'MyFont';
    src: url('font.woff2') format('woff2');
    font-display: swap; /* Critical: avoid invisible text */
  }
</style>

<!-- โœ… Preload critical fonts -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

<!-- โœ… Load fonts with async -->
<link rel="preload" href="secondary-font.woff2" as="font" type="font/woff2" crossorigin>

6. Defer Non-Critical Images

<!-- โŒ Images don't block rendering, but they do block LCP -->
<img src="hero.jpg" alt="Hero">

<!-- โœ… Lazy load below-the-fold images -->
<img src="hero.jpg" alt="Hero" loading="lazy">

<!-- โœ… Responsive images for different devices -->
<img
  srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 2000w"
  sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 100vw"
  src="medium.jpg"
  alt="Hero"
>

<!-- โœ… Use modern formats with fallback -->
<picture>
  <source srcset="image.webp" type="image/webp">
  <source srcset="image.jpg" type="image/jpeg">
  <img src="image.jpg" alt="Image">
</picture>

4. Minimize Reflows & Repaints

// โŒ Multiple reflows
const container = document.getElementById('container');
container.style.width = '100px';
container.style.height = '100px';
container.style.margin = '10px';

// โœ… Single reflow (batch changes)
container.style.cssText = 'width: 100px; height: 100px; margin: 10px;';

// OR use classList
container.classList.add('sized-container');

// โŒ Alternating reads/writes (reflow thrashing)
for (let i = 0; i < 10; i++) {
  element.style.width = (element.offsetWidth + 10) + 'px';
}

// โœ… Separate reads and writes
let width = element.offsetWidth;
for (let i = 0; i < 10; i++) {
  width += 10;
}
element.style.width = width + 'px';

5. Use GPU Acceleration

// โœ… Transform (GPU accelerated)
element.style.transform = 'translateZ(0)'; // Force GPU
element.style.transform = 'translate(100px, 100px)';

// โœ… Opacity (GPU accelerated with will-change)
element.style.willChange = 'opacity';
element.style.opacity = 0.5;

// โœ… Filter (GPU accelerated in modern browsers)
element.style.filter = 'blur(5px)';

// โŒ Avoid: Left/Top repositioning (triggers layout)
element.style.left = '100px';
element.style.top = '100px';

6. Image & Font Optimization

<!-- โœ… Lazy load images below the fold -->
<img src="hero.jpg" alt="Hero" loading="lazy">

<!-- โœ… Responsive images -->
<img srcset="small.jpg 500w, large.jpg 1200w" sizes="100vw" src="medium.jpg" alt="Image">

<!-- โœ… Web font optimization -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preconnect" href="//fonts.googleapis.com">

<!-- โœ… Font-display strategy -->
<style>
  @font-face {
    font-family: 'MyFont';
    src: url('font.woff2') format('woff2');
    font-display: swap; /* Show fallback immediately, swap when ready */
  }
</style>

๐Ÿ› ๏ธ Browser DevTools: Identifying Render-Blocking Resources

Chrome DevTools Performance Tab

// 1. Open DevTools (F12) -> Performance tab
// 2. Click "Start profiling and reload page"
// 3. Look for red bars in the timeline (blocking resources)

// Key indicators:
// - Long green bars = JavaScript execution (blocking)
// - Yellow bars = CSS parsing (blocking)
// - Blue bars = HTML parsing (non-blocking)
// - Purple bars = Layout/Reflow (expensive operations)

Network Tab Analysis

// 1. Open DevTools -> Network tab
// 2. Check "Disable cache" for first-visit simulation
// 3. Look for "Blocking" column (shows render-blocking time)

// Render-blocking indicators:
// - CSS files with "Blocking: Yes"
// - JS files with "Blocking: Yes" (default scripts)
// - Fonts with "Blocking: Yes" (FOIT scenarios)

Lighthouse Audit

// Run Lighthouse audit:
// 1. DevTools -> Lighthouse tab
// 2. Check "Performance" category
// 3. Look for:
//    - "Eliminate render-blocking resources"
//    - "Reduce unused CSS"
//    - "Remove unused JavaScript"

// Example Lighthouse output:
// โŒ Eliminate render-blocking resources (2.1s)
//   - styles.css (1.2s)
//   - app.js (0.9s)

๐Ÿ“Š Measuring Render-Blocking Impact

Performance API: Track CRP Metrics

// Measure First Contentful Paint (FCP)
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('FCP:', entry.startTime + 'ms');
  }
}).observe({ entryTypes: ['paint'] });

// Measure Largest Contentful Paint (LCP)
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('LCP:', entry.startTime + 'ms');
  }
}).observe({ entryTypes: ['largest-contentful-paint'] });

// Track resource loading times
window.addEventListener('load', () => {
  const resources = performance.getEntriesByType('resource');
  resources.forEach(resource => {
    if (resource.name.includes('.css') || resource.name.includes('.js')) {
      console.log(`${resource.name}: ${resource.responseEnd - resource.requestStart}ms`);
    }
  });
});

Real User Monitoring (RUM)

// Track render-blocking impact across users
// Example: Send to analytics when FCP > 2.5s
new PerformanceObserver((list) => {
  const fcp = list.getEntries()[0];
  if (fcp.startTime > 2500) {
    // Send to analytics
    gtag('event', 'web_vitals', {
      event_category: 'Web Vitals',
      event_label: 'FCP',
      value: Math.round(fcp.startTime),
      custom_map: { metric_value: fcp.startTime }
    });
  }
}).observe({ entryTypes: ['paint'] });

๐ŸŽฏ Framework-Specific Render-Blocking Strategies

React Applications

// โŒ Blocking: Large bundle loads immediately
import React from 'react';
import { createRoot } from 'react-dom/client';
// ... 500KB of components ...

// โœ… Better: Code splitting with lazy loading
import React, { Suspense, lazy } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

// โœ… Best: Preload critical routes
const preloadRoute = (route) => {
  const link = document.createElement('link');
  link.rel = 'prefetch';
  link.href = route;
  document.head.appendChild(link);
};

Vue.js Applications

// โœ… Async component loading
const AsyncComponent = () => import('./AsyncComponent.vue');

// โœ… Route-based code splitting
const router = createRouter({
  routes: [
    {
      path: '/heavy-page',
      component: () => import('./HeavyPage.vue'),
      meta: { preload: true }
    }
  ]
});

Angular Applications

// โœ… Lazy loading modules
const routes: Routes = [
  {
    path: 'feature',
    loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule)
  }
];

// โœ… Preloading strategies
@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      preloadingStrategy: QuicklinkStrategy // or PreloadAllModules
    })
  ]
})
export class AppModule { }

๐Ÿ“ฑ Mobile-Specific Considerations

Mobile Render-Blocking Challenges

// Mobile devices have:
// - Slower CPU (2-4x slower than desktop)
// - Higher latency networks
// - Smaller memory
// - Battery constraints

// Impact on render-blocking:
// - CSS parsing 3x slower on mobile
// - JavaScript execution 2-4x slower
// - Network requests have higher latency

Mobile Optimization Strategies

<!-- โœ… Critical CSS only (mobile-first) -->
<style>
  /* Only essential mobile styles */
  body { font-size: 16px; margin: 0; }
  .mobile-nav { display: block; }
  @media (min-width: 768px) {
    .mobile-nav { display: none; }
  }
</style>

<!-- โœ… Defer desktop-specific CSS -->
<link rel="stylesheet" href="desktop.css" media="(min-width: 768px)">

<!-- โœ… Smaller JavaScript bundles for mobile -->
<script src="mobile-app.js" defer></script>
<script src="desktop-enhancements.js" defer media="(min-width: 768px)"></script>

๐Ÿ”ฎ Advanced Techniques

Critical Resource Hints

<!-- DNS prefetch for external domains -->
<link rel="dns-prefetch" href="//cdn.example.com">

<!-- Preconnect for critical connections -->
<link rel="preconnect" href="//fonts.googleapis.com" crossorigin>

<!-- Preload critical resources -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero-image.webp" as="image">

<!-- Prefetch for likely next pages -->
<link rel="prefetch" href="/next-page.html">

Service Worker Caching

// Cache critical resources for instant loading
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('critical-v1').then((cache) => {
      return cache.addAll([
        '/critical.css',
        '/critical.js',
        '/hero-image.webp'
      ]);
    })
  );
});

// Serve cached resources instantly
self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('critical')) {
    event.respondWith(
      caches.match(event.request).then((response) => {
        return response || fetch(event.request);
      })
    );
  }
});

Progressive Loading with Intersection Observer

// Load non-critical CSS when needed
const loadNonCriticalCSS = () => {
  const link = document.createElement('link');
  link.rel = 'stylesheet';
  link.href = 'non-critical.css';
  document.head.appendChild(link);
};

// Load when user scrolls near content
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      loadNonCriticalCSS();
      observer.disconnect();
    }
  });
});

observer.observe(document.querySelector('.content-section'));

๐Ÿ“ˆ Real-World Case Studies

Case Study 1: E-commerce Site (2.1s -> 0.8s FCP)

Before:

<!-- Blocking CSS -->
<link rel="stylesheet" href="bootstrap.css"> <!-- 200KB -->
<link rel="stylesheet" href="theme.css"> <!-- 150KB -->
<link rel="stylesheet" href="components.css"> <!-- 100KB -->

<!-- Blocking JavaScript -->
<script src="jquery.js"></script>
<script src="bootstrap.js"></script>
<script src="app.js"></script>

After:

<!-- Critical CSS inline -->
<style>
  /* 14KB of critical styles only */
  body { margin: 0; font-family: Arial; }
  .hero { background: #f0f0f0; padding: 2rem; }
  .product-card { border: 1px solid #ddd; }
</style>

<!-- Defer non-critical CSS -->
<link rel="preload" href="all-styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

<!-- Defer JavaScript -->
<script src="jquery.js" defer></script>
<script src="bootstrap.js" defer></script>
<script src="app.js" defer></script>

Results:

  • FCP: 2.1s -> 0.8s (62% improvement)
  • LCP: 3.2s -> 1.5s (53% improvement)
  • Total blocking time: 1.8s -> 0.2s (89% reduction)

Case Study 2: News Website (3.5s -> 1.2s FCP)

Problem: Heavy third-party scripts blocking rendering.

Solution:

<!-- Move all third-party to end of body -->
<body>
  <!-- Page content loads first -->
  <header>...</header>
  <main>...</main>

  <!-- Third-party scripts at end -->
  <script async src="//ads.example.com/ads.js"></script>
  <script async src="//analytics.example.com/tracking.js"></script>
  <script async src="//social.example.com/widgets.js"></script>
</body>

Results:

  • FCP: 3.5s -> 1.2s (66% improvement)
  • User engagement: +40%
  • Bounce rate: -25%

๐Ÿ” Summary

  • CRP is fundamental to page performance - understanding it is essential for optimization
  • CSS is render-blocking by default - use inline critical CSS, defer non-critical
  • JavaScript blocks HTML parsing by default - use defer for most scripts, async for analytics
  • Render-blocking resources directly impact FCP/LCP - minimize their count and size
  • Third-party scripts are highest risk - always load with async, consider loading at end of page
  • Reflows are expensive - batch DOM changes and use CSS for animations
  • GPU acceleration - use transform and opacity for smooth animations
  • Prioritize above-the-fold - inline critical CSS, defer non-critical resources, preload important files
  • Measure performance - use DevTools, Lighthouse, and Web Vitals APIs to track improvements
  • Test on real devices - performance varies significantly across devices and networks
  • Monitor third-party impact - track which resources are render-blocking and for how long

๐ŸŒ Related Resources

  • Browser Rendering Basics (general/browser_rendering.md) - Visual flow of rendering stages
  • Promises and Async Patterns (js/promises/) - Understand async JavaScript patterns
  • JavaScript Event Loop (js/general-concepts/event_loop.md) - Deep understanding of microtasks, macrotasks, and rendering synchronization
  • Performance API and Monitoring
  • Web Vitals - Google's performance metrics
  • Chrome DevTools Performance
  • MDN: Event Loop
  • MDN: queueMicrotask

๐Ÿš€ Future Standards & Modern APIs

Speculation Rules API (Chrome 121+)

<!-- Preload pages based on user behavior patterns -->
<script type="speculationrules">
{
  "prerender": [
    {
      "source": "document",
      "where": {
        "href_matches": "/*"
      },
      "eagerness": "moderate"
    }
  ]
}
</script>

Priority Hints

<!-- Set resource priorities -->
<link rel="stylesheet" href="critical.css" fetchpriority="high">
<link rel="stylesheet" href="non-critical.css" fetchpriority="low">
<img src="hero.jpg" fetchpriority="high">
<img src="background.jpg" fetchpriority="low">

Content Visibility API

/* Skip rendering off-screen content */
.content-section {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px; /* Estimated size */
}

CSS Cascade Layers (Chrome 99+)

/* Organize CSS without specificity wars */
@layer reset, base, components, utilities;

@layer base {
  body { margin: 0; }
}

@layer components {
  .card { border: 1px solid #ddd; }
}

๐Ÿ“‹ Summary


Quick Quiz

Test your understanding with 3 quick questions

Q1What is the primary reason CSS is considered render-blocking?
Q2Which approach is recommended for optimizing JavaScript render-blocking?
Q3What happens when microtasks (like Promise.then callbacks) are processing in the event loop?

Continue Reading

CrackFrontend

Your guide to mastering frontend interviews

Resources

LibraryPracticeDonate

Company

About UsContact

Legal

Privacy PolicyTerms of Service

Built with โค๏ธ by Tushar Khanna