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 purify from "purify-css"
const purify = 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.
button-active
Detecting the use of: <!-- 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.
button-active
Detecting the use of: // 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; }
glob file patterns + writing to a file
Example withvar 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);
glob file patterns and source strings + minify + logging rejected selectors
Example with bothvar 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);
content
argument
The Array
or String
Type: 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.
css
argument
The Array
or String
Type: Array
of glob file patterns to the CSS files you want to filter.
String
of CSS to purify.
options
argument
The (optional) Object
Type: Properties of options object:
-
minify:
Set totrue
to minify. Default:false
. -
output:
Filepath to write purified CSS to. Returns raw string iffalse
. Default:false
. -
info:
Logs info on how much CSS was removed iftrue
. Default:false
. -
rejected:
Logs the CSS rules that were removed iftrue
. Default:false
. -
whitelist
Array of selectors to always leave in. Ex.['button-active', '*modal*']
this will leave any selector that includesmodal
in it and selectors that matchbutton-active
. (wrapping the string with *'s, leaves all selectors that include it)
callback
argument
The (optional) Function
Type: 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.
Builds broken -- Uglifyjs & new release
Hi,
Sorry for opening an issue. Didn't know any other way to contact you. I am the owner of Quasar Framework and I depend on this package on Quasar starter kit. Due to the deprecation with error on Uglifyjs devs cannot build anymore.
But I saw this commit https://github.com/purifycss/purifycss/commit/108142998959b1812365e69c6229e0c0284adedc and was wondering when an npm release with this change will be available so I can take a decision: either remove purifycss from the build or wait for the npm release.
Thank you and sorry for opening a github issue for this (but times are hard), Razvan
Adding options.strict to allow more aggressive removal of unused selectors
Support for calculated class names is nice, but it can allow unused classes to remain. When options.strict is set to true, selectors will be matched fully against full words including '_'. '-', and numbers.
breaking change?
I am using grunt-purifycss which of course has never changed. However, a few days ago the version of purifycss used with it was 1.0.21 and is now 1.1.3. Somewhere in in between purifycss is now removing styles that are actually used. Are you aware of any breaking changes or something I need to do differently with the latest release? Thanks. Here is an example of something that was removed:
1.1.0
The API will stay exactly the same. Rework is much simpler and will allow for more precise selector elimination + leaving the order of the CSS files the same (currently, it orders the CSS files into selectors/at-rules)
The following issues should be fixed once this is merged in: #91 #85 #53
Going to be adding stronger tests before I merge this in for v1.1.0-beta
Tool removes @font-face declarations :(
Is there a way to prevent that? For everything else works great just my @font-face declarations are stripped away from the end-result :(
Maybe a way to filter them?
Thanks a lot
AngularJS classes that aren't used immediately get removed
I understand that this could be a doozie to solve, but AngularJS does not add classes to certain elements until they are required to be animated, which is when it adds a whole bunch of classes (.ng-animate, .ng-enter, etc.). These get removed when the CSS gets purified.
Also, angular doesn't add elements to the DOM that have an ng-if directive until a certain condition is met.
Perhaps there can be some type of whitelist of classes to never remove from a source css document?
Just a thought...
Please publish 1.2.6 to NPM (currently: 1.1.9)
Hello! In trying to install purifycss I realized part of the issues I was encountering were because it's stuck at version 1.1.9, depending on the deprecated
uglifyjs
(without the dash), etc. Could you please publish your latest release? Thank you!Pseudo elements not removed - fix not implemented
Hi. I have noticed that many css selectors are not removed, including css using pseudo selectors (such as
.glyphicon-asterisk:before {...}
), although a fix does exist.Some info...
npm install purify-css
- version 1.0.17. This does not remove pseudo selectors.src/sccTree.js
with this fix: https://github.com/purifycss/purifycss/blob/f45537378a8c236bd4ddca5f89d762b3e627ce23/src/cssTree.js and pseudo selectors are now removed successfully. Can this be worked back into the master and can the npm installer make use of this latest version?.progress-bar
. Anybody else had this?Thanks
Option for removing css comments
I ran my code through purifycss, and it gave impressive results. However, I noticed that the css comments contained in the original files were preserved. Is there an option for removing these?
SyntaxError when purifying with Django templates
In the upgrade from 1.2.2 -> 1.2.3 I started getting the following errors:
when attempting to purify html files that are django templates.
The templates look like this:
You can see the error in action by running
gulp
in this project: https://github.com/lopopolo/hyperbola (you might have to muck with deps)Using prepack for js file
Purifycss is relatively simple to understand. It takes a content file, like an html file and extract all the words from it. It takes a css file and extracts all the selectors from it. Then, it compares the two.
But this approach causes some issues for more complex situation:
In the above example, purifycss will extract the following strings from the js:
That means that abcdefg is not considered used since it will not match with the array of strings that we extracted from the js.
Prepack will transform the js before extracting strings from it.
Invalid CSS output if css has ";" symbol in imported URL
I have Google Fonts on my CSS:
@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,[email protected],500;1,500&family=Oswald:[email protected];500&family=Rambla:[email protected];700&display=swap');
But output CSS converts it to:@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,[email protected],500;
As the result output CSS file is corrupted and the browser is not processing it.
Need to ignore when ";" symbol is using in the string.
undefined (at undefined:undefined): "undefined" while purifying
I get this error(undefined (at undefined:undefined): "undefined" while purifying) everytime i try to check my wordpress site css on https://purifycss.online/. What is the problem?
purifycss not working on php exec
` $purifyCSS = "purifycss %s %s --info --out %s";
$match = "/usr/share/nginx/example/media/css_html/main.html";
$input = "/usr/share/nginx/example/media/css_html/input.css";
$output = "/usr/share/nginx/example/media/css_html/ouput.css";
exec(sprintf($purifyCSS , $input , $match, $output),$result);`