NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #49 most downloaded on npm
Tool for transforming styles with JS plugins
Last release 29 days ago
03 Sep 2026
Ships unpredictably
gaps range from 8 days to 9 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
13 years old
292 releases · first in 2013
Fix errors without stack trace.
Allow asynchronous plugins to change processor plugins list (by @ben-eb)
One column per quarter.
Fix for plugins packs defined by postcss.plugin.
postcss.plugin.Fix input inlined source maps with UTF-8 encoding.
- Update Promise polyfill.
Fix error message on wrong plugin format.
Fix Promise behavior on sync plugin errors.
plugin field in CssSyntaxError.plugin field in CssSyntaxError.- Speed up node.clone().
node.clone().Accepts Processor instance in postcss() constructor too.
Processor instance in postcss() constructor too.Speed up postcss.list (by @TrySound).
postcss.list (by @TrySound).Fix Promise behavior on parsing error.
Parse at-words in declaration values.
Fix Promise polyfill dependency (by @antyakushev and @silvenon)
Add Promise polyfill for node.js 0.10 and IE.
List helpers can be accessed independently var space = postcss.list.space.
var space = postcss.list.space.Show deprecated message only once.
PostCSS 4.1 brings async plugins support and messages API.
<img src="https://cloud.githubusercontent.com/assets/19343/6944712/d7303764-d89d-11e4-888f-cf3923767d4c.png" align="right" width="200" height="200" alt="Marquis Andras seal">
PostCSS 4.1 brings async plugins support and messages API.
PostCSS 4.1 allows plugins to operate asynchronously, by returning a Promise.
module.exports = postcss.plugin('postcss-read', function (opt) {
return function (css) {
return new Promise(function (resolve, reject) {
fs.readFile(opt.file, function (err, content) {
if ( err ) {
reject(err);
} else {
css.append(content);
resolve();
}
});
});
};
});
Note, that PostCSS still runs plugins one-by-one to avoid conflicts.
Result instance now has messages array for plugin communications.
Main usage of this messages API is a warnings with Result#warn() and Result#warnings() shortcuts:
var plugin = postcss.plugin('postcss-important-linter', function () {
return function (css, result) {
css.eachDecl(function (decl) {
if ( decl.important ) {
result.warn('Try to avoid !important', { node: decl });
}
});
}
});
postcss([plugin]).process(css).then(function (result) {
result.warnings().forEach(function (msg) {
console.warn(msg.toString());
});
});
With postcss-messages you can see all plugins warnings.
4.1 release contains postcss.plugin() function:
var postcss = require('postcss');
module.exports = postcss.plugin('postcss-plugin-name', function (opts) {
return function (css) {
// Process css
};
});
It creates a plugin with a standard API:
plugin.postcssPlugin //=> "postcss-plugin-name"
plugin.postcssVersion //=> "4.1.0"
postcss([ plugin ]) // with default options
postcss([ plugin({ prop: 'color' }) ]) // with options
Also node.error() now accepts plugin option:
if ( !variables[name] ) {
throw decl.error('Unknown variable ' + name, { plugin: 'postcss-vars' });
}
As PostCSS grows, it is time to take care of its ecosystem.
As first step we made the Guidelines for PostCSS runners, like gulp-postcss or postcss-cli.
The guidelines for plugin developers will be published next month. Stay tuned with @PostCSS.
Result instance to plugins as the second argument.CssSyntaxError#showSourceCode().postcss.list and postcss.vendor aliases.Processor#version.!important statement with spaces and comments inside (by @ben-eb).prop or value (by @philip-peterson).error.generated.Remove babel from released package dependencies (by @zertosh).
babel from released package dependencies (by @zertosh).Fix error message on double colon in declaration.
Fix indent detection in some rare cases.
Faster API with 6to5 Loose mode.
Do not copy IE hacks to code style.
- Add source.input to Root too.
source.input to Root too.PostCSS 4.0 brings new APIs for plugin developers.
<img src="https://cloud.githubusercontent.com/assets/19343/5578797/fab1b094-902e-11e4-9956-481dea05dabf.png" align="right" width="200" height="200" alt="Duke Flauros seal">
PostCSS 4.0 brings new APIs for plugin developers.
cloneBefore() and cloneAfter() shortcuts to clone node and insert clone before or after current one.moveTo(rule), moveBefore(node) and moveAfter(node) to remove node from current parent and append to other parent or insert before/after other node.replaceWith(other) to replace node with other node.rule.removeAll() to remove all children from rule.next(), prev() and root() to travel between nodes.replaceValues(regexp, callback) to replace some string in all declarations values.Methods eachDecl() and eachAtRule() now have optional first argument with string or regexp to filter declarations by property or at-rules by name:
css.eachDecl(/background(|-image)/, function (decl) {
inlineImage(decl);
});
css.eachAtRule('keyframes', function (atrule) {
atrule.removeSelf();
});
If CSS use wrong syntax of your plugin (for example, wrong variable name for variables plugin) now you can throw a custom syntax error with source map support:
if ( wrongName ) {
throw node.error('Wrong variable name');
}
//=> CssSyntaxError: popup.css:45:5: Bad variable syntax
// var-name: 1
// ^
Also error object is a best way to create warning:
if ( notSupported ) {
var error = node.error('This property is not supported in IE');
console.warn( error.toString() );
}
PostCSS syntax error output now contains class name to be like other node.js errors.
PostCSS 4.0 has a lot of fixes in CSS whitespaces support. For example, it will change indentation, when you move rule to other node. So plugins like postcss-nested now will return readable output.
Container#childs was renamed to nodes.PostCSS#processors was renamed to plugins.Node#source.file was moved to source.input.file.root.append({ selector: 'a' }) and root.append({ name: 'encoding', params: '"utf-8"' }).Fix IE filter parsing with multiple commands.
Fix missing semicolon when comment comes after last declaration.
Fix parser to support difficult cases with backslash escape and brackets.
CssSyntaxError#stack (by @MoOx).CssSyntaxError#stack (by Maxime Thirouin).Fix Safe Mode on unknown word before declaration.
Increase tokenizer speed (by @lahmatiy).
Fix Root#normalize in some inserts.
Root#normalize in some inserts.Typo in deprecated warning (by @MoOx).
Child nodes array is now in Container#childs property. decls and rules properties are now deprecated and will be removed in the 3.1 release.
<img src="https://cloud.githubusercontent.com/assets/19343/5574744/aea0a608-8fc8-11e4-8cb6-64a2fedc183e.png" align="right" width="200" height="200" alt="Marquis Andrealphus seal">
PostCSS 3.0 now has the fastest JavaScript-based CSS parser.
Unlike most CSS parsers, PostCSS preserves whitespace. So historically PostCSS did not have the best performance of them all. But for PostCSS 3.0 we've decided to focus on the performance issues.
map.As result, the PostCSS parser is now 6 times faster. Current benchmark on bootstrap.css (Fedora 20, node 0.10.32, i7-3517U, 8 GB RAM, SSD):
PostCSS 3: 23 ms
CSSOM: 28 ms (1.2 times slower)
Mensch: 47 ms (2.0 times slower)
Rework: 62 ms (2.7 times slower)
Stylecow: 122 ms (5.3 times slower)
PostCSS 2: 141 ms (6.1 times slower)
Gonzales PE: 162 ms (7.0 times slower)
Gonzales: 175 ms (7.5 times slower)
Old PostCSS 2 could not parse @page at-rule, because it did contain a mix of at-rules and declarations:
@page {
margin-top: 10px;
@bottom-center { ... /* page number */}
}
PostCSS 3.0 can now parse declarations, rules and at-rules inside any parent node. As a result, we can support custom at-rules with any type of content inside (declarations, rules or mix of declarations and rules):
@sprite-config {
padding: 5px;
}
Another benefit is that you now can write plugins like postcss-nested.
Container#childs property. decls and rules properties are now deprecated and will be removed in the 3.1 release.map.inline and map.sourcesContent properties are now enabled by default, since it is now the most popular way to use maps.each, insertAfter) on child array changes.from option from previous source map file field.to value to from if to option is missing.from option is missing.; is missing between declarations.PostCSS instance or list of plugins to use() method.Result instance to process() method.sourceMappingURL comment on map.annotation: false.before if Root first child got removed.Fix map generation for nodes without source (by @josiahsavary).
Fix source map with BOM marker support (by @MohammadYounes).
- Fix prepend() on empty Root.
prepend() on empty Root.Allow to use object shortcut in use() with functions like autoprefixer.
use() with functions like autoprefixer.Add shortcut to set processors in use() via object with .postcss property.
use() via object with .postcss property.Processors now receive options from process(css, opts) by @MoOx’s idea.
process(css, opts) by @MoOx’s idea.This release adds Node#replace() shortcut and uses GNU style for syntax error messages.
<img src="https://cloud.githubusercontent.com/assets/19343/5574745/c5415632-8fc8-11e4-9b0e-500925032847.png" align="right" width="200" height="200" alt="Marquis Cimeies seal">
This release adds Node#replace() shortcut and uses GNU style for syntax error messages.
@jonathanong suggested good shortcut to replace one node to another (or several other nodes). For example, you can write @import loader:
css.eachAtRule(function (rule) {
if ( rule.name != 'import' ) return;
var file = readFileFromRule(rule);
var content = fs.readFileSync(file);
var root = postcss.parse(content, { from: file });
rule.replace(root);
});
Old PostCSS’s errors was like Can't parse CSS: Unexpected { in decls at line 2:1 in a.css.
But GNU Coding Standards had good recommendations for syntax error messages. Rework, CoffeeScript and other tools already use it. Also some tools can find this format in output and they will open your text editor on this line.
PostCSS 2.2 now uses GNU style for syntax errors:
a.css:2:1 Unexpected { in decls
Also CssSyntaxError now has reason property to build your own error messages in end-user interfaces (in previous example it will be "Unexpected { in decls").
PostCSS repository was moved to postcss GitHub organiztion, which will host official plugins.
@bclinkinbeard found several rare and interesting bugs. This release fix them.
sourcesContent if there is no from and to options.Allow to miss to and from options for inline source maps.
to and from options for inline source maps.Node#source.id if file name is unknown.PostCSS 2.1 has new ES6 compiler and show syntax error source.
<img src="https://cloud.githubusercontent.com/assets/19343/5574748/d89a4d4c-8fc8-11e4-99c2-a2bca83d57d7.png" width="200" height="200" align="right" alt="King Amdusias seal">
PostCSS 2.1 has new ES6 compiler and show syntax error source.
PostCSS 2.0 used Traceur to compile ES6 sources to pure JS. Traceur is very powerful, but require to add special runtime JS file to build. Runtime was very big, had side effects and some problems in Browserify and Rhino.
New PostCSS 2.1 uses ES6 Transpiler. It hasn’t runtime, doesn’t change system classes and very small and easy to use. Also it has line-to-line input/output mapping to make debug easier.
By @jonathanong idea CSS syntax error messages now include broken source line:
> postcss.parse('a {\n b { }\n}')
Can't parse CSS: Unexpected { in decls at line 2:5
a {
b { }
^
}
PostCSS will try to detect environment and use colors in error output if they are supported.
<img src="http://postcss.github.io/postcss/logo.svg" width="80" height="80" align="right">
And now PostCSS has own logo. It is alchemist symbol of philosopher’s stone, which can process lead into gold.
PostCSS 2.0 was rewritten from CoffeeScript to ES6, contains Safe Mode and is more friendly to new developers.
<img src="https://cloud.githubusercontent.com/assets/19343/5574751/ff3977fc-8fc8-11e4-8806-6095b3da4b28.png" width="200" height="200" align="right" alt="King Belial seal">
PostCSS 2.0 was rewritten from CoffeeScript to ES6, contains Safe Mode and is more friendly to new developers.
PostCSS was written on CoffeeScript to have clean and readable code. But many developers afraid CoffeeScript, because of very different syntax.
I think, that it is very important to be able to read your framework sources. To be more friendly to developers PostCSS was rewritten to ES6.
If you use npm you will not see any changes. PostCSS releases contain only compiled pure JS from Traceur. But now you can read PostCSS sources without the knowledge of CoffeeScript syntax.
PostCSS should not fall on some legacy CSS with hacks. So we have not only unit tests, but also test all releases with real world CSS from Twitter, GitHub, Bootstrap and Habrahabr.
But this sites have good written code. PostCSS 2 are also tested with Browserhacks examples and contains few parser fixes to pass all CSS hacks from there.
PostCSS 2.0 had special Safe Mode, which try to fix broken CSS. For example, it will parse a { as a {}. It will be useful for live input tool (like Autoprefixer interactive demo) or to parse old legacy code.
postcss.parse('a {'); // will throw "Unclosed block"
postcss.parse('a {', { safe: true }); // will return CSS root for a {}
PostCSS used getter and setter for selector, value, etc properties. They confused new users, because getters was not showed, when you inspect node in console.
PostCSS 2 is more friendly to new developers and use only regular properties without any magic.
There is map: 'inline' shortcut if you want to set only map: { inline: true }. Old options are deprecated and will print warnings.
<img src="https://cloud.githubusercontent.com/assets/19343/5574753/1092042e-8fc9-11e4-9de6-990688f5e0a0.png" width="200" height="200" align="right" alt="Marquis Decarabia seal" />
This release improved source map API and allowed to use PostCSS with multiple inputs, like in file concatenation tools.
@lydell suggested great plan to clean up source map options. Now all map options will be inside map object.
inlineMap: true was renamed to map: { inline: true }.mapAnnotation: false was renamed to map: { annotation: false }.map: { prev: prevMap } instead of old map: prevMap.There is map: 'inline' shortcut if you want to set only map: { inline: true }. Old options are deprecated and will print warnings.
Also there are two API improvements for plugin’s popular needs:
map: { sourcesContent: true } option.map: { annotation: '../maps/app.css.map' } option. Note that path in annotation must be relative to output CSS file.By @dantman idea, process(css, opts) and toResult(opts) methods now return lazy result object, so CSS will not be stringified until you access to result.css or result.map properties:
var result1 = processor.process(css1);
var result2 = processor.process(css2);
// We need to concat this files, so we doesn’t need to stringify content yet
result1.root.append( result2.root );
result1.css // Now output CSS will be stringified
result1.map // Source map will be generated only now
// and will include map from result2
Also Result#map will return SourceMapGenerator object (from Mozilla’s source-map) instead of string. It will allow to change something in generated map:
var result = processor.process(css, { map: true });
result.map.applySourceMap(otherMap, 'undetected.css');
console.log('map: ' + result.map) // SourceMapGenerator has toString() method,
// so old code should work
result.map.toJSON().file // But also you can access to generated map properties
PostCSS now tracks previous source map in every node. So, when you move any node from one root to another, it will take previous map:
root1 = postcss.parse(css1, { map: { prev: prev1 } });
root2 = postcss.parse(css2, { map: { prev: prev2 } });
root1.append( root2.rules[0] );
root.toResult().map // will include prev1 and prev2 maps
Also all methods to add node (append, prepend, insertBefore, insertAfter) now accept arrays and Root node:
root1.append( root2 );
root1.append( root3.rules[1].rules );
"postcss": "ai/postcss" in your npm’s package.json.Root node now has prevMap property with information about previous map. Mostly for internal usage, but maybe you will need it.Node#source.file now contains absolute path. It is also part of work to support style concatenation, when you can generate different roots from different paths.Declaration#clone() will clean between style too to use style from new place.Allow to use Root or Result as first argument in process().
Root or Result as first argument in process().Result#root.Better space symbol detect to read UTF-8 BOM correctly.
Remove source map hacks by using new Mozilla’s source-map (by @lydell).
source-map (by @lydell).source-map (by Simon Lydell).Add URI encoding support for inline source maps.
Fix relative paths from previous source map.
Rule#selectors (by @lydell).Rule#selectors (by Simon Lydell).Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →