How to remove unused CSS in WordPress

In this post you will learn how to find and remove unused CSS on your website and prevent WordPress from transferring megabytes of unused code without any plugins.

Why should you remove unused CSS in the first place?

Come on, let’s be serious, you know why you should do it. 

You wouldn’t be here if you didn’t want to optimize your web page performance. You’ve probably run your website through a PageSpeed checker and received a suggestion to remove unused CSS.

Many websites use lots of 3rd party libraries or some pre-built themes, with lots of features and code to cover all possible scenarios, while only a small portion of it is really used. You end up transferring megabytes of unused CSS (dead code), which makes your website take really really long to load. 

How to find unused CSS?

If you use WordPress, unfortunately there isn’t an easy way to find unused CSS, like by just installing a plugin and clicking through some configuration steps. Although there are some tools online, that help to find the needed CSS by submitting your URL. 

Purifycss.online, for example, crawls your web page and checks all CSS files and inline styles as well. But caution: it will remove all CSS rules that aren’t used on the specified page, even though some of them might be used on sub pages. You have the possibility to insert multiple URLs, but if you manage a site with hundreds of pages, it might get quite cumbersome.

purifycss.online with multiple URLs and results

Disclaimer: purifycss.online is made by me. The JavaScript library purifycss, which the online tool is based on, is not.

How to use the purified CSS code on your WordPress website

1. Upload purified stylesheet

Now, if you already have your clean CSS code, let’s copy & paste it in a new file and name it styles.pure.css and upload it to your theme folder (if you’re using a pre-built theme, I hope you already created a child theme).

2. Remove existing stylesheets

Now you’ll have to remove all stylesheet references from your web page. You can do this by iterating through all queued styles and dequeue them. Add this to your functions.php:

// set a variable to make it easy to enable and disable the purifycss feature
// while testing, just append this parameter to your url: http://www.yourwebsite.com/?purifytest
$purifyCssEnabled = array_key_exists('purifytest',$_GET);

// when you're done, set the variable to true - you will be able to disable it anytime with just one change
// $purifyCssEnabled = true;

function dequeue_all_styles() {
    global $wp_styles;
    foreach( $wp_styles->queue as $style ) {
        wp_dequeue_style($wp_styles->registered[$style]->handle);
    }
}

if ($purifyCssEnabled) {
    // this will remove all enqueued styles in head
    add_action('wp_print_styles', 'dequeue_all_styles', PHP_INT_MAX - 1);

    // if there are any plugins that print styles in body (like Elementor),
    // you'll need to remove them as well
    add_action('elementor/frontend/after_enqueue_styles', 'dequeue_all_styles',PHP_INT_MAX);
}

3. Make sure all styles have been removed

Now open your web page URL with the ?purifytest parameter appended and you should see only the raw content your page. Open the source code viewer in your browser and make sure there is no <link rel="stylesheet" ...> and no <style>...</style> block left.

4. Remove inline styles if any exists

Unfortunately there is no WordPress hook to remove inline styles, as they are not enqueued like the stylesheet file references. 

The only possibility that comes to my mind (please let me know in the comments if there is a better way), is to go through the HTML that is about to be rendered and remove inline styles with regular expressions. To catch the full HTML, we need to do a workaround with output buffer.

Add this to your functions.php file:

/* Remove inline <style> blocks. */
function start_html_buffer() {
    // buffer output html
    ob_start();
}
function end_html_buffer() {
    // get buffered HTML
    $wpHTML = ob_get_clean();

    // remove <style> blocks using regular expression
    $wpHTML = preg_replace("/<style[^>]*>[^<]*<\/style>/m",'', $wpHTML);

    echo $wpHTML;
}
if ($purifyCssEnabled) {
    add_action('template_redirect', 'start_html_buffer', 0); // wp hook just before the template is loaded
    add_action('wp_footer', 'end_html_buffer', PHP_INT_MAX); // wp hook after wp_footer()
}

5. Enqueue the purified CSS

function enqueue_pure_styles() {
    wp_enqueue_style('pure-styles', get_stylesheet_directory_uri().'/styles.pure.css');
}

