HTML & CSS
Article

An Introduction to PostCSS

By Pavels Jelisejevs

Most developers who spend their time working with CSS are familiar with preprocessors such Less, Sass, and Stylus. These tools have become a vital part of the web development ecosystem. Writing styles for a website without using features like nesting, variables, or mixins now seems cumbersome and awkward. Although each of them is a great and extremely useful product, let’s take a step back and consider if using preprocessors in such a way is indeed the best approach.

I see a couple of problems with tradition preprocessors:

  • They are not extendable. Whichever preprocessor you choose, you are limited to the set of features that it provides. If you need anything on top of that, you’ll need to add it as a separate step in your build process. If you feel like writing your own extension, you’re on your own.
  • You can’t leave anything out. Some of the features preprocessors provide such as Sass’s @extend may be detrimental to you, and you might want to leave them out completely. Unfortunately, while you can avoid using them, you can’t remove that part of the tool to minimize code.
  • They push out CSS standards. You might say that each of the preprocessors has become a standard of its own. Regrettably, they don’t aim at being compatible with the W3C standards, which means that they cannot be used as polyfills for early testing of the newer W3C standards.

This is where PostCSS comes in.

What is PostCSS?

PostCSS is not a preprocessor per se; it doesn’t transform CSS. As a matter of fact, it doesn’t do much by itself at all. What it does is provide a CSS parser and a framework for creating plugins that can analyse, lint, handle assets, optimise, create fallbacks, and otherwise transform parsed CSS. PostCSS parses CSS into an abstract syntax tree (AST), passes it through a series of plugins, and then concatenates back into a string. If you’re familiar with JavaScript tooling, then you can think of PostCSS as Babel for CSS.

There are currently more than 200 plugins for PostCSS, many of which are listed on the PostCSS GitHub page, while others can be found on the useful PostCSS directory postcss.parts. PostCSS can be integrated in most the build tools including Gulp, Grunt, webpack or npm.

So how does PostCSS tackle the problems we listed earlier?

  • Each plugin is installed separately. This means you choose which ones you need and in what order they should be applied. Usually, plugins can be additionally configured using some set of options.
  • You can write your own plugins. Each PostCSS plugin receives parsed CSS as an input parameter, analyses or modifies it, and returns it in the same manner. This means that plugins don’t need to handle parsing CSS and converting it back into a string. So the ability to build your own plugins is not as difficult as you might think.
  • PostCSS can be used to polyfill real W3C features. There are a lot of plugins that aim to implement features from new W3C specifications. This will enable you to write code that respects standards and is likely to be compatible with future versions of CSS.

Using PostCSS

Theory is great, but let’s move on to some juicy practice. Let’s install PostCSS and see what it can actually do. We won’t go into much detail about setting up proper project builds, since that’s a topic that deserves an article of its own. Instead we’ll run PostCSS directly from the command line. You can find more info on using PostCSS with your favourite build tool on its Github page.

Installing PostCSS

PostCSS is installed via node and npm, so make sure you have those installed before you start. To install PostCSS globally on your system run:

npm install -g postcss-cli

You can make sure it’s working by running:

postcss --help

This will give you a list of parameters that the CLI accepts. You can also find these in the postcss-cli documenation.

Running PostCSS

Now that we have PostCSS installed, let’s give it something to work with. Create a styles.css file in your project folder and add some CSS. For example, define a flexbox container:

.container {
  display: flex;
}

Flexbox is a great feature, but it does require vendor prefixes to run on certain browsers. I would hate to maintain these manually. Fortunately, Autoprefixer, one of the most popular PostCSS plugins does exactly that. It automatically adds vendor prefixes based on the information provided via Can I use. I’ll show you how to use it to keep our vendor prefixes up to date.

To install Autoprefixer run:

npm install -g autoprefixer

Next, navigate to your project folder and create a dist folder that will contain the processed CSS:

mkdir dist

Then run PostCSS:

postcss -u autoprefixer styles.css -d dist

What this says is: run Autoprefixer on styles.css and save the output to dist/styles.css. Now if you open dist/styles.css you will see your CSS with all of the required vendor prefixes:

.container {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
}

If you run PostCSS with a -w flag, this will also start a watcher process and automatically rebuild styles.css each time the file is modified.

Plugin Configuration

We can configure Autoprefixer to add prefixes according to the browsers we plan on supporting. This can be done using the browsers option. When running PostCSS via the CLI, plugin configuration needs to be defined in a separate .json file, for example, postcss.json. Let’s create the file in the current folder and configure Autoprefixer to support the 2 most recent versions of each browser.

{
  "autoprefixer": {
    "browsers": ["last 2 versions"]
  }
}

We can now re-run the PostCSS watcher with the new configuration file:

postcss styles.css -u autoprefixer -c postcss.json -d dist -w

Enabling Source Maps

Source maps are essential for debugging compiled CSS. PostCSS can generate inline source maps in the output file if you add the --map option (or the -m flag).

