When the browser encounters a <script> tag or a <link rel="stylesheet"> in your HTML, it stops rendering the page until those files are downloaded and processed. On a WordPress site with 10+ plugins each loading their own CSS and JS, this can add 1–3 seconds to your First Contentful Paint (FCP).
Why render-blocking resources happen in WordPress
WordPress and its plugins load assets via wp_enqueue_scripts(). Without configuration, these are placed in the <head> section or just before </body>. Head scripts block rendering entirely. Even footer scripts block the main thread and increase Total Blocking Time (TBT).
The most common offenders on WordPress sites:
- jQuery (loaded in
<head>by default on older setups) - Font Awesome and icon libraries
- Google Fonts loaded without
display=swap - WooCommerce cart scripts loaded on every page
- Slider and carousel plugins (Revolution Slider, Slick)
- Contact form scripts loaded on every page (not just contact page)
- Page builder scripts (Elementor, Divi, Visual Composer)
Step 1: Identify your render-blocking resources
Run your site through PageSpeed Insights (or use WPStats which fetches PSI data for you). Look for the "Eliminate render-blocking resources" audit. It lists every blocking file with its potential savings in milliseconds.
Also open Chrome DevTools (F12) → Network tab → reload the page → sort by Waterfall column. Files with a long grey bar before the colored bar are blocking the render.
Step 2: Defer JavaScript (most impactful)
Adding the defer attribute to script tags tells the browser to download the script in parallel but only execute it after the HTML has been parsed — eliminating the render block entirely.
Option A: WP Rocket (easiest)
WP Rocket → File Optimization → JavaScript → enable "Load JavaScript deferred" and "Delay JavaScript execution." This automatically adds defer to all scripts and delays non-critical JS until user interaction.
Option B: functions.php (manual)
add_filter('script_loader_tag', function($tag, $handle, $src) {
// Exclude critical scripts that must run synchronously
$exclude = ['jquery-core', 'jquery-migrate'];
if (in_array($handle, $exclude)) return $tag;
// Add defer to all other scripts
return str_replace(' src', ' defer src', $tag);
}, 10, 3);
Warning: Deferring scripts can break functionality if a script depends on another running first. Always test thoroughly after enabling defer. Start with non-essential scripts.
Option C: Perfmatters plugin
Perfmatters provides granular per-script/per-page control — defer this script on all pages, disable that script on every page except WooCommerce. The most surgical approach.
Step 3: Optimize CSS delivery
CSS is always render-blocking — the browser won't paint anything until all CSS is loaded. The goal is to minimize critical CSS and defer non-critical stylesheets.
Inline critical CSS
Extract the CSS needed for above-the-fold content and inline it directly in <head>. Load the full stylesheet asynchronously:
<!-- Inline critical CSS -->
<style>
/* Only styles needed for above-the-fold content */
body { margin: 0; font-family: sans-serif; }
.header { background: #fff; height: 60px; }
.hero { min-height: 80vh; }
</style>
<!-- Load full CSS asynchronously -->
<link rel="preload" href="style.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="style.css"></noscript>
Generating critical CSS manually is tedious. Use the Critical CSS plugin or WP Rocket's "Remove Unused CSS" feature which automates this process.
Minify and combine CSS
Fewer CSS files mean fewer HTTP requests (less important with HTTP/2) and less total bytes. Enable CSS minification in your caching plugin. Be cautious with combination — it can break some theme/plugin combos.
Step 4: Optimize Google Fonts
Google Fonts loaded the traditional way are render-blocking. Three ways to fix them:
Option A: Add display=swap
<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">
This allows text to render immediately with a fallback font, replacing it with the custom font when loaded.
Option B: Preconnect + preload
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
Option C: Self-host fonts (best performance)
Download your fonts using the Google Fonts Helper tool, upload to your server, and serve them directly. Eliminates the external DNS lookup entirely and gives you full cache control.
Step 5: Disable scripts on pages where they're not needed
Contact Form 7 loads its scripts on every page — even pages with no contact form. Slider scripts load everywhere even without a slider. This is unnecessary overhead.
Use Perfmatters or Asset CleanUp to disable specific plugin scripts on specific page types. Common wins:
- Disable CF7 scripts everywhere except the contact page
- Disable WooCommerce scripts on non-shop pages
- Disable slider scripts on pages without sliders
- Disable comment scripts on pages with comments disabled
// Disable CF7 scripts globally, re-enable only on contact page
add_action('wp_enqueue_scripts', function() {
if (!is_page('contact')) {
wp_dequeue_style('contact-form-7');
wp_dequeue_script('contact-form-7');
}
}, 99);
Step 6: Use resource hints
Resource hints tell the browser to prepare for resources it will need soon:
<!-- DNS prefetch for external domains -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="dns-prefetch" href="//www.google-analytics.com">
<!-- Preconnect for high-priority external resources -->
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Preload critical resources -->
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/wp-content/themes/theme/style.css" as="style">
Measuring the improvement
After making changes, re-run PageSpeed Insights (or WPStats) and look for improvements in:
- FCP (First Contentful Paint) — should drop significantly
- TBT (Total Blocking Time) — reduced by deferring JS
- "Eliminate render-blocking resources" audit — should show fewer files or pass
- Overall Performance score — typically gains 10–25 points
Quick win: The WordPress emoji detection script is loaded in <head> and makes an extra DNS lookup. Remove it with: remove_action('wp_head', 'print_emoji_detection_script', 7); in functions.php. Instant FCP improvement for most sites.
See your WordPress FCP and TBT scores now
WPStats pulls real PageSpeed Insights data — see exactly how render-blocking resources are affecting your scores.
Check my PageSpeed scores