PostCSS 0.1, the very first version of the tool that introduced a novel way to transform CSS with JavaScript, was released in the early November 2013. On the project’s fifth anniversary, Andrey Sitnik, the creator of PostCSS, takes a chance to look back. He tells the story behind the project, reviews the community’s present achievements, and peeks into the future.
Before I started building PostCSS my mind was not entirely occupied by CSS and JavaScript, I was reflecting on a broader subject of the relationship between a human and a machine. If that sounds too broad—bear with me, soon it will all start to make sense.
The Past
A human brain has its limits. It makes mistakes. It can not keep a thing too complex readily accessible for too long. That is one of the reasons we created computers. Сomputers have introduced even more complexity, but luckily they can also help reduce it. Consider this: we don’t write code in binary since a very long time.
Machines help us build programs by translating our language into theirs. Higher-level constructs are compiled into lower level ones. A piece of code produced by a human is analyzed by machines for errors and then translated into something a machine itself could understand.
In fact, cyberpunk is already here: computers are co-authors in our work.
Websites are programs too. Big websites require a lot of code, and it becomes increasingly hard to keep a whole complexity of a big code base in a single developer’s head.
But why should people suffer from that complexity at all? I believe these are machines who should suffer, not humans.
These were the thoughts in my head before I went on a PostCSS journey. And the story of PostCSS starts with Autoprefixer.
Autoprefixer helps to solve an exceptionally tedious task in maintaining CSS code bases: managing vendor prefixes that unlock cutting-edge CSS features for specific browsers. The job is not only daunting, but it is fantastically error prone. At the time, there were scores of articles on doing prefixing right. But the numerous attempts to school developers did not change a thing: no developer can (or should) read each and every article and watch each and every talk just do to their job correctly.
Maintaining vendor prefixes by hand made developers suffer. It made me suffer, because at the moment, while doing frontend work at Evil Martians for a client, I had to deal with a particularly unruly codebase that required a lot of prefixes.
It sounded exactly like something a machine should have suffered from. A computer, after all, could easily parse CSS and add these prefixes automatically.
Autoprefixer, at the moment of its release, was not the only tool for helping with CSS. Other tools existed that could optimize the size of a styles bundle or lint CSS code for errors. And most of those tools followed the same sequence of steps: parse a string of CSS into an object tree (AST), change it in some way, and produce a new CSS string as a result.
But what made us repeat the same parsing work again and again? Why could not we create a framework that would solve the base problem once and for all and allow us to develop new tools faster, and without repeating the same mistakes?
That is precisely the idea behind PostCSS.
PostCSS is not a preprocessor or a way to add syntactic sugar. It is a framework for creating CSS tools.
I designed that framework for a single purpose: bring more exciting ideas into the world of CSS tooling. If the tools were easier to build, I thought, more people would build them, and everyone would benefit from the variety of approaches.
With that in mind, I started working on PostCSS and had my first release just two months later: on November 4, 2013.
I was under a deadline, a quite unusual one. I had a pre-set date in mind to start on a “digital sabbatical”: the plan was not to touch anything with a processor and Internet connection for a whole month and see how it would affect my mind. But that is an entirely different story.
The Present
Five years later, PostCSS is one of the most popular frontend tools and keeps growing at a rocket pace.
PostCSS’ core idea, a framework for plugins to perform AST transformations, has spread to other languages: giving birth to PostHTML for HTML, Remark for Markdown, and Retext for natural language.
Babel, the tool at the heart of modern JS ecosystem, now also evolves around plugins that perform necessary transformations while the core compiler just parses and prints back the code.
We now even have a “Babel for CSS”: a postcss-preset-env plugin that picked up the banner from the abandoned cssnext. It allows you to use upcoming CSS features in the current browsers and comes out of the box with create-react-app or recent releases of Rails.
stylelint, a PostCSS-based styles linter, is well ahead of its competition. It supports CSS, SCSS, Less, Sass, and CSS-in-JS. It detects common mistakes that developers commit when writing CSS code. It is used by Facebook, Wikipedia, and WordPress.
CSS Modules, also PostCSS-based, is one of the most popular approaches for component isolation in React. It is also available as a PostCSS plugin, built and maintained by Alexander Madyankin, my colleague at Evil Martians.
My original dream of building a tool that encourages developers to create more tools was fulfilled tenfold.
Let’s take a look at some plugins that I think are especially worth mentioning as they bring some truly interesting ideas to CSS.
- postcss-easing-gradients improved default color gradients in CSS and was even transformed into a CSS Working Group Level 4 draft proposal. It’s still a long way to go, but we might see the default browser support one day!
- postcss-grid-kiss provides an alternative approach to CSS Grid Layout: a grid is described inside a single property through a demonstrative ASCII art syntax.
grid-kiss:
"+------------------------------+ "
"| header ↑ | 120px"
"+------------------------------+ "
" "
"+--150px---+ +----- auto -----+ "
"| .sidebar | | main | auto "
"+----------+ +----------------+ "
" "
"+------------------------------+ "
"| ↓ | "
"| → footer ← | 60px "
"+------------------------------+ "
-
postcss-autoreset and postcss-initial suggest an entirely new level of component isolation. BEM, CSS Modules and CSS-in-JS only isolate selectors, they don’t protect from conflicts caused by CSS resets or inherited properties like
line-height
. “Local reset technique” suggests addingall: initial
(with polyfill for IE/Edge) into every component to isolate it from unwanted inherited properties and perform a “bullet-proof” style reset locally. -
postcss-normalize is an “Autoprefixer for Normalize.css”: it only adds normalizations that are necessary for your target browsers. And it uses the same Browserslist config as the Autoprefixer uses.
It would not be fair not to mention areas where the PostCSS community was less successful. Preprocessors like postcss-nested still lag far behind Sass, Less, and Stylus.
In a way, that is fair: it is hard to suggest something entirely new for syntactic sugar, and the only reason to use PostCSS-based tools as a Sass replacement is performance: it is much faster to parse code in PostCSS than to combine it with another tool.
I think it is also important to mention PostCSS’ main competitors.
Some of them suggested really fresh ideas and were less lucky (in terms of popularity) mainly due to marketing reasons. Stylecow implemented a Visitor pattern before Babel 6. This approach can improve processing performance when there is a large number of plugins in a pipeline. CSSTree found a way to become three times faster than PostCSS. Check out Roman Dvornov’s slides about optimizations that helped to achieve this stunning result.
The Future
In the last five years, a community around PostCSS has achieved impressive results, but it is not the time to bask in the glory. There are still a lot of interesting challenges that CSS brings and that can be solved by the tools we can build together. I am going to outline a few of them.
Autoprefixer and Grid Layout for Internet Explorer
CSS Grid Layout is awesome. It is new, shiny, easy to reason about, and supported by all major browsers, with a notable exception of Internet Explorer. The fact is that IE11 is still important for many companies and dropping the support for it means becoming less attractive to enterprise.
Ironically, the idea for Grid Layout was born at Microsoft and first implemented in IE10 back in 2011—through -ms-
vendor prefix.
So, the modern Grid Layout specification can be made backward compatible, and it sounds like an excellent task for Autoprefixer. In fact, that task is already solved, at least partially—thanks to the hard work of many frontend heroes.
Here is some Autoprefixer-generated, IE11-compatible CSS grid code:
body {
display: -ms-grid;
display: grid;
grid-gap: 10px;
-ms-grid-rows: 30px 10px auto 10px 30px;
grid-template-rows: 30px auto 30px;
-ms-grid-columns: 3fr 10px 1fr;
grid-template-columns: 3fr 1fr;
grid-template-areas:
"🎩 🎩"
"🍔 📰";
}
.header {
-ms-grid-row: 1;
-ms-grid-column: 1;
-ms-grid-column-span: 3;
grid-area: 🎩;
}
.nav {
-ms-grid-row: 3;
-ms-grid-column: 1;
grid-area: 🍔;
}
.main {
-ms-grid-row: 3;
-ms-grid-column: 3;
grid-area: 📰;
}
Note that even grid-gap
and grid-template
are supported. And they are not even part of the original IE’s grid implementation.
Big companies like Financial Times and Yandex (NASDAQ: YNDX) already use this magic in production.
Unfortunately, not all Grid features are yet supported. You cannot use the Autoprefixer’s familiar “run and forget” approach and still need to double-check the result manually. Still, it is faster than coding a separate grid implementation just for IE from scratch.
We have many ideas on how to make CSS Grid work even better in IE. There is also an attempt to support auto-placement. Now it is a perfect time to join the effort and make your cross-browser grid implementations completely hassle-free.
Zero-runtime CSS-in-JS
CSS-in-JS is a great idea. It allows you to keep the whole component in a single file, styles included.
At first, CSS-in-JS implementations used inline styles, and this approach was not received well in the community who saw it as a step back from modern frontend practices.
But now the second generation of CSS-in-JS is upon us: it does not rely on inline styles and has native support for :hover
and @media
and pseudo-selectors.
One big problem with these implementations is that they require a client-side JavaScript runtime, and in some cases, it can become rather heavy (up to 15 KB in case of styled-components).
However, the third generation of CSS-in-JS approach has just appeared on the horizon: the “zero runtime” one. The best examples are astroturf and linaria. Both libraries use the familiar styled-components API but bring significant performance improvements.
It is also now possible to combine CSS-in-JS with the state-of-the-art CSS tools. For example, with astroturf
, you can process your CSS with Sass and Autoprefixer.
Improving tooling for CSS-in-JS is yet another exciting frontier for the PostCSS community.
Stylelint as a way to share best practices
Stylelint is a linter: it is a tool that will analyze your CSS, warn about well-known errors and even fix them automatically with a --fix
flag.
.widget {
margin-top: 10px;
width: 100px;
height: 100px;
margin: auto 0; /* ← Stylelint will warn you that this margin overrides margin-top
from second line */
}
However, automatic linting is not the only reason to adopt Stylelint in your project. It can be extremely helpful for onboarding new developers on the team: a lot of time (and nerves!) are wasted on code reviews until junior developers are fully aware of accepted code standards and best practices. Stylelint can make this process much less stressful for everyone.
Companies like Facebook have already adopted Stylelint’s custom rules as a way to promote best team practices. Some of the rules used at Facebook are slow-css-properties
, filters-with-svg-files
, use-variables
, and mobile-flexbox
.
The use of best practices enforced by Stylelint rules can also serve a broader developer community.
For instance, everyone heard about accessibility, and it is now considered good manners to make web applications as accessible as possible. Accessibility practices are also notoriously hard to implement, especially in projects that have tight deadlines and limited resources: it is also very easy to make a mistake that breaks accessibility, and an error like that can stay unnoticed for a long time.
stylelint-a11y brings together most common a11y practices and makes following them a question of setting up a right pre-commit hook: no need to remember all the rules constantly.
Stylelint can work with any sharable config—and there is a big demand for creating such configs and new rules for them. That itself can be an excellent task for anyone interested in exploring the PostCSS philosophy.
Stay brave
In the PostCSS community, there is no lack of passionate developers full of original ideas—exactly how I envisioned it five years ago. The only thing I can say to them—stay brave.
Even if you are not a member of CSS Working Group, you can still make CSS better.
Create a PostCSS plugin, write a polyfill for it, test it thoroughly with your colleagues, and then create a pull request to CSSWG’s drafts repository. You don’t have to be a rock star programmer to make a contribution: if your idea is valuable enough, it can have the power to change the community.
It is easy to say “if developers have problems with CSS on real projects, this is because they don’t understand CSS”. I read this too often, and I don’t believe it is the case. Be brave. Create tools that can help to make large CSS code bases more maintainable. A lot of popular tools were created by developers who were not very famous at the time but had bright ideas.
Your CSS practices may be worth sharing, but for a lot of reasons it may be hard to participate in a big conference and have a world-class stage to share them. Don’t worry. Pack your best practices into custom linting rules: they may have a bigger impact than a popular conference talk.
Stay brave, and let’s build the future of CSS together.