Render-Blocking Resources: What They Are and How to Fix Them
What Render-Blocking Resources Are
When a browser parses an HTML document and encounters a <link rel="stylesheet"> or a <script> tag in the document head, it stops parsing HTML and waits for that resource to download and execute before continuing. This pause is called "render blocking" — the browser cannot paint anything to the screen until these resources are processed.
Render-blocking resources directly delay First Contentful Paint (FCP) and Largest Contentful Paint (LCP). Every millisecond spent waiting for a render-blocking stylesheet or script is a millisecond delay before the user sees anything. On a slow 4G connection, a single render-blocking CSS file can add 500ms+ to your FCP.
CSS is render-blocking by default because the browser needs styles to render content correctly — it doesn't want to show unstyled content (a flash of unstyled content, or FOUC) and then reflow. JavaScript without async or defer attributes is also render-blocking because it might contain document.write() calls that modify the HTML being parsed.
How to Identify Render-Blocking Resources
Google PageSpeed Insights will explicitly list render-blocking resources in the "Eliminate render-blocking resources" opportunity, including an estimated time saving for each. This is the easiest starting point — run your URL through PSI and look for this audit.
Chrome DevTools provides deeper analysis: open DevTools (F12), go to the Performance tab, click "Record" (or press Ctrl+Shift+E), reload the page, then stop recording. In the waterfall view, look for resources in the "Network" row that appear before the first paint (marked by FCP or LCP lines). Resources with long bars in the early part of the waterfall that block the FCP line are your culprits.
The Coverage tab (DevTools > More Tools > Coverage) shows exactly how much of each CSS and JS file is actually used on the current page. A stylesheet that's 80% unused is a strong candidate for splitting — load only the critical above-the-fold CSS inline and defer the rest.
Fixing Render-Blocking CSS
The gold standard for CSS is the critical CSS pattern: extract the CSS needed to render above-the-fold content (the styles visible on first load without scrolling), inline it directly in the <head>, and defer the full stylesheet to load after the initial render. This eliminates render blocking entirely while preventing FOUC for visible content.
Tools to generate critical CSS automatically: critters (used by Next.js and Angular by default), critical (npm package), and Penthouse. These tools run a headless browser, identify which CSS rules apply above the fold, and output the critical CSS string.
Fixing Render-Blocking JavaScript
For JavaScript, the fix is usually one of three attributes: defer, async, or moving the script to the end of <body>.
defer: Downloads the script in parallel with HTML parsing, then executes it after the HTML is fully parsed (but before DOMContentLoaded). Scripts execute in order. Use this for scripts that need the DOM to be ready and that depend on each other's execution order (e.g., analytics that need page title from the DOM).
async: Downloads the script in parallel and executes it as soon as it's downloaded — potentially interrupting HTML parsing. Use this only for completely independent scripts that don't depend on the DOM or on other scripts (e.g., independent A/B testing beacons, some third-party widgets).
Common Render-Blocking Offenders
Google Tag Manager: GTM's main snippet is render-blocking. The standard GTM installation instructions put the script in the <head> without defer/async because some tags must fire before pageview events. However, you can add async to the GTM script tag with minimal impact on most tag implementations. The GTM team acknowledges this trade-off.
jQuery: Many themes and plugins still load jQuery synchronously in the head. Add defer to the jQuery script tag — but be aware this may break plugins that call jQuery before DOMContentLoaded. Test thoroughly after making this change.
Font loaders: Loading fonts via JavaScript (e.g., older versions of Typekit/Adobe Fonts) is render-blocking. Switch to @font-face with font-display: swap or use <link rel="preload"> for self-hosted fonts.
What NOT to defer: Anti-flicker snippets for A/B testing tools (like Optimize, VWO, or Optimizely) must execute before render — deferring them causes flicker. Keep these synchronous in the head, but minimize their size. Some analytics implementations also need to be synchronous to capture early events.
WordPress-Specific Render-Blocking Fixes
WordPress plugins that help eliminate render-blocking resources:
WP Rocket: Under "File Optimization," enable "Defer JavaScript" (excludes jQuery by default to prevent conflicts) and "Load JavaScript Deferred." Enable "Optimize CSS Delivery" to inline critical CSS. These settings handle 80% of render-blocking issues automatically.
Autoptimize: Aggregates and minifies CSS and JS. Enable "Inline and Defer CSS" to use the critical CSS approach. Enable "Force JavaScript in Head" with the defer option to add defer attributes automatically.
After applying render-blocking fixes, re-run PageSpeed Insights and compare the "Eliminate render-blocking resources" opportunity. A successful fix should show that opportunity removed or dramatically reduced in estimated savings. LCP improvements of 0.5-2 seconds are common after eliminating all render-blocking resources.