Technical SEO

Render-Blocking Resources: How to Fix JavaScript & CSS That Delays Page Load

By Reviewed by Hawrry Bhattarai
August 23, 2026 15 min read
Contents
TL;DR — the short answer

Fix render-blocking JavaScript and CSS that delays LCP and FCP. Understand defer vs async, critical CSS extraction, above-the-fold optimization, and how to validate fixes.

12 min read · Technical SEO · Last updated July 2026

Quick answer: Render-blocking resources are JavaScript and CSS files that the browser must fully download and process before it can display any page content. They delay First Contentful Paint (FCP) and Largest Contentful Paint (LCP). The fix is either eliminating the blocking resource, deferring JavaScript execution, or inlining critical CSS and loading non-critical CSS asynchronously.

Introduction

Your page might have a fast server (low TTFB) and perfectly compressed images, but if the browser stalls for 1.5 seconds loading a render-blocking JavaScript bundle before it can show anything, users see a blank white screen. That white screen is FCP. And a delayed FCP means a delayed LCP — one of Google’s three Core Web Vitals metrics.

Render-blocking resources are the most common cause of poor LCP scores on sites that aren’t resource-heavy. A WordPress site with 8 plugins, each adding CSS and JavaScript to the <head>, can accumulate 400–1,200ms of render-blocking delay from those resources alone — before a single pixel is painted.

This guide explains exactly what causes render-blocking, how to diagnose it, and the specific fixes for each scenario — from simple JavaScript defer to critical CSS extraction.

What you’ll learn:
– What render-blocking is and how browsers process resources
– How to identify render-blocking resources with Lighthouse and PageSpeed Insights
– The correct use of defer vs async for JavaScript
– How to extract and inline critical CSS
– Above-the-fold optimization strategies
– How to verify your fixes actually worked


Table of Contents

  1. What Are Render-Blocking Resources?
  2. How Render-Blocking Affects Core Web Vitals
  3. Identifying Render-Blocking Resources
  4. defer vs async JavaScript
  5. Critical CSS: What It Is and How to Extract It
  6. Above-the-Fold Optimization
  7. Testing and Verifying Fixes
  8. Common Mistakes When Removing Render-Blocking
  9. Frequently Asked Questions
  10. Conclusion

What Are Render-Blocking Resources?

When a browser loads a web page, it parses HTML from top to bottom, building the Document Object Model (DOM). When it encounters a <link rel="stylesheet"> or <script> tag without special attributes, it stops building the DOM, downloads and processes that resource, then resumes.

This stop-and-process behavior is render-blocking. The browser cannot paint anything to the screen until all render-blocking resources are resolved. This is why a page with 5 external CSS files and 4 JavaScript files in the <head> appears blank in the browser for longer than a page with the same files loaded non-blocking.

Why does this default exist? It’s intentional. CSS defines how the page looks — parsing CSS before rendering prevents a “flash of unstyled content” (FOUC). Synchronous JavaScript can modify the DOM, so the browser waits for it to execute before continuing to parse HTML (because the script might change what comes next).

The problem: not all CSS needs to be loaded before the page renders, and not all JavaScript needs to execute before the page is visible. Loading all CSS and JavaScript synchronously in the <head> is safe but unnecessary — it causes render-blocking for resources that users won’t even notice until after the page has loaded.

Resources that are render-blocking by default:
<link rel="stylesheet" href="..."> — all external CSS
<script src="..."> without async or defer attributes
– CSS @import rules within CSS files

Resources that are NOT render-blocking:
<script src="..." defer> — loads while parsing HTML, executes after DOM is built
<script src="..." async> — loads while parsing HTML, executes immediately when downloaded (can still block briefly)
<link rel="preload" as="style"> — preloads CSS without blocking rendering
– Fonts loaded via font-display: swap


How Render-Blocking Affects Core Web Vitals

Render-blocking resources directly delay two metrics that matter for rankings:

First Contentful Paint (FCP): FCP measures when the browser first renders any content — text, image, SVG. Render-blocking resources delay FCP because no content can render until they’re resolved. A page with 800ms of render-blocking delay will have FCP no earlier than 800ms (typically much later, once parsing and rendering also complete).

Largest Contentful Paint (LCP): Google’s primary Core Web Vitals metric. LCP measures when the page’s largest content element becomes visible. Since LCP can’t start until FCP, render-blocking resources that delay FCP also delay LCP by the same amount. Google’s “Good” LCP threshold is 2.5 seconds. On a page where 1.2 seconds is consumed by render-blocking JavaScript, you have only 1.3 seconds left for everything else to reach good LCP.

Total Blocking Time (TBT): Long-running JavaScript tasks (over 50ms) create blocking periods where the browser can’t respond to user input. JavaScript loaded with async can still contribute to TBT if it executes as a long task. defer typically improves TBT by pushing execution to after initial render.

The cascade: Render-blocking resources → delayed FCP → delayed LCP → poor Core Web Vitals → reduced Page Experience ranking signal. The cascade is entirely linear. Fixing render-blocking at the top fixes every metric below it.


Identifying Render-Blocking Resources

PageSpeed Insights (pagespeed.web.dev): Run your URL. In the “Opportunities” section, look for “Eliminate render-blocking resources.” It shows each blocking resource, its size, and the estimated time savings from fixing it. This is the fastest diagnostic.

Chrome DevTools Lighthouse: Open DevTools (F12), click Performance or Lighthouse tab, run an audit. The Lighthouse report shows render-blocking resources under “Opportunities.” DevTools Coverage tab shows which CSS and JavaScript is actually used vs loaded but unused — the unused portion is a candidate for either deferred loading or elimination.

WebPageTest (webpagetest.org): The waterfall view shows exactly when each resource starts downloading and when it finishes. Resources that block the “Start Render” marker (the vertical line where painting begins) are render-blocking. WebPageTest also shows filmstrip screenshots — you can see the exact moment the first content appears, correlated against the waterfall.

Chrome DevTools Network tab: Load the page with DevTools open, Network tab active. Look at the Initiator column and Priority column. Resources with “High” priority that initiate from the main HTML document and appear in the waterfall before the page first renders are candidates for render-blocking analysis.

A typical WordPress site audit finding: 7 CSS files (totaling 180KB) and 9 JavaScript files (totaling 320KB) are loading synchronously in the <head>. Combined render-blocking time: 1,350ms. After optimization (defer non-critical JS, inline critical CSS, async-load non-critical CSS): render-blocking time reduced to 120ms (only the critical CSS inline). FCP improved from 3.1s to 1.2s.


⏱️ Render-Blocking vs Non-Blocking Timeline


defer vs async JavaScript

The defer and async attributes on <script> tags change when the browser downloads and executes external JavaScript:

Default (no attribute):

<script src="app.js"></script>

Browser encounters the script → stops parsing HTML → downloads app.js → executes app.js → resumes parsing. This is fully render-blocking. Avoid this for any script in <head>.

async:

<script src="analytics.js" async></script>

Browser starts downloading analytics.js while continuing to parse HTML. When the download finishes, the browser pauses HTML parsing and executes the script immediately. Less blocking than synchronous, but can still briefly interrupt parsing. Use for: Independent scripts that don’t depend on the DOM or other scripts — analytics, ad scripts, third-party widgets.

defer:

<script src="app.js" defer></script>

Browser starts downloading app.js while continuing to parse HTML. Execution is deferred until after the entire HTML document is parsed. Multiple deferred scripts execute in order. Use for: Any script that manipulates the DOM, depends on jQuery or another library, or is your main application code.

When to use which:

Script Type Use
Main application bundle defer
jQuery and dependents defer
Analytics (GA4, GTM) async
Social sharing widgets async or defer
A/B testing (Optimize, VWO) Inline at top (can’t defer)
Chat widgets defer
Ad scripts async

Moving scripts to bottom of <body> vs defer: Both strategies delay execution until after HTML parsing. But defer in <head> allows the browser to start downloading the script earlier — as soon as <head> is parsed — while executing after the DOM is ready. Bottom-of-body placement doesn’t start downloading until the browser reaches that position. defer is generally faster.


Critical CSS: What It Is and How to Extract It

Critical CSS is the minimal set of CSS styles needed to render the above-the-fold content of a page. Instead of loading all your CSS in a blocking <link> tag, you inline the critical CSS in a <style> tag in <head> and load the rest asynchronously.

The result: the browser can render the visible viewport immediately after parsing the HTML head — no external CSS request needed. Full CSS loads asynchronously and “fills in” the rest of the page styles after the above-fold content is visible.

What counts as critical CSS:
– Styles for the page layout (width, max-width, flexbox/grid)
– Styles for above-the-fold elements: header, hero, first content section
– Typography for visible text: font-family, font-size, color
– Background colors and primary visual structure
– Approximately 10–30KB of CSS for most pages

What is non-critical CSS:
– Styles for elements below the fold
– Hover states, animations, transitions
– Styles for modals, drawers, pop-ups
– Print styles
– Footer styles

Extracting critical CSS:

Tool-based extraction:
Critical (npm package): npm install -g critical — runs headlessly and extracts CSS for specified URLs
Penthouse: Another npm-based extractor with configurable viewport sizes
Crittr: Focuses on performance and accuracy

WordPress tools:
WP Rocket has a “Remove Unused CSS” feature that automatically generates critical CSS per page and defers the rest
Flying Pages and Async JavaScript plugin for deferring non-critical CSS

Implementation pattern:

The rel="preload" trick: preloads the CSS file (starts downloading early without blocking render) and then switches to rel="stylesheet" when loaded. The <noscript> fallback ensures CSS loads normally if JavaScript is disabled.


Above-the-Fold Optimization

Above-the-fold optimization is the set of techniques that ensure the visible viewport renders as fast as possible, regardless of how much content or resources exist below it.

Image preloading for LCP: If your LCP element is an image (hero image, featured product photo), preload it to start downloading immediately:

<link rel="preload" as="image" href="hero.webp" fetchpriority="high">

The fetchpriority="high" attribute (supported in all modern browsers) tells the browser this resource is critical and should be prioritized over other resources.

Font optimization: Web fonts loaded via @font-face in external CSS files are render-blocking in effect — even if CSS loads asynchronously, fonts needed for above-fold text create invisible text (FOIT) until they load. Fix:

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" as="font" href="/fonts/inter-regular.woff2" type="font/woff2" crossorigin>

And in CSS: font-display: swap; — shows system font immediately, swaps to web font when loaded.

Lazy loading below-fold images: Add loading="lazy" to all images that aren’t in the initial viewport:

<img src="product.webp" loading="lazy" alt="Product description">

This prevents below-fold images from competing with above-fold resources for bandwidth. One of the easiest, highest-impact optimizations available.

Resource hints for third-party connections:

<link rel="preconnect" href="https://www.googletagmanager.com">
<link rel="preconnect" href="https://connect.facebook.net">

These establish DNS, TCP, and TLS connections to third-party domains before they’re needed, reducing connection latency when those scripts eventually load.


🔬 defer vs async Interactive Comparison


Quick Reference Table
Attribute Download Execution DOM Order Best For
none Blocks HTML Immediate Yes Avoid in <head>
async Parallel On download No Analytics, ads
defer Parallel After DOM ready Yes App code, jQuery


Testing and Verifying Fixes

After implementing render-blocking fixes, verify they actually work:

PageSpeed Insights re-test: Run PageSpeed Insights again. The “Eliminate render-blocking resources” opportunity should show reduced time savings or disappear entirely. The Performance score should improve. Compare FCP and LCP values before and after.

Lighthouse in Chrome DevTools: Run a Lighthouse audit in an incognito window (avoids extension interference). Compare the “Render Blocking Resources” section — it should show fewer or no blocking resources.

WebPageTest filmstrip: Run a WebPageTest comparison with before and after URLs (or use the comparison feature). The filmstrip shows the exact frame where content first appears. Visual comparison makes the improvement tangible.

Search Console Core Web Vitals: After making performance changes, wait 28 days (the rolling window CrUX uses). Check Search Console’s Core Web Vitals report for your pages. URL-level data shows whether field metrics improved.

Critical check — visual regression: After deferring CSS or inlining critical CSS, load the page in multiple browsers and devices to confirm there’s no flash of unstyled content (FOUC). If styles appear broken or elements flash before styling kicks in, your critical CSS extraction didn’t capture all above-fold styles.

Key takeaway: Fixing render-blocking resources is the highest-impact optimization you can make to improve FCP and LCP without changing any page content. The rendering pipeline is sequential — removing blockers at the start speeds up everything that follows.


