Introduction to PostCSS and Developing Custom Plugins
This article introduces PostCSS, explains its role in transforming CSS via JavaScript plugins, demonstrates how to integrate it with tools like Webpack and its JavaScript API, and provides a step‑by‑step guide for creating a simple PostCSS plugin that doubles pixel values, including handling of Less syntax.
Getting Started with PostCSS
CSS is a core part of web development, but browser compatibility issues have led to preprocessors such as Sass, Less, and Stylus. PostCSS is defined as a tool for transforming CSS with JavaScript; it parses CSS into an abstract syntax tree (AST) and lets plugins manipulate that tree before converting it back to plain CSS.
What PostCSS Can Do
There are over 200 PostCSS plugins. Some popular ones include:
autoprefixer – adds vendor prefixes based on caniuse data.
postcss-preset-env – enables the latest CSS features while maintaining compatibility.
postcss-modules – provides scoped class names.
precss – adds Sass‑like syntax (variables, nesting, mixins).
stylelint – lints CSS for syntax errors.
More plugins can be found at the official list .
Using PostCSS with Build Tools
PostCSS can be combined with bundlers such as Webpack, Gulp, Grunt, or Rollup. Below is a minimal Webpack configuration that loads PostCSS:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{ loader: 'style-loader', options: { importLoaders: 1 } },
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }
]
}
]
}
};PostCSS JavaScript API
const autoprefixer = require('autoprefixer');
const postcss = require('postcss');
const precss = require('precss');
const css = `
.test {
color: #fff;
}`;
postcss([precss, autoprefixer])
.process(css, { from: 'src/app.css', to: 'dest/app.css' })
.then(result => {
console.log(result.css);
});Building a PostCSS Plugin from Scratch
Understanding the AST
Before writing a plugin, you need to understand the AST that PostCSS generates. For example, the CSS rule body { margin: 0; } is represented as a JSON object with a root node containing a rule node, which in turn contains a declaration node for the margin property.
Key AST node types are root , rule , decl , atrule , and comment . Traversal methods include .walk() , .walkAtRules() , .walkRules() , and .walkComments() . See the PostCSS API documentation for details.
Creating a Simple Plugin
The following plugin doubles every pixel value found in declarations:
const postcss = require('postcss');
const postcssPluginParseMargin = postcss.plugin('postcss-parse-margin', function () {
return function (root) {
root.walkDecls(function (decl) {
decl.value = decl.value.replace(/(\d*\.?\d+)\s*px/, function (match, numStr) {
return Number(numStr) * 2 + 'px';
});
});
};
});
const css = `
.test {
font-size: 2.5px;
}
`;
postcss([postcssPluginParseMargin])
.process(css)
.then(res => {
console.log(res.css);
});This plugin uses root.walkDecls to iterate over all declaration nodes, replaces pixel values with their doubled equivalents, and outputs the transformed CSS.
Real‑World Problem: Using PostCSS to Process Less Syntax
Less is a CSS preprocessor with features like variables and mixins. To process Less with PostCSS without a double‑parse step, you can use postcss-less-engine , which converts a Less AST directly into a PostCSS AST. The original engine is outdated for Less 3.x, but a fork postcss-less-engine-latest works with newer versions.
const postcss = require('postcss');
const postCssLessEngine = require('postcss-less-engine');
const css = `
@color: red;
.test { color: @color; }
`;
postcss([postCssLessEngine()])
.process(css, { parser: postCssLessEngine.parser })
.then(result => {
console.log(result.css);
});If you only need partial Less support, you can write a custom PostCSS plugin that recognizes Less constructs (using postcss-less for parsing) and then transforms them as needed.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.