Eliminate Render-Blocking Resources: How to Fix It

No Comments
Eliminate render-blocking resources: how to fix it

What "Eliminate render-blocking resources" actually flags

This check fires when your page loads CSS or JavaScript in a way that halts rendering. A synchronous <script> or a stylesheet in the <head> forces the browser to stop, fetch, and process that file before it can paint a single pixel. Until every blocking resource in the head resolves, your visitor stares at a blank screen. Lighthouse lists each blocker and estimates the milliseconds you would reclaim by unblocking it.

The stakes hit First Contentful Paint and Largest Contentful Paint (LCP) directly, since nothing renders until the head clears. On slow connections a handful of blocking files can push first paint back by seconds, which is exactly where impatient users bail.

A real failing example (and the fix)

Here the head blocks on a full stylesheet and a synchronous script, both of which stall the first paint:

<head>
  <!-- Blocks paint until the whole file downloads and parses -->
  <link rel="stylesheet" href="/css/app.css">
  <!-- Blocks parsing AND paint right here in the head -->
  <script src="/js/bundle.js"></script>
</head>

Fix the script first, it almost never needs to block. Move it out of the critical path with defer (runs after HTML parses, in order) or async (runs whenever it arrives, for independent scripts):

<head>
  <script src="/js/bundle.js" defer></script>
</head>

For CSS, inline the small slice needed for above-the-fold content and load the rest without blocking. The media="print" swap is a reliable trick to fetch a stylesheet asynchronously, then apply it once loaded:

<head>
  <style>/* critical above-the-fold CSS, kept small */</style>

  <!-- Load the rest without blocking paint -->
  <link rel="stylesheet" href="/css/app.css"
        media="print" onload="this.media='all'">
  <noscript><link rel="stylesheet" href="/css/app.css"></noscript>
</head>

Why the head is a bottleneck

Browsers build a page in a strict order: parse the HTML, build the DOM, apply the CSSOM from your stylesheets, then paint. A blocking resource in the <head> jams a stop sign into that pipeline. The parser reaches your synchronous <script> and refuses to move on until the file is downloaded, parsed, and executed, because that script might rewrite the very HTML that follows it. A stylesheet blocks painting for the same reason: the browser will not risk flashing unstyled content, so it waits for the CSS. That is why two or three files in the head, each needing its own round trip on a slow connection, can hold the screen blank for whole seconds while the rest of your beautifully optimized page sits ready and waiting.

defer vs. async vs. blocking

AttributeBlocks HTML parsing?Execution timingUse for
none (default)YesImmediately, in placeAlmost nothing in the head
deferNoAfter parse, in document orderMost app/site scripts
asyncNoAs soon as it downloadsIndependent tags (analytics)
inline critical CSSNo (already present)N/AAbove-the-fold styles
media="print" swapNoOn loadNon-critical stylesheets

How to detect it on your own site

  1. Lighthouse: the "Eliminate render-blocking resources" opportunity names every blocking URL and the estimated savings in milliseconds for each, so you can prioritize the biggest wins.
  2. PageSpeed Insights: the same opportunity appears at pagespeed.web.dev, tied to your field LCP so you know whether blocking is what is actually delaying real users.
  3. DevTools Coverage tab: open Coverage (Cmd/Ctrl+Shift+P, "Show Coverage"), reload, and see how much of each blocking CSS/JS file is unused, that unused chunk is a prime candidate to split out and defer.
  4. WebPageTest: the waterfall shows blocking requests stacked before Start Render. Anything to the left of that green line is delaying your first paint.

How to fix it, step by step

  1. Add defer to scripts that need DOM order, or async to independent third-party tags; move both out of blocking position.
  2. Extract the critical above-the-fold CSS, inline it in the head, and keep it lean.
  3. Load the remaining CSS non-blocking with the media="print"/onload pattern (plus a <noscript> fallback).
  4. Split large bundles so each page ships only the CSS and JS it needs; delete unused code (remove unused JavaScript).
  5. Preload genuinely critical assets (a hero font or LCP image) so they start early without blocking parse.
  6. Re-run Lighthouse and confirm the blocking list shrinks and FCP/LCP improve.

FAQ

Should I just defer every script?

Defer is the safe default for most site scripts because it preserves execution order and waits for the DOM. Use async only for scripts that do not depend on the page or each other, like an analytics beacon. Inline scripts that must run before paint (rare) stay put.

Is inlining CSS bad for caching?

Inlined critical CSS is not cached separately, but it is tiny by design and it removes a blocking round trip. The bulk of your stylesheet still loads as a cacheable external file. The tradeoff favors inlining the small critical part.

Do blocked resources hurt crawling or just speed?

Mostly speed and Core Web Vitals. But if you go the other way and block CSS/JS from crawlers in robots.txt, that does break rendering for Google, see disallowed stylesheet. Deferring for users and disallowing for bots are different problems.

Will a CDN solve render-blocking?

A CDN makes blocking files arrive faster, which helps, but a resource in the critical path still blocks. You have to change how it loads, not just where it loads from.

How does this tie into Core Web Vitals?

Render-blocking directly delays paint, which pushes out LCP, one of the three Core Web Vitals. Clearing the critical path is one of the highest-leverage LCP fixes there is.

How do I know which CSS is "critical"?

Critical CSS is only the styling needed to render what is visible above the fold on first paint, the header, hero, and initial layout, not your footer or modal styles. You can extract it by hand from the styles those elements use, or generate it with a critical-CSS tool that loads the page, records which rules apply to the visible viewport, and inlines just those. Keep it small; if your "critical" block balloons, you have defeated the point and are back to shipping most of the stylesheet inline.

Does WordPress handle this automatically?

Not out of the box, but caching and optimization plugins can defer JavaScript, inline critical CSS, and load the rest asynchronously with a few toggles. Test after enabling, aggressive deferral occasionally breaks a script that expected to run early. See speed up WordPress for the safe settings.

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog