Removing Unused CSS Code With PurgeCSS

Optimize your web projects by automatically removing unused CSS selectors. A complete guide to PurgeCSS implementation for faster, leaner websites.

Understanding Unused CSS and Its Impact

Modern web applications often accumulate CSS bloat over time. Legacy styles from refactored components, unused utility classes from design systems, and entire CSS framework modules that were imported but never utilized all contribute to bloated stylesheets that slow down page loads and hurt user experience.

PurgeCSS is a powerful tool that analyzes your project content and removes unused CSS selectors, dramatically reducing stylesheet sizes. This guide covers everything you need to know about implementing PurgeCSS in your web development workflow.

The Problem of CSS Bloat

CSS files tend to grow over the lifecycle of a project. Several factors contribute to this bloat:

  • Legacy styles from removed or refactored components
  • Utility classes from CSS frameworks (like Bootstrap's 147 KB+ when minified) that go unused
  • Design system additions that supersede older patterns
  • Developer experimentation that wasn't cleaned up
  • Theme variations and responsive breakpoints for devices no longer supported

This unused CSS has real consequences for website performance. Larger stylesheets mean longer download times, especially on mobile networks. The browser must parse and process more CSS before rendering the page, which delays first contentful paint and time to interactive. Additionally, larger CSS bundles consume more memory and increase the computational cost of style calculations during rendering. For performance-conscious development teams, removing unused CSS is one of the highest-impact optimizations available, requiring no changes to visual design or functionality.

How Unused CSS Affects Core Web Vitals

Core Web Vitals metrics like Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS) are directly impacted by CSS performance. When users download excess CSS, they wait longer for the page to become visually complete. The parsing overhead can also cause main thread blocking that affects interactivity. Optimizing CSS not only improves user experience but also supports your overall SEO strategy by improving page speed signals that search engines consider.

How PurgeCSS Works

The Core Algorithm

PurgeCSS operates on a deceptively simple but effective principle: it compares your CSS selectors against the actual content of your project to determine which selectors are actually being used.

The process:

  1. PurgeCSS scans your specified content files--HTML templates, JavaScript/TypeScript files, Vue/React/Svelte components--to extract all CSS selectors that appear in the content
  2. The extraction process uses specialized extractors designed for different file types to accurately identify selectors
  3. PurgeCSS walks through your CSS files and identifies which selectors are not present in the extracted content
  4. These unused selectors are then removed from the final output

Content Detection

The content option tells PurgeCSS which files to analyze. You can specify content as file paths, glob patterns, or arrays of both:

module.exports = {
 content: [
 './src/**/*.{js,jsx,ts,tsx,vue,html}',
 './public/index.html'
 ]
}

Selectors and Extractions

