Lighthouse audit render-blocking-resources · Performance

Eliminate render-blocking resources: what it is and how to fix it

View raw .md for LLMs / your notes

The browser can't render anything until it finishes downloading and parsing every render-blocking CSS and synchronous JS in the <head>. Each blocking resource adds latency to FCP and LCP.

TL;DR

What the audit checks

Lighthouse identifies every CSS link tag and synchronous <script> in <head> that delays the first paint. It estimates how much time you'd save by deferring each one.

Why it matters

The browser parses HTML top-down. When it hits:

<link rel="stylesheet" href="big-app.css" />

…it stops, downloads big-app.css, parses it, then continues. If your CSS is 200 KB on a slow network, that's a 1-2 second pause before any pixels paint. Same for synchronous JS in <head>.

Three fix tactics

1. Inline critical CSS

"Critical CSS" = the styles needed to render the above-the-fold portion of the page. Inline it directly in <head>:

<head>
  <style>
    /* critical: header, hero, primary nav */
    body { margin: 0; font-family: system-ui; }
    header { padding: 16px; background: #fafaf9; }
    h1 { font-size: 2rem; }
  </style>
  <link rel="preload" as="style" href="/full.css" onload="this.rel='stylesheet'" />
</head>

For larger sites, tools like Critical, Penthouse, or framework features (Next.js does this automatically in some configurations) extract critical CSS at build time.

2. Defer non-critical CSS

<!-- WRONG: blocks rendering -->
<link rel="stylesheet" href="/non-critical.css" />

<!-- RIGHT: load asynchronously, apply after parse -->
<link rel="preload" as="style" href="/non-critical.css" onload="this.rel='stylesheet'" />
<noscript><link rel="stylesheet" href="/non-critical.css" /></noscript>

The onload swap converts the preload into a stylesheet once it's loaded, without blocking. The <noscript> fallback ensures JS-disabled users still get styles.

3. Add defer or async to scripts

<!-- WRONG: blocks the parser -->
<script src="app.js"></script>

<!-- defer: runs after document parse, preserves order -->
<script src="app.js" defer></script>

<!-- async: runs whenever it's downloaded (no order guarantee) -->
<script src="analytics.js" async></script>

Rule of thumb:

4. Load fonts strategically

Web fonts are a common silent render-blocker. Best practice:

<head>
  <!-- preconnect to the font origin so DNS/TLS is warm -->
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />

  <!-- preload the most critical font file (typically the body font) -->
  <link rel="preload" as="font" type="font/woff2"
        href="https://fonts.gstatic.com/.../inter.woff2" crossorigin />

  <!-- load the CSS asynchronously -->
  <link rel="preload" as="style"
        href="https://fonts.googleapis.com/css2?family=Inter"
        onload="this.rel='stylesheet'" />
</head>

Or self-host fonts and use font-display: swap so text renders with a fallback font immediately.

Common mistakes

Verification

  1. Re-run Lighthouse, render-blocking-resources audit should pass or show much smaller estimated savings.
  2. Check first-contentful-paint and largest-contentful-paint audits, both should improve.
  3. DevTools → Network → throttle to Slow 3G → reload. The page should paint within ~1-2 seconds even on slow connections.

Related audits


Audit your URL at https://lighthouse-md.com.

Audit your page now

Paste your URL, get scores plus a CLAUDE.md plan for Claude Code.

Run audit →