Even More Plugins

PostCSS has an amazing number of plugins for linting, quality checks, fallback, old browser support, inlining assets, generating sprites, optimisation, new syntax support, and future CSS features. As mentioned, you can find a structured catalogue of plugins at postcss.parts.

To give you a sample, here are a few more plugins that demonstrate the power of PostCSS.

The Custom Properties Plugin for CSS Variables

The postcss-custom-properties plugin aims to implement support for the W3C custom properties specification (aka native variables). It allows you to define custom properties in a selector with arbitrary values and reference these in other places in the stylesheet.

This serves a similar purpose to Less and Sass variables: to store common values and eliminate code duplication. The main difference is that the scoping mechanism is a bit different; similar to regular properties, CSS custom properties propagate along the element cascade, instead of being block scoped.

Here’s an example of how this plugin works. The following code:

:root {
  --container-width: 800px;
}

.container {
  width: var(--container-width);
}

Will compile to:

.container {
  width: 800px;
}

The Custom Selectors Plugin

The postcss-custom-selectors plugin implements the Custom Selector specification. This allows you to pre-define selectors and reference them later in the code. For example, we can save all headers in one selector and re-use this as a variable:

@custom-selector :--headings h1, h2, h3, h4, h5, h6;

:--headings {
  color: mediumblue;
}

Which will compile as follows:

h1,
h2,
h3,
h4,
h5,
h6 {
  color: mediumblue;
}

The Russian Stylesheets Plugin

Ever wanted to learn Russian but were too busy writing CSS? No worries, you can now do both by writing CSS in Russian! Just use the Russian Stylesheets plugin. Check this out:

h1 {
  размер-шрифта: 20пикселей;
  цвет: красный;
  цвет-фона: белый;
  вес-шрифта: жирный;
}

Which is translated into:

h1 {
  font-size: 20px;
  color: red;
  background-color: white;
  font-weight: bold;
}

Well… I never said all the plugins were equally useful!

Wrapping Things Up

Preprocessors like Less and Sass are great. They have contributed much to our development process and are definitely not something we can easily leave behind. But, I feel that that the time has come to stop and reconsider whether those tools are the right way to do things in the long run.

We don’t just need new features writing stylesheets, we also need modularity, additional exposure of the new standards, as well as flexible build processes. PostCSS provides just that and might be a game changer in the CSS world.

  • David Nguyen

    Thank you for this article. Very helpful!

  • Phil

    I’ve been thinking about using postCss for a long time now.
    Might actually try it after this article !

  • http://artanddesign.us/ lori

    Interesting but why would one want to use Post CSS when Gulp already does all that it does with versions of the same plugins? Secondly, I dont see the reasoning behind using Post CSS WITH Gulp? As far as the quality of the CSS that’s compiled, Isn’t it true that if you are already using Sass and Gulp intelligently, you have quality and conformant CSS compiled?

    • Pavels Jelisejevs

      There are a number of reasons:
      1. It makes you less dependant on Gulp. If later for some reason you’ll want to switch to a different build system, it will be easier to do.
      2. Not all PostCSS plugins have a Gulp adapter. Plus, having one adds a new layer of abstraction, a new dependency and thus a new level of complexity an more space for errors.
      3. When using only Gulp and plugins there are some additional things that you’ll need to take care of yourself. For instance, source map support. Sure, it’s possible, but it’s one more thing to do.

      And I’m not saying that Sass is a bad thing and you can’t write good css with Sass. It’s just that PostCSS takes a different approach to it.

      • http://artanddesign.us/ lori

        Yeoman-Gulp generates a sourcemap. Yes it is a different approach.. It’s true that there are new, tempting capabilities in CSS. I don’t feel dependent on Gulp and it is quite easy to take my working files into another build system but I’d miss Yeoman and Gulp if they were no longer maintained, as I am comfortable and productive with those tools. So far I found made-for-Gulp, or adapted-from-Grunt, any plugin I needed.. and writing my own tasks isn’t too challenging. Nevertheless I’m looking at the horizon of CSS, PostCSS, and the newer kids on the block. Good to know about them.

  • http://habd.as Josh Habdas

    Thanks for the rundown and link to the PARTS app. I was surprised not to see Pleeease listed on there – it packs a wallop. But the crack about Russian CSS made up for it.

    For those who’re not familiar with media query packing take a peek at Pleeease CSS, built using PostCSS.

    Last thing. Many people are using module bundlers like Webpack. It’d be great to see a section here on integrating PostCSS with a module bundler so readers have a better understanding how to incorporate this tool into existing dev workflows.

    • Pavels Jelisejevs

      I wasn’t aiming at listing all of the great plugins available for PostCSS, that’s why Pleeease didn’t make it to the article. I’m hoping to elaborate this topic on SitePoint and write some more detailed articles about different plugins. As well as different build system integration.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Front-end, once a week, for free.