# Eliminate render-blocking resources and unused CSS in WordPress

> How to eliminate render-blocking resources and remove unused CSS and JavaScript in WordPress: find which plugin or theme each file comes from, stop it loading where it is not needed, then defer, inline and trim the rest with your builder and cache plugin.

Updated 2026-09-26 · WordPress & WooCommerce · HTML version: https://getreport.app/guides/render-blocking-and-unused-css-wordpress

To eliminate render-blocking resources in WordPress, first find which plugin or theme adds each blocking file, stop the files loading on pages that do not use them, then let your page builder and one cache plugin defer the JavaScript, inline the critical CSS and remove unused CSS from what is left. Doing it in that order matters: a cache plugin can hide the symptom, but only unloading removes the cause, and it is what also fixes "reduce unused CSS" and "reduce unused JavaScript". This guide walks through each step with the plugin settings and the code. For how render blocking works on any site, read our [guide to eliminating render-blocking resources](https://getreport.app/guides/render-blocking-resources).

## Quick answer

1. **Measure** one page per template with the free [unused code checker](https://getreport.app/tools/unused-code) and the speed test, and note the files named.
2. **Trace each file to its source** from the URL (`/wp-content/plugins/{name}/` or `/themes/{name}/`) and its `id` attribute, which is the WordPress handle plus `-css` or `-js`.
3. **Unload files where they are not used,** with an asset manager or a few lines of code: a form plugin only on the contact page, WooCommerce styles only on shop pages.
4. **Switch on your builder's own asset settings** (Elementor, Divi) so it ships only the CSS and JavaScript of the widgets on each page.
5. **Let one cache plugin** defer JavaScript, load CSS without blocking and remove unused CSS, one switch at a time.
6. **Test menus, sliders, forms and checkout** after each change, then re-run the checker.

## Why WordPress sites have so much render-blocking CSS and JavaScript

WordPress themes and plugins add their files with `wp_enqueue_style()` and `wp_enqueue_script()`. Most enqueue on every page, because the plugin cannot know which pages will use it: a slider plugin loads on the blog, a form plugin on the product pages, WooCommerce styles on the About page. Stylesheets in the `<head>` block rendering by definition, and many older plugins also put their scripts in the `<head>` without `defer`.

Page builders add a second layer: CSS and JavaScript for every widget they offer, whether the page uses it or not. On a typical theme-plus-builder site, most of the CSS a page downloads is never used on that page. The waste is not in any single file; it is in files loading where they are not needed.

## Step 1: Find the files and where they come from

> **Free tool:** [Find and remove unused CSS and JavaScript](https://getreport.app/tools/unused-code): Free tool to remove unused CSS and JavaScript: real Chromium coverage shows the waste in every file, third parties marked, with Google's estimated time saved.

The unused code checker loads the page in Chromium with code coverage switched on and lists every script and stylesheet by unused bytes, first-party and third-party apart, with Google's estimate of the time you would save. The speed test's render-blocking finding lists the files that delay the first paint.

> **Check: No render-blocking resources delay the first paint.** Stylesheets and scripts in <head> stop the browser from drawing anything until they have downloaded. Each one adds a round trip before the visitor sees the page.
>
> 1. Add defer or async to scripts that are not needed before the first paint, or move them to the end of <body>.
> 2. Inline the CSS needed for the first screen and load the rest asynchronously (WordPress: "Optimize CSS delivery" in WP Rocket / LiteSpeed Cache).
> 3. Remove unused plugin CSS/JS from pages that do not need it.

> **Check: Little unused CSS is downloaded.** Most of the CSS on a typical page is never used on that page. It still has to download and parse before anything renders.
>
> 1. Remove or split stylesheets so each page loads only what it needs; page builders and themes often ship one giant file.
> 2. Use a "remove unused CSS" feature (WP Rocket, LiteSpeed Cache, PurgeCSS in your build).
> 3. Load below-the-fold or component CSS on demand.

> **Check: Little unused JavaScript is downloaded.** JavaScript is the most expensive thing a page loads: it must be downloaded, parsed and run. Code that never executes still costs all of that on a phone.
>
> 1. Delay third-party scripts until interaction (WP Rocket "Delay JavaScript", Shopify: audit installed apps).
> 2. Code-split large bundles so each page loads only its own code.
> 3. Remove plugins, apps and tags you no longer use.

To trace a file to its source, look at its URL and its `id`:

```html
<link rel="stylesheet" id="contact-form-7-css"
  href="https://getreport.app/wp-content/plugins/contact-form-7/includes/css/styles.css?ver=5.9" media="all">
<script id="swiper-js" src="https://getreport.app/wp-content/plugins/some-slider/assets/swiper.min.js?ver=8.4"></script>
```

- The folder after `/plugins/` or `/themes/` names the plugin or theme.
- The `id` is the handle WordPress registered, plus `-css` or `-js`. Here the handles are `contact-form-7` and `swiper`. You need the handle to unload the file in code.
- Files under `/wp-includes/` come from WordPress core, such as `wp-block-library` (block styles) and `jquery-core`.

The [WordPress theme & plugin detector](https://getreport.app/tools/wordpress-plugin-checker) adds up what each plugin loads on a page, and [what each WordPress plugin costs your page](https://getreport.app/guides/wordpress-plugin-cost) explains how to read it.

## Step 2: Unload files on pages that do not need them

This is the step that actually removes unused CSS and JavaScript, rather than hiding it. Two ways:

### With an asset manager plugin

Asset CleanUp and Perfmatters (its Script Manager) list every file each page loads, grouped by plugin, and let you switch a file off per page, per post type or everywhere except chosen pages. Typical rules:

- Contact form plugin: off everywhere except the contact page.
- Slider plugin: only on the home page.
- WooCommerce styles and scripts: off on blog posts and static pages (keep them on shop, product, cart, checkout and account pages).
- Social sharing and comment plugins: only on posts.

Test each rule on the pages it touches. An asset manager is one more plugin, but it runs its logic before the page is built and usually pays for itself.

### With code

If you prefer no extra plugin, dequeue by handle in a child theme's `functions.php` or a small must-use plugin. Use a late priority so the plugin has already enqueued its files:

```php
<?php
// wp-content/mu-plugins/unload-assets.php
add_action('wp_enqueue_scripts', function () {
    // Contact Form 7 only on the contact page
    if (!is_page('contact')) {
        wp_dequeue_style('contact-form-7');
        wp_dequeue_script('contact-form-7');
    }
    // Slider only on the front page
    if (!is_front_page()) {
        wp_dequeue_style('swiper');
        wp_dequeue_script('swiper');
    }
}, 100);
```

Some plugins offer their own switch. Contact Form 7 has the filters `wpcf7_load_js` and `wpcf7_load_css`, and WooCommerce's stylesheets can be removed with the `woocommerce_enqueue_styles` filter, for example on a site that styles the shop entirely in its theme.

### WordPress core block styles

WordPress loads `wp-block-library`, the CSS for all core blocks. Block themes load only the styles of the blocks each page uses. Classic themes can opt in with one line (WordPress 5.8 and later):

```php
add_filter('should_load_separate_core_block_assets', '__return_true');
```

If the site does not use the block editor at all, for example a site built entirely in a page builder, you can dequeue `wp-block-library` instead. Check a few posts first: content made with blocks will lose its styling.

## Step 3: Turn on your page builder's asset settings

Builders ship the most unused CSS, and each has settings that load only what a page's widgets need:

- **Elementor:** Settings → Performance (in older versions, Features): Optimized CSS Loading, Improved Asset Loading and the related switches. See [Elementor performance](https://getreport.app/guides/elementor-performance-asset-loading-fonts-dom).
- **Divi:** Theme Options → General → Performance: Dynamic CSS, Dynamic JavaScript Libraries, Critical CSS and Defer jQuery and jQuery Migrate. See [Divi performance settings](https://getreport.app/guides/divi-performance-settings).

Builder settings come before the cache plugin, because they reduce what exists; the cache plugin then has less to process.

> **Check: Page builder weight.** A page builder ships its whole framework on every page, whatever the page uses, and wraps every element in extra containers. When it becomes most of the code and most of the markup the visitor downloads and the browser lays out, every other speed fix has less to work with.
>
> 1. Switch on the builder's own performance settings first: see the report for the exact setting
> 2. Remove widgets, animations and add-on packs the page does not use; each one adds its own CSS and JavaScript.
> 3. For the pages that matter most (home, key landing pages) consider building them with core blocks and the theme alone, and keep the builder for the rest.

## Step 4: Defer JavaScript and load CSS without blocking

Now let one cache or performance plugin handle delivery. The settings have different names but do the same four jobs:

| Job | What it does | WP Rocket | LiteSpeed Cache |
| --- | --- | --- | --- |
| Defer JavaScript | Scripts download in parallel and run after parsing | Load JavaScript deferred | Load JS Deferred → Deferred |
| Delay JavaScript | Chosen scripts run only after the first interaction | Delay JavaScript execution | Load JS Deferred → Delayed |
| Load CSS without blocking | Inline critical CSS, load the full CSS later | Optimize CSS delivery → Load CSS asynchronously | Load CSS Asynchronously |
| Remove unused CSS | Replace stylesheets with only the rules each page uses | Optimize CSS delivery → Remove Unused CSS | Generate UCSS |

Our [WP Rocket settings](https://getreport.app/guides/wp-rocket-settings-for-core-web-vitals) and [LiteSpeed Cache settings](https://getreport.app/guides/litespeed-cache-settings-for-core-web-vitals) guides give the values we recommend and the exclusions each needs. Other plugins, such as Autoptimize, offer similar options under their own names.

Three rules keep this safe:

- **Defer before delay.** Deferring rarely breaks anything; delaying breaks anything that must work before a tap, such as a cookie banner or an above-the-fold slider. For how deferring works and why inline scripts break, read [async vs defer](https://getreport.app/guides/async-vs-defer).
- **Remove unused CSS needs a safelist.** Styles for menus, pop-ups and elements added after interaction are "unused" when the page loads. Add their classes to the plugin's safelist when something loses its styling.
- **One cache plugin only.** Two plugins that both minify, defer and cache fight over the same files.

> **Check: One caching layer is active.** Two caching or optimisation plugins fight over the same files: double minification breaks scripts, and stale pages are served from whichever cache wins.
>
> 1. Keep one caching plugin (the one your host recommends) and deactivate the other.
> 2. If the host provides server-side caching, use only its plugin and a separate image optimiser if needed.

If you manage the theme yourself, WordPress 6.3 and later can defer your own scripts at the source with the `strategy` argument of `wp_enqueue_script()`, which is cleaner than rewriting HTML afterwards.

## Step 5: Minify CSS and JavaScript

Minifying strips whitespace and comments. In WordPress it is a checkbox in every cache plugin ("Minify CSS files", "CSS Minify") and in some builders. It saves a little on files that are not already minified; most plugin files ship minified (`.min.css`, `.min.js`) already. It does not reduce unused CSS; it only makes the same rules smaller. Minify in one place only: minifying in the builder and again in the cache plugin is a common source of broken scripts.

Leave "combine" options off on HTTP/2 and HTTP/3 hosts. Combining helped on HTTP/1.1, where every file cost a connection; today it mostly produces one big file that changes whenever any part changes, so browsers cannot cache the parts separately.

## Step 6: Verify and watch for breakage

After each change:

1. Clear the cache plugin's cache and any CDN cache.
2. Load the page as a logged-out visitor (logged-in admins often bypass optimisation).
3. Click through menus, sliders, tabs, forms, the cart and the checkout. Open the browser console and look for errors.
4. Re-run the unused code checker and the speed test on the same page. The files you unloaded should be gone, not just marked non-blocking.

Some files will stay. A theme's main stylesheet is always partly unused on any one page, because it holds the rules for other templates. Aim for a short list of small files, not an empty list.

## Common mistakes

- **Starting with "Remove unused CSS"** before unloading plugin files. It generates per-page CSS from everything that loads, including files you could have removed.
- **Delaying all JavaScript on day one.** Forms, carts and consent banners stop working until the visitor scrolls.
- **Dequeuing by guesswork.** Use the handle from the `id` attribute; a wrong handle does nothing.
- **Dequeuing in the parent theme.** The next update undoes it. Use a child theme or an mu-plugin.
- **Testing while logged in.** Most cache plugins do not optimise pages for administrators.
- **Keeping plugins you no longer use.** Deactivating a plugin removes every file it adds, which beats any optimisation setting.

## Questions people ask

### How do I remove unused CSS in WordPress without a plugin?

Find the handles of the stylesheets a page does not need from their `id` attributes, then call `wp_dequeue_style()` with conditional tags such as `is_page()` or `is_front_page()` in a child theme or must-use plugin, on `wp_enqueue_scripts` at priority 100. Classic themes can also load core block styles per block with the `should_load_separate_core_block_assets` filter.

### Why does the speed test still say "reduce unused CSS" after I installed a cache plugin?

Because most cache plugin settings change how CSS is delivered, not how much of it there is. Loading CSS asynchronously and minifying keep every rule. Only unloading files on pages that do not use them, your builder's per-widget CSS settings, or a "remove unused CSS" feature actually shrink it. Start with unloading, then check the result with the unused code checker.

### Which WordPress plugins cause the most render-blocking resources?

Usually page builders, slider and gallery plugins, form plugins, WooCommerce on non-shop pages, and social sharing or popup plugins, because they load their CSS and JavaScript on every page. The exact list differs per site, so measure: the file URLs in the speed test and the unused code checker name the plugin folder each file comes from.
