Develoger
19 Dec 2022
•
3 min read
I bet that when you think about PostCSS you must think of this...
Yet the truth is that PostCSS is around for almost as long as React!
The widest spread application of PostCSS usage is through seamless integration of Autoprefixer (Just one of many PostCSS plugins. Not lib on its own.)
display: flex;
// becomes
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
Writing such logic outside of more traditional SASS / LESS mixins and automatically making it part of your app build is just genius.
This sure seems awesome and is the main reason why this particular plugin has 11,103,982 downloads per month on NPM
It’s obvious that industry needs a concept which PostCSS introduced.
The single PostCSS plugin has more downloads than the most popular JavaScript frameworks / libraries… Check it out on NPM trends.
PostCSS is not coupled with any specific framework / library. It’s a Front-End tool.
## Babel for CSS
With plugins or better say set of plugins PostCSS can be used in the same way we use Babel in JavaScript.
CSSnext is set of plugins which among other awesome stuff can transform CSS custom properties into what browsers can interpret today.
Alternative to CSSnext (possibly better maintained) is postcss-preset-env…
:root {
--fontSize: 1rem;
}
h1 {
font-size: var(--fontSize);
}
This will obviously fail to work in most browsers but with PostCSS it will be transformed into.
h1 {
font-size: 1rem;
}
PostCSS is "just" a parser for CSS. This means that with its API one can do anything possible.
Stylelint is PostCSS based! Check this awesome CSS linter here.
## How PostCSS?
Weirdly enough the PostCSS is not about the CSS it’s about what JavaScript can do with your CSS.
With that being said, let’s do a simple transform of single display: flex to multiple browser-specific definitions.
// require the postcss for our plugin to work
const postcss = require('postcss');
// export the plugin
module.exports = postcss.plugin('postcss-flex', (opts) => {
opts = opts || {};
return (css) => {
// define the new values
const values = [
'-webkit-box',
'-webkit-flex',
'-ms-flexbox',
];
// iterate through declarations
css.walkDecls('display', decl => {
// ignore everything else other than flex
if (decl.value !== 'flex') return;
// map values to actual string
const newDecls = values.map((value) => {
return ` display: ${value}`;
}).join(';');
// add new declarations before the current
decl.before(newDecls);
});
};
});
Essentially PostCSS takes your CSS (or SASS / LESS) source as input, gives you the possibility to alter it and outputs the end result. Simple as that.
For more details regarding PostCSS API please go here. But beware that docs are automatically generated from JSdoc (If anyone ever ask you why you should use JSdocs, just show him/her PostCSS API docs). Even though they are insightful, IMHO it would be better if they were written manually.
If your theme support requires different palette set for each theme. Together with possibly some other variables which needs to be adjusted eg. font-sizes or border-radius or … One of the easiest (possibly best) ways to achieve this would be to separate mapping of the variables eg. colors, border-radius … in the theme files.
For this scenario, we can @import just the default theme file and replace the import to theme specific file during the build, via PostCSS. As result of this, we can build theme specific CSS bundles easily and never put any references to it in our SASS codebase.
@import './variables';
.button--color-primary {
background-color: $primary;
}
Where variables.scss have such mapping.
@import '~styles/colors/colors';
$primary: $green;
Theme specific variables.blue.scss have different mapping.
@import '~styles/colors/colors';
$primary: $blue;
SASS itself does not support dynamic imports (imports with variables in their path). Issue# 279 on Github of SASS So doing this is practically not possible if you use SASS. At least without PostCSS…
This small plugin is just one example of creative usage of PostCSS. How does it work?
/*
example of options
const opts = {
originalValue: './variables',
targetValue: './variables.blue'
};
*/
css.walkAtRules((node) => {
const isImport = (node.name === 'import');
const isOriginalValue = node.params.includes(opts.originalValue);
if (isImport && isOriginalValue) {
node.params = `"${opts.targetValue}";`;
}
});
```## Fun Fact
**Autoprefixer** will eventually become obsolete...
<br></br>
![1_JOMdbTUH7C1BJ9HdV5XM2Q.png](https://functionalworks\-backend\-\-prod.s3.amazonaws.com/logos/a7f02c7d72656389dc4b08926839b8d6)
*[Source](https://github.com/postcss/autoprefixer/blob/master/lib/autoprefixer.js#L25)*
Feel free to follow Develoger on twitter [@Develoger](https://twitter.com/develoger) and check out his other blogs [here](https://develoger.com/)
Interested in Front End Development jobs, [check out the jobs board!](https://javascript.works-hub.com/jobs/)
<br></br>
Develoger
See other articles by Develoger
Ground Floor, Verse Building, 18 Brunswick Place, London, N1 6DZ
108 E 16th Street, New York, NY 10003
Join over 111,000 others and get access to exclusive content, job opportunities and more!