if ($purifyCssEnabled) {
    // enqueue our purified css file
    add_action('wp_print_styles', 'enqueue_pure_styles', PHP_INT_MAX);
}

6. Test your changes thoroughly!

Please keep in mind that you might have thrown away CSS code that is being used on sub pages or that is dependent on some user interaction, like a modal dialog, form validation messages, AJAX callbacks etc. 

Some tips what to pay attention to:

  • Hover over and click on each element
  • Try submitting your forms with incomplete or invalid data
  • Also test pages that are not linked from your home page or through your main navigation
  • Test on different screen sizes – not just by resizing your window, but also on different physical devices
  • Test in different browsers!
  • Please comment below with other frequent cases that might be missed by purifycss.online

7. Adjust purified CSS code

If you detect styles that are missing in your purified code, make sure first, that you added the URL of the page to the “additional URLs” on purifycss.online.

If that’s the case, then copy the corresponding HTML code of your unstyled element (like a modal popup) and add it to “custom HTML code”. 

For this, right click on the element, click “Inspect Element”, then in the Element view, right click on the tag and click Copy > Copy outerHTML

Copy element as HTML in Chrome Developer Tools

Then in purifycss.online paste the code into “Add custom HTML code”.

Add custom HTML code in purifycss.online

And then repeat from step 1 😉

Bonus tip: Optimize for First Contentful Paint (< 2s)

Now check your PageSpeed score again. You’ve done a really great job so far!

But there is one more thing you can optimize. It’s not just the PageSpeed score that matters, the perceived speed of your site matters much more. If your site takes longer than 2 seconds to show the first meaningful content, your users will be annoyed and might leave before your page even starts to render.

Even if the unused CSS is removed, your styles might still be too large. While the browser loads the CSS file, your web page remains blank. On slow connections (mobile 3G), this could be longer than we would like. 

Wouldn’t it be much better if the browser could load the CSS that is necessary to show the first visible portion right away? The rest could be loaded after the most important content is already visible. This technique is called Critical Path CSS. You’ll basically include the styles needed for the above-the-fold content as an inline-style and load the rest asynchronously. Read more about how to find critical CSS in detail.

Need a No-Code-Solution for PurifyCSS as WordPress Plugin?

Do you feel overwhelmed or unconfident with messing around in your PHP code?
I agree with you: the simplest way would be to run this purification process through a WordPress plugin. Unfortunately, there isn’t a PurifyCSS WordPress Plugin yet, but it’s on my plan.

Oh, no! I just noticed that I’m running out of coffee. 😱 I desperately need some coffee before being able to continue coding!
If you need this feature, please go to purifycss.online and buy me a coffee by clicking BuyMeACoffee in the top right corner. Thanks
😉

