uncss vs purify-css
Automated CSS Purging Strategies for Production Builds
uncsspurify-cssSimilar 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
uncss66,0879,399-587 years agoMIT
purify-css19,1499,845-809 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: uncss vs purify-css

  • 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.

  • 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.

README for uncss

UnCSS

NPM version Linux Build Status Windows Build status Coverage Status dependencies Status devDependencies Status

UnCSS is a tool that removes unused CSS from your stylesheets. It works across multiple files and supports Javascript-injected CSS.

How

The process by which UnCSS removes the unused rules is as follows:

  1. The HTML files are loaded by jsdom and JavaScript is executed.
  2. All the stylesheets are parsed by PostCSS.
  3. document.querySelector filters out selectors that are not found in the HTML files.
  4. The remaining rules are converted back to CSS.

Please note:

  • UnCSS cannot be run on non-HTML pages, such as templates or PHP files. If you need to run UnCSS against your templates, you should probably generate example HTML pages from your templates, and run uncss on those generated files; or run a live local dev server, and point uncss at that.
  • UnCSS only runs the Javascript that is run on page load. It does not (and cannot) handle Javascript that runs on user interactions like button clicks. You must use the ignore option to preserve classes that are added by Javascript on user interaction.

Installation

npm install -g uncss

Usage

Online Server

Within Node.js

var uncss = require('uncss');

var files   = ['my', 'array', 'of', 'HTML', 'files', 'or', 'http://urls.com'],
    options = {
        banner       : false,
        csspath      : '../public/css/',
        htmlroot     : 'public',
        ignore       : ['#added_at_runtime', /test\-[0-9]+/],
        ignoreSheets : [/fonts.googleapis/],
        inject       : function(window) { window.document.querySelector('html').classList.add('no-csscalc', 'csscalc'); },
        jsdom        : {
            userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)',
        },
        media        : ['(min-width: 700px) handheld and (orientation: landscape)'],
        raw          : 'h1 { color: green }',
        report       : false,
        strictSSL    : true,
        stylesheets  : ['lib/bootstrap/dist/css/bootstrap.css', 'src/public/css/main.css'],
        timeout      : 1000,
        uncssrc      : '.uncssrc',
        userAgent    : 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)',
    };

uncss(files, options, function (error, output) {
    console.log(output);
});

/* Look Ma, no options! */
uncss(files, function (error, output) {
    console.log(output);
});

/* Specifying raw HTML */
var rawHtml = '...';

uncss(rawHtml, options, function (error, output) {
    console.log(output);
});

At build-time

UnCSS can also be used in conjunction with other JavaScript build systems, such as Grunt, Broccoli or Gulp!

From the command line

Usage: uncss [options] <file or URL, ...>
    e.g. uncss https://getbootstrap.com/docs/3.3/examples/jumbotron/ > stylesheet.css

Options:

  -h, --help                            output usage information
  -V, --version                         output the version number
  -i, --ignore <selector, ...>          Do not remove given selectors
  -m, --media <media_query, ...>        Process additional media queries
  -C, --csspath <path>                  Relative path where the CSS files are located
  -s, --stylesheets <file, ...>         Specify additional stylesheets to process
  -S, --ignoreSheets <selector, ...>    Do not include specified stylesheets
  -r, --raw <string>                    Pass in a raw string of CSS
  -t, --timeout <milliseconds>          Wait for JS evaluation
  -H, --htmlroot <folder>               Absolute paths' root location
  -u, --uncssrc <file>                  Load these options from <file>
  -n, --noBanner                        Disable banner
  -a, --userAgent <string>              Use a custom user agent string
  -I, --inject <file>                   Path to javascript file to be executed before uncss runs
  -o, --output <file>                   Path to write resulting CSS to