PurgeCSS extracts multiple types of selectors from your content:

  • Class selectors (.classname)
  • ID selectors (#idname)
  • Attribute selectors ([attribute="value"])
  • Tag selectors (div, span, etc.)
  • Pseudo-classes and pseudo-elements (when they affect specificity)
Key PurgeCSS Capabilities

Everything you need to effectively remove unused CSS

Multi-File Analysis

Analyze HTML, JavaScript, TypeScript, Vue, React, and other file types to find all used selectors

Smart Selectors

Extract class names, IDs, attribute selectors, and tag selectors from complex code structures

Framework Support

Native integration with Next.js, React, Vue, Webpack, PostCSS, and more

Safelist Controls

Keep specific selectors that are dynamically added or used in ways PurgeCSS cannot detect

Blocklist Options

Force removal of known-unused legacy styles that might appear in content

Keyframe Handling

Automatically remove unused @keyframes and @font-face declarations

Installing and Setting Up PurgeCSS

Installation

PurgeCSS can be installed as a command-line tool or integrated into your build pipeline:

# Using npm
npm install --save-dev purgecss

# Using yarn
yarn add --dev purgecss

# Using pnpm
pnpm add --save-dev purgecss

Command-Line Usage

For quick testing or simple projects, use PurgeCSS directly from the command line:

npx purgecss --content src/**/*.html src/**/*.js --css src/**/*.css --output dist/

Integration with PostCSS

PostCSS is the most common way to integrate PurgeCSS into a build pipeline:

npm install --save-dev postcss postcss-purgecss
// postcss.config.js
module.exports = {
 plugins: [
 require('postcss-import'),
 require('tailwindcss'),
 require('autoprefixer'),
 require('postcss-purgecss')({
 content: ['./src/**/*.{js,jsx,ts,tsx,html,vue}']
 }),
 ]
}

Configuration Options

Content Configuration

The content option is the most critical configuration for PurgeCSS. It determines which files are analyzed for selector usage:

module.exports = {
 content: [
 './public/**/*.html',
 './src/**/*.{js,jsx,ts,tsx}',
 './src/**/*.vue',
 './node_modules/**/*.vue'
 ]
}

Safelist

The safelist option prevents specific selectors from being removed:

module.exports = {
 safelist: {
 standard: [
 'active',
 'disabled',
 'hidden',
 /^modal-/ // Regex: matches modal-open, modal-close, etc.
 ],
 deep: [
 /:hover/,
 /:focus/
 ]
 }
}

Blocklist

The blocklist option forces removal of selectors:

module.exports = {
 blocklist: [
 '.old-component-styles',
 '.legacy-modal',
 /^ie-/ // IE-specific styles
 ]
}

Keyframes and Font-Face

Control removal of animations and fonts:

module.exports = {
 keyframes: true, // Remove unused keyframe definitions
 fontFace: true // Remove unused @font-face declarations
}

Framework-Specific Integration

Next.js

For Next.js projects, integration happens through PostCSS configuration. Both the Pages Router and App Router are supported with appropriate content patterns:

// postcss.config.js
module.exports = {
 plugins: {
 tailwindcss: {},
 autoprefixer: {},
 'postcss-purgecss': {
 content: [
 './pages/**/*.{js,ts,jsx,tsx}',
 './components/**/*.{js,ts,jsx,tsx}',
 './app/**/*.{js,ts,jsx,tsx}',
 ],
 safelist: [
 'html', 'body',
 /^hover:/,
 /^active:/,
 ]
 },
 },
}

For more on building performant Next.js applications, see our guide on implementing infinite scroll with Next.js server actions.

React (Vite/Webpack)

// postcss.config.js
module.exports = {
 plugins: [
 require('postcss-import'),
 require('postcss-purgecss')({
 content: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
 }),
 require('autoprefixer'),
 ]
}

Vue 3 with Vite

// vite.config.js
export default defineConfig({
 plugins: [
 vue(),
 purgeCss({
 content: ['./src/**/*.{vue,js,ts,jsx,tsx}'],
 safelist: { standard: [/^v-/, 'active', 'disabled'] }
 })
 ]
})

Vue projects can also benefit from our top Vue admin dashboard examples for building optimized admin interfaces.

Webpack

// webpack.config.js
module.exports = {
 plugins: [
 new PurgeCSSPlugin({
 paths: glob.sync(`${path.join(__dirname, 'src')}/**/*`, { nodir: true }),
 safelist: { standard: ['active', 'disabled'] }
 }),
 ],
}

Best Practices for Effective CSS Purging

Keep Your Content Patterns Updated

As your project grows, your content patterns need to evolve. New components, new pages, and new file types all need to be included in the content array. Regular audits of your PurgeCSS configuration prevent the tool from missing content that should be analyzed.

Be Strategic with Safelisting

Safelisting should be a conscious decision, not a workaround for detection problems:

  • Do safelist: Dynamic classes added via JavaScript
  • Do safelist: Third-party integrations
  • Consider alternative patterns for frequently safelisted classes

Test the Output

Always verify the purged CSS contains all necessary styles:

  • Check interactive states (hover, focus, active)
  • Test responsive breakpoints
  • Verify conditional content displays
  • Test dynamic content loaded after initial render

Monitor Bundle Sizes Over Time

Track your CSS bundle size as part of your development metrics. A sudden increase might indicate new unused styles creeping in. Many teams add bundle size checks to their CI pipeline to catch bloat before it reaches production.

Combine with Other Optimizations

PurgeCSS works best when combined with other CSS optimizations:

  • Minification (cssnano, css-minimizer-webpack-plugin)
  • Code splitting for page-specific CSS
  • Critical CSS extraction for above-fold content
  • Compression (gzip, brotli) for network transfer

Common Pitfalls and Solutions

Dynamic Classes

Classes added dynamically through JavaScript won't be detected:

safelist: {
 standard: ['active', 'disabled', 'hidden']
}

Alternatives:

  • Use data attributes instead of classes for dynamic state
  • Use safelist patterns with regular expressions

Third-Party CSS

When using CSS from npm packages:

content: [
 './src/**/*',
 './node_modules/some-package/**/*.css'
]

Or safelist specific classes:

safelist: {
 standard: ['from-npm-package']
}

CSS-in-JS Libraries

Libraries like styled-components generate class names at runtime. Consider:

  • Extracting critical styles separately
  • Configuring safelists for known patterns
  • Using CSS modules for better purging

Animation Issues

If animations appear broken after purging:

safelist: {
 standard: ['fadeIn', 'slideUp']
}

Safelist keyframe names and classes that use them.

Expected CSS Size Reduction

80%

Bootstrap projects

60%

Tailwind projects

40%

Custom CSS with legacy styles

Frequently Asked Questions

Optimize Your Web Performance Today

Our team specializes in building high-performance web applications with modern optimization techniques.