purify-css vs uncss
Automated CSS Purging Strategies for Production Builds
purify-cssuncssSimilar Packages:

Automated CSS Purging Strategies for Production Builds

purify-css and uncss are both utilities designed to reduce final CSS bundle sizes by analyzing source code (HTML, JavaScript, templates) and removing unused selectors from stylesheet files. purify-css operates by scanning content files for class names and IDs, then filtering the CSS based on these matches. It is known for its flexibility with custom content extractors and broad template engine support. uncss, historically a pioneer in this space, uses a headless browser (PhantomJS) to render pages and determine which styles are actually applied in the DOM. This allows it to handle dynamic class additions and complex selectors more accurately than static analysis, but introduces heavier runtime dependencies and configuration complexity.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
purify-css09,852-819 years agoMIT
uncss09,403-587 years agoMIT

Purify-CSS vs UnCSS: Technical Comparison for Legacy and Modern Stacks

Both purify-css and uncss solve the same critical problem: removing unused CSS to shrink bundle sizes and improve load times. However, they take fundamentally different approaches to detecting what is "unused," leading to distinct trade-offs in accuracy, performance, and maintenance. Understanding these differences is vital when dealing with legacy systems or deciding whether to migrate to modern alternatives.

🔍 Detection Strategy: Static Parsing vs. Headless Rendering

The core difference lies in how each tool decides which CSS rules to keep.

purify-css uses static analysis. It reads your source files (HTML, JS, templates) as text, extracts strings that look like class names or IDs using regular expressions, and compares them against your CSS selectors.

// purify-css: Static analysis configuration
const purify = require('purify-css');

purify(['src/**/*.html', 'src/**/*.js'], ['src/**/*.css'], {
  output: 'dist/clean.css',
  // It simply looks for strings matching class patterns
  minify: true
});

uncss uses dynamic rendering. It spins up a headless browser (historically PhantomJS) to actually load your pages, execute JavaScript, and render the DOM. It then snapshots the computed styles to see what is truly being used.

// uncss: Dynamic rendering configuration
const uncss = require('uncss');

uncss(['http://localhost:8080/index.html'], {
  css: ['src/styles.css'],
  // It loads the URL in a browser to find used styles
  ignore: ['.js-added-class'] 
}, function(error, output) {
  console.log(output);
});

⚡ Performance and Dependencies

Because of their detection strategies, the runtime requirements differ significantly.

purify-css is extremely fast and lightweight. It runs purely in Node.js with no external binaries. You can run it on any CI/CD server without extra setup.

# purify-css: Runs instantly in any Node environment
npm install purify-css
# No additional system dependencies required

uncss is heavy and slow. It requires a headless browser engine. Historically, it depended on PhantomJS, which is now obsolete. Running it often requires installing system-level libraries for browser rendering, making CI/CD setup cumbersome.

# uncss: Requires heavy system dependencies
npm install uncss
# Historically required PhantomJS installation on the OS
# This often fails on modern minimal Docker images or CI runners

🎯 Accuracy with Dynamic Content

Static analysis often struggles with dynamic classes, while rendering engines handle them naturally.

purify-css can miss classes added by JavaScript at runtime if they aren't present as strings in the source code. You often need to manually whitelist these patterns.

// purify-css: May miss dynamic classes unless whitelisted
purify(files, css, {
  output: 'clean.css',
  // Must manually tell it to keep classes matching this pattern
  whitelist: ['.is-active', '/^js-/' ] 
});

uncss naturally catches dynamic classes because it executes the JavaScript on the page. If a script adds a class after load, uncss sees it in the DOM and keeps the CSS.

// uncss: Automatically detects runtime classes
// No whitelist needed for classes added by JS execution
uncss(urls, options, function(err, output) {
  // The output includes styles for classes added via DOM manipulation
});

🛑 Maintenance Status and Deprecation Warning

This is the most critical factor for architectural decisions today.

purify-css is no longer actively maintained. The original repository has seen little activity in recent years. While it still works for many setups, it lacks support for modern CSS features and newer framework patterns. Developers are strongly encouraged to migrate to purgecss, which is the spiritual successor with active maintenance and a plugin ecosystem.

// purify-css: Deprecated/Inactive
// Recommendation: Migrate to 'purgecss'
// const purgecss = require('purgecss'); // Active alternative

