Unused CSS is a persistent problem in WordPress themes that ship large utility or component stylesheets, and it is one of the quickest wins identified by Lighthouse’s Reduce Unused CSS audit. A typical WordPress theme loads 60–120 KB of CSS on a simple blog post, of which 40–80 percent may be styles that match no element on the current page. PurgeCSS analyses HTML, JavaScript, and PHP template output to build a list of all class and ID selectors actually used, then removes everything else from the stylesheet. Integrating PurgeCSS into a WordPress theme build process requires Node.js, a package.json, and a short configuration file that points to the theme’s PHP templates and JavaScript files as content sources. WordPress’s conditional tag system — is_singular(), is_archive(), and is_woocommerce() — lets you enqueue page-type-specific stylesheets instead of a single global stylesheet, which keeps each stylesheet small. Splitting a monolithic theme stylesheet into a base CSS file and separate page-type stylesheets reduces the bytes parsed on every page without a build tool. The wp_enqueue_style() function’s dependency array ensures stylesheets load in the correct cascade order when split across multiple files. Media-query splitting is an alternative: WordPress can enqueue the same stylesheet with a media parameter so the browser downloads but defers non-matching media queries during the critical rendering path. Critical CSS — the minimum styles needed to render above-the-fold content — can be inlined with wp_add_inline_style() to eliminate render-blocking stylesheet requests entirely. The JS and CSS deferral post covers the JavaScript side of the same Lighthouse audit and should be applied alongside CSS pruning. The CSS grid guide demonstrates writing purposeful, minimal CSS from the start rather than purging a large framework. After running PurgeCSS, always test dynamic class names generated by JavaScript plugins such as sliders or modals — dynamic classes are not present in static HTML and will be incorrectly purged unless you add them to the PurgeCSS safelist.
Problem: WordPress themes enqueue large monolithic stylesheets that include hundreds of unused CSS rules on every page, increasing render-blocking payload and hurting Core Web Vitals scores.
Solution: Add a PurgeCSS build step to strip unused selectors from the theme stylesheet, and use conditional WordPress enqueue logic to serve page-type-specific CSS only where needed.
// purgecss.config.js — place in theme root
module.exports = {
content: [
'./**/*.php',
'./js/**/*.js',
],
css: ['./style.css'],
output: './dist/',
safelist: {
standard: [/^slick-/, /^wp-/, /^menu-/, /^alignwide/, /^alignfull/],
deep: [/open$/, /active$/, /is-expanded$/],
},
};
// Run: npx purgecss --config purgecss.config.js
// functions.php — enqueue page-type stylesheets conditionally
add_action('wp_enqueue_scripts', function() {
$ver = wp_get_theme()->get('Version');
$dir = get_template_directory_uri();
// Base styles: loaded on every page
wp_enqueue_style('theme-base', "$dir/dist/base.css", [], $ver);
// Archive styles: loaded only on archive and search pages
if (is_archive() || is_search() || is_home()) {
wp_enqueue_style('theme-archive', "$dir/dist/archive.css", ['theme-base'], $ver);
}
// Single post styles
if (is_singular('post')) {
wp_enqueue_style('theme-single', "$dir/dist/single.css", ['theme-base'], $ver);
}
// WooCommerce styles
if (function_exists('is_woocommerce') && is_woocommerce()) {
wp_enqueue_style('theme-woo', "$dir/dist/woocommerce.css", ['theme-base'], $ver);
}
});
NOTE: Add Tailwind CSS utility classes and any class names toggled by JavaScript plugins to the safelist arrays — PurgeCSS cannot detect strings assembled at runtime and will strip them, breaking features that only activate on user interaction.