Common Mistakes When Removing Render-Blocking

Deferring A/B testing scripts: Tools like Google Optimize, VWO, and Optimizely work by modifying the DOM before render. If you defer them, users see the original page briefly before the test variant loads — this is the “flicker” problem. These scripts genuinely need to load synchronously. Accept the render-blocking cost or use a server-side A/B testing approach.

Not updating the critical CSS when design changes. If your critical CSS is extracted once and hardcoded, any design update to above-fold styles will cause a FOUC. Re-extract critical CSS whenever above-fold design changes.

Incorrectly applying async to jQuery-dependent scripts. If your theme or plugin scripts depend on jQuery, and jQuery is loaded async, those scripts may execute before jQuery is available — causing JavaScript errors. Use defer for both jQuery and its dependents to preserve execution order.

Removing CSS without checking all pages. Critical CSS extraction is viewport and page-type specific. Critical CSS for your homepage is different from your product page. Use per-page-type critical CSS when using WP Rocket’s optimization features, not a global single extraction.

Adding defer to inline scripts. defer only applies to external scripts (src="..."). Inline <script> tags cannot be deferred — they always execute synchronously. Move inline JavaScript to external files if you want to defer it.


Frequently Asked Questions

What is the difference between render-blocking and parser-blocking?
They’re almost the same thing. All render-blocking resources in <head> are also parser-blocking — they stop both HTML parsing and rendering. Render-blocking specifically refers to preventing the first paint. Parser-blocking refers to halting DOM construction. In practice, a synchronous script in <head> causes both effects simultaneously.

Does Google’s bot care about render-blocking resources?
Yes. Googlebot renders pages using a Chromium-based renderer. Render-blocking resources delay Googlebot’s ability to see the page’s content. While Google uses both raw HTML and rendered content for indexing, render-blocking delays the rendered view. This can affect how Google evaluates page experience signals and Core Web Vitals field data.

Can I use defer for everything?
Almost. defer is safe for any script that doesn’t need to execute before HTML parsing completes. A/B testing scripts and analytics scripts that track initial page views are exceptions — they need to run earlier. For everything else (jQuery, plugins, app code, chat widgets), defer is safe and beneficial.

My Lighthouse score improved but Search Console still shows Poor CWV. Why?
Lighthouse is a lab test with simulated conditions. Search Console Core Web Vitals uses field data from real Chrome users (CrUX). The two can diverge significantly. Field data uses a 28-day rolling window — improvements take time to show up. Also, real users may have different devices, networks, and browser cache states that affect performance differently from lab conditions.

How do I fix render-blocking resources on Shopify?
Shopify’s theme liquid controls how CSS and JavaScript load. Modify your theme’s theme.liquid to add defer to script tags where possible. Shopify apps inject their scripts via the App Bridge — you have limited control over third-party app scripts. For critical CSS, you can inline styles in your <head> liquid section. Shopify’s Dawn theme (the official reference theme) already implements many of these best practices.


Conclusion

Render-blocking resources are often the single biggest obstacle between a site with good content and good Core Web Vitals scores. The gap between “average WordPress site with plugins” and “optimized WordPress site” on FCP can be 1–2 seconds — all attributable to synchronously loaded CSS and JavaScript.

The fix hierarchy: first, defer all JavaScript that can be deferred. Second, extract critical CSS and async-load non-critical CSS. Third, preload your LCP image and use lazy loading on below-fold images. Fourth, add preconnect hints for third-party domains. Each step removes blocking time from the critical rendering path.

Use the timeline comparison and defer/async explainer above to understand what you’re changing and why. Test with PageSpeed Insights before and after. Monitor in Search Console for field data improvement over 28 days.


Let Ignited Nepal Handle This

→ Request a Free Technical SEO Audit


Written by the Ignited Nepal SEO team. We build organic search systems for businesses across Nepal, Australia, UAE, USA, UK, and beyond. ignitednepal.com

NR

Article by

Niraj Raut

Head of Search at Ignited Nepal. Drove 340% organic traffic growth for EzyDog (Australia), 4× revenue for The Turf Man (Australia), and 120% month-on-month traffic growth for ThemeGrill (Nepal). Keynote speaker at WordCamp Nepal 2023 and verified WordPress.org open-source contributor.