22 thoughts on “How to remove unused CSS in WordPress”

  1. hello,
    thank you for this tutorial,
    i have wordpress bundled with wpforo forum with di theme, i tried your tuto, but i have an issue with wpforo css and tinymce, can’t force them like elementor
    any suggestion?
    thank you

    1. Hi, the CSS calls you’re seeing in your DevTools Network tab, are initiated by tinymce.min.js. I don’t think you can do much about that, but it doesn’t necessarily harm your performance, as they are loaded asynchronously after page load. What I would suggest instead (not sure if that’s possible) is to try disabling tinymce for the pages where the editor is not needed, e.g. homepage.

    1. Hi Kerem, I can’t think of any conflict with Elementor. In my tests it worked just fine.
      Make sure to have backups before making any permanent changes and let me know if you get any conflicts.

  2. hello I have uploaded in the theme folder the styles file generated via the cpanel and then I inserted in the functions.php those codes you wrote in this guide, but how do I know if everything went well? is there a way to verify that the website is actually using the purified css? And regarding the other guide on critical css, I pasted the css before the / head tag in header.php but I don’t understand step 1.2, what should be done? what needs to be added in the body tag? can you give an example?

    Thanks

    1. Hi Charles, the easiest way to test if the purified CSS is used, is by opening the Developer Tools (F12 in Chrome) “Network” tab and filter by “style” or “css”. After refreshing the page, you will see which files were loaded.

      For critical CSS, you’ll need to insert the generated critical CSS code between <style> … </style> tags in <head> part of the page, while the reference to the rest of CSS, e.g. <link rel=”path/to/style.css”> must go in the footer.php.

    2. “you’ll need to insert the generated critical CSS code between <style> … </style> tags in <head> part of the page” in which pages?

      “while the reference to the rest of CSS” how are references made? is there a code to write? if you could make me understand how to write it? an example of code.

      thanks

    1. I am planning to build one, but didn’t make any significant progress yet. Subscribe to my newsletter, if you want to get such updates.

    1. Hi Moses, there is no plugin-based solution yet, as far as I know. But I’m seeing high demand here and plan to build a plugin. Sign up to the newsletter and get informed, when it’s ready.

  3. I don’t understand step two. So I get to skip current stylesheets, but how would I go with the clean up? Can you direct me where can I remove these stylesheets which are loading up and have a ton of code not used?

    I ran web-domain.com/?purifytest and it loaded the page without styles, what is the next steps to follow before getting to step 3 and right after 3.
    It seems its just temporary if i’m running ?purifytest.

    Awesome solution Peter.

    1. Hi Eduardo, step 1 assumes that you already have a purified CSS code. If you don’t have it yet, then go to purifycss.online, enter your URL(s), download the result file, name it styles.pure.css and upload it to your theme folder. Let me know if this helps. Cheers

  4. Hello Peter!

    Thank you so much for this solution! I think I have done all your steps correctly but want to be clear on this 1 step before implementing.

    In step 2 you say,

    // set a variable to make it easy to enable and disable the purifycss feature
    // while testing, just append this parameter to your url: http://www.yourwebsite.com/?purifytest
    $purifyCssEnabled = array_key_exists(‘purifytest’,$_GET);

    // when you’re done, set the variable to true – you will be able to disable it anytime with just one change
    // $purifyCssEnabled = true;

    where exactly do I set the variable to ‘true’?

    do I change the parameter
    $purifyCssEnabled = array_key_exists(‘purifytest’,$_GET);
    to
    $purifyCssEnabled = true;
    ?

    Or do I leave that parameter as is and add
    $purifyCssEnabled = true;
    to my functions.php before or after one of the pieces of code you provided?

    Thank you in advance for your help!

    -Kismet

    1. Thank you, Kismet for your feedback!

      I would suggest to comment out the line with
      // $purifyCssEnabled = array_key_exists(‘purifytest’,$_GET);
      and set the variable to true right below.
      $purifyCssEnabled = true;

      With that you can easily switch back and forth between the two modes by commenting/uncommenting the two lines when needed.

  5. Hi ‘Peter, thanks for great article, I have one slight problem.

    I’m using a plugin to generate cookie consent.

    When I enable remove inline css blocks. (it strips out the popover on first view to consent to cookies) I commented out those lines from your functions insert and its back… (is there any way to exclude that from happening) so I can take advantage of the strip inline css blocks AND retain the functionality of this.
    (website linked in my comment)
    regards Lee

  6. This is so DESPERATELY needed as a wordpress plugin. If it also works with Autoptimize plugin that would be amazing. Following for sure!!

  7. Peter,

    Really great and interesting solution. I’d like to give it a try, but I’m curious- Does this method prevent me from making any additional css changes from within wordpress (I use X Theme > Cornerstone Editor). If this is the case, if I make changes to design/site, would I have to toggle back so all styles are queued again, go through purifycss, and update the styles.pure.css?

    1. Hi Matt, I don’t know the X Theme, but it’s very likely, that you’ll need to disable the purifycss solution (e.g. by setting $purifyCssEnabled = false;) while working on changes and go through the whole purifycss process again when you’re done. I know that’s still some manual work, but hopefully I can provide an at least semi-automated solution soon.

Leave a Comment

Your email address will not be published. Required fields are marked *