Exploring New Possibilities with
PostCSS
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1950926/pasted-from-clipboard.png)
David Clark - @davidtheclark
Every frontend developer should learn about PostCSS
(°ロ°)☝
Questions this talk should answer:
- What is PostCSS, really?
- Why is PostCSS important?
- What kinds of tools are people building with PostCSS?
Feelings this talk should foster:
- Curiosity
- Excitement
- Eagerness
- Compulsion
Does all the PostCSS hype annoy you?
(ง •̀_•́)ง
"Sass is enough ..."
"It's probably just an unnecessary toy ..."
CSS presents problems: PostCSS helps us solve them. That's not unnecessary.
Sass presents one kind of answer to one subset of CSS problems. That's not enough.
(ง •̀_•́)ง
(ง •̀_•́)ง
PostCSS is important enough to be worth it.
It can change the way you work with CSS.
(ง •̀_•́)ง
"But I'm so tired of learning ..."
What is PostCSS?
PostCSS is ...
➽ A tool for making CSS tools with JS
ᕙ༼ຈل͜ຈ༽ᕗ
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/2025042/Steam_engine_diagram_1908.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/2029694/Hammer2.jpg)
Want to build a CSS tool?
You'll probably need to ...
- parse CSS
- perform transforms
- create sourcemaps (ಥ_ಥ)
- handle pre-existing sourcemaps
- register errors and warnings with source positions
- give up and do something else ¯\(°_o)/¯
POSTCSS HANDLES ALL THESE THINGS!
YOU FOCUS ON YOUR PROBLEM!
- parse CSS
- perform transforms
- create sourcemaps (◕‿◕)
- handle pre-existing sourcemaps
- register errors and warnings with source positions
give up and do something else ¯\(°_o)/¯
A simple (hypothetical) problem: CSS adds a size property not yet supported by browsers.
/* before */
.foo {
size: 20px 10px;
}
/* after */
.foo {
width: 20px;
height: 10px;
}
- size in other properties: background-size, font-size, &c.?
- size in values: keyframe animation name, function name, &c.?
- size with whitespace(s) before the colon?
- size in selectors ... maybe even followed by a colon, e.g. .heading-full-size:first-child?
- size: 20px 10px in comments?
- Generate a sourcemap?
- Modify an existing sourcemap?
- Inform the user of syntax errors, providing line and column positions in the original source?
\_(o_0)_/
Use a regular expression to find size?
??
\_(o_0)_/
A simple (hypothetical) problem: CSS adds a size property not yet supported by browsers.
➽ Solution: use PostCSS.
... and all those problems are solved for you.
A simple (hypothetical) problem: CSS adds a size property not yet supported by browsers.
(this exists: postcss-size)
/* Walk all declaration nodes with size properties */
css.walkDecls(function (declaration) {
if (declaration.prop !== 'size') return;
var sizes = postcss.list.space(declaration.value);
var width = sizes[0]
var height = sizes[1] || sizes[0];
/* Create new nodes */
declaration.cloneBefore({
prop: 'width',
value: width
});
declaration.cloneBefore({
prop: 'height',
value: height
});
/* Remove the size node */
declaration.remove();
});
(adapted from postcss-size)
Rough overview of how PostCSS works ...
source stylesheet
tree of nodes
plugins
CSS
Parse
/* Root */
.foo { /* Rule */
color: pink; /* Declaration */
}
/* AtRule */
@media (min-width: 10px) {
.foo { color: orange; }
}
Learn terminology at http://apps.workflower.fi/vocabs/css/en
Parse
- AtRule
- name, e.g. media
- params, e.g. (min-width: 10px)
- Rule
- selector, e.g. .foo > .bar
- Declaration
- prop, e.g. color
- value, e.g. #e6e6e6
source stylesheet
tree of nodes
plugins
CSS
Rough overview of how PostCSS works ...
Learn terminology at http://apps.workflower.fi/vocabs/css/en
Read & Transform (Plugins)
root.walkRules()
rule.walkDecls()
decl.insertBefore()
atRule.clone()
comment.remove()
// and so on ...
source stylesheet
tree of nodes
plugins
CSS
Rough overview of how PostCSS works ...
Stringify (Generate)
Make CSS to feed the browser.
- Formatting preserved
- Sourcemap created
source stylesheet
tree of nodes
plugins
CSS
Rough overview of how PostCSS works ...
PostCSS is not ...
- Another either/or
- It offers the rare yes/and
ᕕ( ᐛ )ᕗ
Sass or Less?
Browserify or Webpack?
Gulp or Grunt?
React or Angular or Ember?
༼ ºººººل͟ººººº ༽
PostCSS is not ...
"An alternative to Sass & Less, but faster and with future-friendly syntax."
PostCSS is not ...
"An alternative to Sass & Less, but faster and with future-friendly syntax."
?
?
?
PostCSS is not ...
"A postprocessor (vs. preprocessors)."
PostCSS is not ...
"A postprocessor (vs. preprocessors)."
?
?
PostCSS is not ...
"A postprocessor (vs. preprocessors)."
standard CSS => CSS with fallbacks
(e.g. Autoprefixer)
non-standard CSS => standard CSS
(e.g. Sass or ...)
"PostCSS" is also ...
The ecosystem of
PostCSS-powered tools
➽
PostCSS is ...
➽ A tool for making CSS tools with JS
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1951202/Squaring-The-Circle-CROP.jpg)
How to pick tools?
The old way: choose a preprocessor and a library or two
With PostCSS:
- Pick and choose
- Use a pack
- Do both
- Build your own solution
Fallback Generators
The old way: processor-specific libraries
@include transform(translateY(50px));
/* -webkit-transform: translateY(50px);
-moz-transform: translateY(50px);
...
transform: translateY(50px); */
@include rempx(margin, 1rem 2rem);
/* margin: 16px 32px;
margin: 1rem 2rem; */
.flex-grow(1); /* less hat */
/* -webkit-flex-grow: 1;
flex-grow: 1; */
Fallback Generators
transform: translateY(50px);
/* -webkit-transform: translateY(50px);
-moz-transform: translateY(50px);
...
transform: translateY(50px); */
margin: 1rem 2rem;
/* margin: 16px 32px;
margin: 1rem 2rem; */
flex-grow: 1;
/* -webkit-flex-grow: 1;
flex-grow: 1; */
With PostCSS: just write standard CSS
Fallback Generators
With PostCSS: just write standard CSS
Fallback Generators
With PostCSS: just write standard CSS
You can use it now with this PostCSS plugin!
{ all: initial; }
Fallback Generators
With PostCSS: just write standard CSS
You can use it now with this PostCSS plugin!
.element:container(width >= 100px)
All CSS fallback-generating tools should be written as PostCSS plugins that simply compile standard CSS.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1978692/tumblr_inline_n4foafra0C1sew80h.jpg)
(°ロ°)☝
Fallback Generators
.absolute(10px 0 0 20px);
/* position: absolute;
top: 10px;
right: 0; left: 0;
bottom: 20px; */
transition-timing-function: $ease-in-circ;
/* ... cubic-bezier(0.6, 0.04, 0.98, 0.335); */
@include span(1 of 4);
/* width: 21.05263%;
float: left;
margin-right: 5.26316%; */
Utilities
The old way: preprocessor-specific libraries using preprocessor-specific constructs
absolute: 10px 0 0 20px;
/* position: absolute;
top: 10px;
right: 0; left: 0;
bottom: 20px; */
transition-timing-function: ease-in-circ;
/* ... cubic-bezier(0.6, 0.04, 0.98, 0.335); */
lost-column: 1/4;
/* width: calc(99.99% * 1/4 - (30px - 30px * 1/4));
float: left;
margin-right: 30px;
clear: none;
... */
Utilities
The new way: preprocessor-agnostic libraries using standard CSS constructs
┌( ಠ_ಠ)┘
<aside>
Are you upset by non-standard
properties and keywords?
┌( ಠ_ಠ)┘
- Confusing
- How to know?
- Mixins are "explicit"
- Sass! Sass Sass!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1978692/tumblr_inline_n4foafra0C1sew80h.jpg)
- If you don't know your toolset, nothing will save you.
- One plugin ≠ "PostCSS"
- "PostCSS can be used to make things I don't like" — that's not really a problem.
<aside>
Is that a valid criticism of PostCSS?
- Namespaces: e.g. lost-column, -lost-column
-
Mechanical solutions:
postcss-plugin-context and postcss-use
<aside>
Or is it a solvable problem?
@context cssnext {
.css-example { color: gray(255, 50%); }
}
</aside>
@use autoprefixer(browsers: ['last 2 versions']);
:fullscreen a {
display: flex
}
@mixin intrinsic-ratio-parent($extend: null) {
$extend: if($extend != null, $extend,
toolkit-get('intrinsic ratio extend'));
@if $extend {
@include dynamic-extend('intrinsic ratio parent') {
@include intrinsic-ratio-parent(false);
}
}
@else {...}
}
The old way: treat extended CSS like a (barely adequate) programming language
Utilities
With PostCSS:
USE JAVASCRIPT
- the capable programming language you already know
- Node.js! npm! (っ◕‿◕)っ
Utilities
"...all my libraries will be written in PostCSS from now on and you should do the same..."
- Cory Simmons, creator of the
(PostCSS-powered) Lost Grid system
See his full presentation at
https://github.com/corysimmons/presentations
Utilities
Use standard CSS language constructs like properties, keywords, at-rules, and functions in PostCSS-powered utilities that will work within any Node-capable build process.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1978692/tumblr_inline_n4foafra0C1sew80h.jpg)
(°ロ°)☝
Utilities
The old way: use what your processor-of-choice offers
@for $i from 1 through 3 {
.item-#{$i} { width: 2em * $i; }
}
.foo {
@extend .bar;
@include baz;
}
.box-shadow(@style, @c) when (iscolor(@c)) {
box-shadow: @style @c;
}
.foo {
&:extend(.bar);
.baz();
}
Non-Standard Syntax
With PostCSS: pick and choose language extensions
- For your preferences
- For your project
- For your team
Non-Standard Syntax
Many plugins and packs are based on W3C spec drafts ...
Non-Standard Syntax
:root { --foo: 20px; }
.bar {
margin-left: var(--foo);
@nest &:hover { margin-left: 0; }
}
@custom-media --viewport-medium (width <= 50rem);
@custom-selector :--heading h1, h2, h3, h4, h5, h6;
a:hover { color: color(red alpha(-10%)); }
Non-Standard Syntax
Many plugins and packs are based on W3C spec drafts ...
Non-Standard Syntax
Warning: Not like ES2015!
— not ratified, not stable, might not be implemented.
They are at varying stages of the standards process.
Many plugins and packs are based on W3C spec drafts ...
Other plugins offer Sass-, Less-, Stylus-, and even Rust-like syntax ...
Non-Standard Syntax
@define-mixin bar { color: pink; }
$foo: 20px;
.bar {
@mixin bar;
width: calc($foo + 7px);
height: @width;
}
@for $i from 1 to 3 {
.b-$i { width: $(i)px; }
}
Other plugins offer Sass-, Less-, Stylus-, and even Rust-like syntax ...
Non-Standard Syntax
$animal: bear;
.zoo {
@match $animal {
snake => { color: green; },
buffalo | bear => { background: brown; },
lion => { font-weight: bold; },
_ => { color: gray; }
}
}
Non-Standard Syntax
Other plugins offer Sass-, Less-, Stylus-, and even Rust-like syntax ...
Love your preprocessor's syntax? Use it!
- x => preprocessor => PostCSS => CSS
- or try postscss, poststylus
- x => PostCSS w/ parser => preprocessor => CSS
- postcss-scss (want to write Less & Stylus parsers?)
- Reproduce it with a plugin!
- Divide the tasks: Use preprocessor for transforms, PostCSS for analysis
Non-Standard Syntax
Analytical Tools
"... building plugins for PostCSS is so damn easy and fun." (Brian Holt)
Analytical tools help us mechanically improve the quality of our CSS, instead of relying on good intentions and discipline.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1978692/tumblr_inline_n4foafra0C1sew80h.jpg)
(°ロ°)☝
Analytical Tools
Enforce BEM-style selector conventions.
/** @define Card */
.Card {..}
.Card.is-disabled {..}
.Card-title {..}
.Card-title--small {..}
.Card-body {..}
.list-item {..} /* ERROR! */
.Card ul > li {..} /* ERROR! */
.Card--big--closed {..} /* ERROR! */
Don't rely on discipline!
Enforce ~100 rules to keep your CSS clean, legible, consistent, intentional
Don't nitpick:
auto-enforce!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1978859/example.png)
Mr Larry Davis spoke early about
- SUIT naming conventions
- CSS property ordering conventions
- use stylelint
-
38*$px convention to produce rems
- use postcss-pxtorem
(╯°□°)╯
Other Important Tools Powered-By PostCSS:
(☞゚∀゚)☞
The old approach to CSS problems:
- complain
- strive eternally for discipline
- ignore problems
- build an awesome but super complex and isolated tool (e.g. Sass & Less & Stylus, CSSLint, CSScomb, -prefix-free)
- pick sides instead of features
IN SUM
The PostCSS approach to CSS problems:
- never shy from addressing a pain point
- experiment with new features and syntax
- try to build mechanical solutions
- pick and choose features
- share a low-level parser, node tree, and stringifier (PostCSS) with other tools
- get better at writing JavaScript and Node.js
IN SUM
Thank you!
@davidtheclark
davidtheclark.com
![](https://s3.amazonaws.com/media-p.slid.es/uploads/284334/images/1978947/avatar.jpg)
Exploring New Possibilities with PostCSS
By David Clark
Exploring New Possibilities with PostCSS
- 2,864