uncss is officially deprecated. The project is archived, and its dependency on PhantomJS (which is also dead) makes it incompatible with modern security standards and build environments. It should not be used in any new project.

// uncss: Deprecated and Archived
// DO NOT USE in new projects.
// The underlying PhantomJS engine is insecure and obsolete.
// Modern alternative: Use PurgeCSS with a custom extractor or critical CSS tools.

🏗️ Integration with Build Tools

Both tools offered plugins for popular loaders, but support varies.

purify-css had simple webpack plugins but required manual configuration for many frameworks.

// purify-css: Webpack plugin example (Legacy)
const PurifyCSSPlugin = require('purify-css-webpack');

module.exports = {
  plugins: [
    new PurifyCSSPlugin({
      paths: glob.sync(path.join(__dirname, 'app/*.js'))
    })
  ]
};

uncss integrated deeply with task runners like Gulp, often as part of a larger pipeline involving server spinning.

// uncss: Gulp task example (Legacy)
const gulp = require('gulp');
const uncss = require('gulp-uncss');

gulp.task('css', function () {
  return gulp.src('src/**/*.css')
    .pipe(uncss({
      html: ['http://localhost:3000']
    }))
    .pipe(gulp.dest('dist'));
});

📊 Summary: Key Differences

Featurepurify-cssuncss
MethodStatic Text AnalysisHeadless Browser Rendering
SpeedVery FastSlow (Browser startup time)
Dynamic ClassesMisses them (needs whitelist)Detects them automatically
DependenciesNone (Pure Node)Heavy (PhantomJS/Browser)
StatusInactive / UnmaintainedDeprecated / Archived
Best ForLegacy static sites (temporary)None (Obsolete)

💡 The Big Picture

purify-css was a reliable workhorse for simple, static projects where build speed mattered more than 100% accuracy. However, its lack of maintenance makes it a risk for modern stacks. If you are currently using it, plan a migration to purgecss, which offers the same static analysis benefits with active support and better framework integration.

uncss was a powerful tool for complex applications where JavaScript heavily manipulated the DOM. Its ability to "see" the rendered page was unique. However, the death of PhantomJS and the project itself means it is now a liability. Using it today introduces security vulnerabilities and build instability.

Final Recommendation: Do not start new projects with either of these packages. The industry has standardized around purgecss. It combines the speed of static analysis with the ability to write custom extractors for dynamic frameworks (like React, Vue, and Angular), effectively replacing the need for heavy headless browsers while maintaining high accuracy. Use purify-css or uncss only when maintaining older legacy builds that cannot yet be refactored.

How to Choose: purify-css vs uncss

  • purify-css:

    Choose purify-css if you need a lightweight, static analysis tool that integrates easily into build pipelines without requiring a browser environment. It is ideal for projects using standard template engines (Handlebars, Pug) or frameworks where class names are explicitly written in the source files. However, be aware that this package is no longer actively maintained, so you should evaluate modern forks like purgecss for long-term projects requiring security updates and framework-specific plugins.

  • uncss:

    Choose uncss only if you are maintaining a legacy build pipeline that specifically relies on its headless browser rendering to catch dynamically applied styles that static analyzers miss. For all new projects, do not choose this package; it is officially deprecated and unmaintained, relying on obsolete technologies like PhantomJS. Modern alternatives offer better performance, active support, and safer execution environments without the need for a full browser instance.

README for purify-css

PurifyCSS

Travis npm David Join the chat at https://gitter.im/purifycss/purifycss

A function that takes content (HTML/JS/PHP/etc) and CSS, and returns only the used CSS.
PurifyCSS does not modify the original CSS files. You can write to a new file, like minification.
If your application is using a CSS framework, this is especially useful as many selectors are often unused.

Potential reduction

  • Bootstrap file: ~140k
  • App using ~40% of selectors.
  • Minified: ~117k
  • Purified + Minified: ~35k

Usage

Standalone

Installation

npm i -D purify-css
import purifycss from "purify-css"
const purifycss = require("purify-css")

let content = ""
let css = ""
let options = {
    output: "filepath/output.css"
}
purify(content, css, options)

Build Time

CLI Usage

$ npm install -g purify-css
$ purifycss -h

purifycss <css> <content> [option]