Note that you can pass both local file paths (which are processed by glob) and URLs to the program.

  • banner (boolean, default: true): Whether a banner should be prepended before each file block in the processed CSS.

  • csspath (string): Path where the CSS files are related to the HTML files. By default, UnCSS uses the path specified in the <link rel="stylesheet" href="path/to/file.css"/>.

  • htmlroot (string): Where the project root is. Useful for example if you have HTML that references local files with root-relative URLs, i.e. href="/css/style.css".

  • ignore (string[]): provide a list of selectors that should not be removed by UnCSS. For example, styles added by user interaction with the page (hover, click), since those are not detectable by UnCSS yet. Both literal names and regex patterns are recognized. Otherwise, you can add a comment before specific selectors:

    /* uncss:ignore */
    .selector1 {
        /* this rule will be ignored */
    }
    
    .selector2 {
        /* this will NOT be ignored */
    }
    
    /* uncss:ignore start */
    
    /* all rules in here will be ignored */
    
    /* uncss:ignore end */
    
  • ignoreSheets (string[] | RegExp[]): Do not process these stylesheets, e.g. Google fonts. Accepts strings or regex patterns.

  • inject (string / function(window)): Path to a local javascript file which is executed before uncss runs. A function can also be passed directly in.

    Example inject.js file

    'use strict';
    
    module.exports = function(window) {
        window.document.querySelector('html').classList.add('no-csscalc', 'csscalc');
    };
    

    Example of passing inject as a function

    {
      inject: function(window){
        window.document.querySelector('html').classList.add('no-csscalc', 'csscalc');
      }
    }
    
  • jsdom (object) (Supported only by API): Supply the options used to create the JSDOM pages (https://github.com/jsdom/jsdom). At the moment, config.resources is not yet supported.

  • media (string[]): By default UnCSS processes only stylesheets with media query _all_, _screen_, and those without one. Specify here which others to include.

  • raw (string): Give the task a raw string of CSS in addition to the existing stylesheet options; useful in scripting when your CSS hasn't yet been written to disk.

  • report (boolean, default: true): Return the report object in callback.

  • strictSSL (boolean, default: true): Disable SSL verification when retrieving html source

  • stylesheets (string[]): Use these stylesheets instead of those extracted from the HTML files. Prepend paths with the file:// protocol to force use of local stylesheets, otherwise paths will be resolved as a browser would for an anchor tag href on the HTML page.

  • timeout (number): Specify how long to wait for the JS to be loaded.

  • uncssrc (string): Load all options from a JSON file. Regular expressions for the ignore and ignoreSheets options should be wrapped in quotation marks.

    Example uncssrc file:

    {
        "ignore": [
            ".unused",
            "/^#js/"
        ],
        "stylesheets": [
            "css/override.css"
        ]
    }
    
  • userAgent (String, default: 'uncss'): The user agent string that jsdom should send when requesting pages. May be useful when loading markup from services which use user agent based device detection to serve custom markup to mobile devices. Defaults to uncss.

As a PostCSS Plugin

UnCSS can be used as a PostCSS Plugin.

postcss([ require('uncss').postcssPlugin ]);

See PostCSS docs for examples for your environment.

Note: Depending on your environment, you might not be able to use uncss as a PostCSS plugin since the plugin is not directly exported. In such cases, use the wrapper library postcss-uncss.

Options

  • html (string[]): provide a list of html files to parse for selectors and elements. Usage of globs is allowed.

  • ignore (string[] | RegExp[]): provide a list of selectors that should not be removed by UnCSS. For example, styles added by user interaction with the page (hover, click), since those are not detectable by UnCSS yet. Both literal names and regex patterns are recognized. Otherwise, you can add a comment before specific selectors in your CSS:

    /* uncss:ignore */
    .selector1 {
        /* this rule will be ignored */
    }
    
    .selector2 {
        /* this will NOT be ignored */
    }
    
Example Configuration
{
  html: ['index.html', 'about.html', 'team/*.html'],
  ignore: ['.fade']
}

License

Copyright (c) 2019 Giacomo Martino. See the LICENSE file for license rights and limitations (MIT).