Options:
  -m, --min        Minify CSS                         [boolean] [default: false]
  -o, --out        Filepath to write purified css to                    [string]
  -i, --info       Logs info on how much css was removed
                                                      [boolean] [default: false]
  -r, --rejected   Logs the CSS rules that were removed
                                                      [boolean] [default: false]
  -w, --whitelist  List of classes that should not be removed
                                                           [array] [default: []]
  -h, --help       Show help                                           [boolean]
  -v, --version    Show version number                                 [boolean]

How it works

Used selector detection

Statically analyzes your code to pick up which selectors are used.
But will it catch all of the cases?

Let's start off simple.

Detecting the use of: button-active

  <!-- html -->
  <!-- class directly on element -->
  <div class="button-active">click</div>
  // javascript
  // Anytime your class name is together in your files, it will find it.
  $(button).addClass('button-active');

Now let's get crazy.

Detecting the use of: button-active

  // Can detect if class is split.
  var half = 'button-';
  $(button).addClass(half + 'active');

  // Can detect if class is joined.
  var dynamicClass = ['button', 'active'].join('-');
  $(button).addClass(dynamicClass);

  // Can detect various more ways, including all Javascript frameworks.
  // A React example.
  var classes = classNames({
    'button-active': this.state.buttonActive
  });

  return (
    <button className={classes}>Submit</button>;
  );

Examples

Example with source strings
var content = '<button class="button-active"> Login </button>';
var css = '.button-active { color: green; }   .unused-class { display: block; }';

console.log(purify(content, css));

logs out:

.button-active { color: green; }
Example with glob file patterns + writing to a file
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = ['**/src/css/*.css'];

var options = {
  // Will write purified CSS to this file.
  output: './dist/purified.css'
};

purify(content, css, options);
Example with both glob file patterns and source strings + minify + logging rejected selectors
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = '.button-active { color: green; } .unused-class { display: block; }';

var options = {
  output: './dist/purified.css',

  // Will minify CSS code in addition to purify.
  minify: true,

  // Logs out removed selectors.
  rejected: true
};

purify(content, css, options);

logs out:

.unused-class
Example with callback
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = ['**/src/css/*.css'];

purify(content, css, function (purifiedResult) {
  console.log(purifiedResult);
});
Example with callback + options
var content = ['**/src/js/*.js', '**/src/html/*.html'];
var css = ['**/src/css/*.css'];

var options = {
  minify: true
};

purify(content, css, options, function (purifiedAndMinifiedResult) {
  console.log(purifiedAndMinifiedResult);
});

API in depth

// Four possible arguments.
purify(content, css, options, callback);
The content argument
Type: Array or String

Array of glob file patterns to the files to search through for used classes (HTML, JS, PHP, ERB, Templates, anything that uses CSS selectors).

String of content to look at for used classes.


The css argument
Type: Array or String

Array of glob file patterns to the CSS files you want to filter.

String of CSS to purify.


The (optional) options argument
Type: Object
Properties of options object:
  • minify: Set to true to minify. Default: false.

  • output: Filepath to write purified CSS to. Returns raw string if false. Default: false.

  • info: Logs info on how much CSS was removed if true. Default: false.

  • rejected: Logs the CSS rules that were removed if true. Default: false.

  • whitelist Array of selectors to always leave in. Ex. ['button-active', '*modal*'] this will leave any selector that includes modal in it and selectors that match button-active. (wrapping the string with *'s, leaves all selectors that include it)

The (optional) callback argument
Type: Function

A function that will receive the purified CSS as it's argument.

Example of callback use
purify(content, css, options, function(purifiedCSS){
  console.log(purifiedCSS, ' is the result of purify');
});
Example of callback without options
purify(content, css, function(purifiedCSS){
  console.log('callback without options and received', purifiedCSS);
});
Example CLI Usage
$ purifycss src/css/main.css src/css/bootstrap.css src/js/main.js --min --info --out src/dist/index.css

This will concat both main.css and bootstrap.css and purify it by looking at what CSS selectors were used inside of main.js. It will then write the result to dist/index.css

The --min flag minifies the result.

The --info flag will print this to stdout:

    ________________________________________________
    |
    |   PurifyCSS has reduced the file size by ~ 33.8%
    |
    ________________________________________________

The CLI currently does not support file patterns.