Skip to content

I Prefer PostCSS

Published:

PostCSS logo

Let me explain why I prefer PostCSS, and you should too, for writing CSS.

Disclaimers

Origin of CSS Preprocessors

Let’s start by reviewing the origin of CSS Preprocessors.

A CSS preprocessor is a program that lets you generate CSS from the preprocessor’s unique syntax.

The first one (that I remember) was Less, a JavaScript library that offered us a new syntax, which after parsing our code, converted it to browser-supported CSS. Like Less, other tools appeared, such as Sass, Stylus, or PostCSS.

With these new tools, and their new syntax (on top of CSS), we suddenly had in our hands a programming language with variables, functions, mixins, loops, or operators. With this we could reuse a lot of code, both in the same project and across multiple projects. The spearhead were variables—without knowing it, the foundation of what we now know as Tokens from current design systems appeared. A dream for any developer.

What I Think Scares People About PostCSS

Recently a friend told me:

I haven’t gotten around to PostCSS yet. I tried it a few years ago on a project following Naiara Abaroa’s talk, and I really struggled with it. And I went back to my comfortable SCSS.

On one hand, I understand what happened to Alberto, at first PostCSS can be scary. But I’m surprised by the comment that he finds SCSS comfortable, since at the time he had to learn a new syntax, nothing like standard CSS.

Hello PostCSS

The first impression when approaching PostCSS is that it’s chaotic. Many configuration parameters, many ways to do things, many plugins, the configuration order of those plugins matters as it can vary the result, and most shocking, don’t expect to find a CSS syntax error system, since you can invent any property, alias, or syntax and have your own plugin generate the CSS you need.

Something like Sass’s @mixins, but less controlled, since all validation falls on the person developing the plugin that will transform that code into what’s desired, otherwise, it will return it as is. And of course, it might be syntax that makes no sense to the browser.

I’m sure if you were considering leaving that comfort zone that Sass has offered you for so long, I’ve just scared you. But have a little patience, remember I’m explaining this because it’s what I believe scares people about switching to PostCSS.

PostCSS Coexisting with Our Sass Project

One of the first questions that appears when we decide to try or implement PostCSS in our active project is: Is it necessary to change everything from Sass to PostCSS or can they coexist? They can coexist, in fact you’re most likely already using PostCSS without knowing it.

If you’re using Autoprefixer in your project, you’re already using PostCSS. Since it’s the driving plugin of this entire PostCSS ecosystem.

There are several ways to make PostCSS and Sass (or another preprocessor) coexist. If you’re using Autoprefixer, you’ll be running it after generating CSS from Sass, to add necessary vendor prefixes. It’s at that point where you can add optimization plugins like: cssnano, CSS MQPacker, Sort Media Queries, which are plugins that optimize CSS generated by Sass.

So in this case we’d be using Sass to develop our CSS and PostCSS to optimize it.

There’s the PostCSS SCSS Syntax plugin, which allows you to write SCSS syntax but use the PostCSS ecosystem to generate the final CSS.

There are many plugins, I encourage you to take a look at PostCSS.parts and PostCSS Plugins where you’ll find many of them, grouped by categories. However, I advise you that if you find one that interests you and it’s a plugin pack, like those you’ll find in packs, first analyze what plugins it includes, what plugins you need, and consider using them separately. This will allow you to have control and force you to read the documentation of each one. In that list you’ll see postcss-preset-env, which I’ll talk about later.

I’ll take this opportunity to mention that I recently published a PostCSS plugin that allows using the new AVIF image format in our CSS background images, avif-in-css. Leave a ⭐️ if you think it’s interesting, seeing that I have people’s support encourages me to create more tools 😊. In this article I explain how to use it AVIF in CSS with PostCSS.

Who’s Using PostCSS?

Here’s where I could list a long list of well-known company names, but I prefer to dig a little deeper and see that it’s included in frameworks that are being used in many production projects.

Let’s start with the best-known CSS framework of all, Bootstrap. If we take a look at the package.json we’ll see that among the dependencies is PostCSS.

Screenshot of part of Bootstrap's package.json file

Here we can see that Bootstrap is using PostCSS to manage LTR (Left To Right) to provide coverage for content that has this reading format, and with Autoprefixer to add necessary vendor prefixes.

#nuclitip analyzing dependencies of tools, frameworks, or applications helps me better understand what’s behind them. And on many occasions discover what magic is hidden behind certain functionalities.

Another framework currently among trending topics is Tailwind CSS, which with a paradigm totally opposite to what we’ve been using for a long time, offers us a series of utilities to apply our styles with a composition pattern from our HTML. I want to dedicate the next article to sharing my opinion on this framework.

Well in this case, PostCSS is present in 100% of Tailwind CSS, since it’s not using Sass, Less, or Stylus in the coding of CSS properties.

The first version was based on suitcss-base which includes suitcss-preprocessor as a preprocessor, which is made up of several PostCSS plugins.

So we’re using PostCSS in many of the CSS frameworks being used in web development.

PostCSS Writing Standard and Next-Generation CSS

Here you’ll learn the most important reason why I prefer PostCSS. It’s not because it’s cool, because the language behind the plugins is JavaScript, it’s not because it makes me look like a super cool developer, it’s because it allows me to write standard CSS.

As its own definition informs us, PostCSS is a tool for transforming CSS with JavaScript. That means we can write any syntax in a CSS file and through a plugin, convert it so that browsers can interpret the resulting CSS.

Under that premise, Max Thirouin gave it a very interesting approach: instead of inventing syntax, use plugins to be able to write the CSS being defined in the CSSWG of the W3C, and have those plugins convert “future” CSS into CSS that works in current browsers.

CSSNEXT

From that idea came cssnext, a pack of PostCSS plugins that closely followed CSSWG drafts to keep the plugins updated. The project appeared in August 2014, being updated practically monthly until January 2018, and in May of the same year Max published the article Deprecating cssnext, where he expressed his opinion of not agreeing with the directions PostCSS was taking and that he was no longer working directly with CSS. However, in the same article he advised us to use postcss-preset-env by Jonathan Neal.

I tried to maintain the package for a while, as the number of downloads prove that people are actually using it. But now that a solid alternative is around (postcss-preset-env), I think it’s time to deprecate cssnext.

postcss-preset-env

As I mentioned in PostCSS Preset Env, the Babel of CSS, using PostCSS with postcss-preset-env opens the doors for us to use properties being defined in the CSSWG before they’re implemented in browsers, not all of course.

Yes, this package is a plugin pack, so remember, use it with knowledge and by studying the documentation of the plugins you’re going to use.

Since it’s a pack of several plugins, the way to specify the support we want is through the specification state. Here Jonathan Neal proposed a state system like we have in JavaScript, so on cssdb we can check the state of each CSS property, as well as information with links to the official specification documentation and the plugin repository we can use to utilize that new property.

Screenshot of Nesting Rules property on cssdb.org

Here we can see an example of the information we can find: state, name, link to specification, link to PostCSS plugin, and a code example. That’s right, we’ll have nesting natively in CSS.

Image with definition of each state of new CSS properties

In this other image we can see the different states we have available. So if we want to use nesting in our CSS code, we can do it as if it were already available in browsers.

postcss.config.js
  ...
    plugins: [
      postcssPresetEnv({
        stage: 1
      }),
    ]
  ...
style.css
article {
  & p {
    color: var(--color-text);
  }
}

With a configuration of stage: 1, postcss-preset-env will parse our CSS using the necessary plugins to support state 1 or higher specifications. This way, when nesting is at stage 4, the nesting plugin will no longer be used, since we’ll have it natively supported.

Use tomorrow’s CSS today

As postcss-preset-env’s own slogan indicates, we can use tomorrow’s syntax today.

On many occasions I mistakenly refer to writing standard CSS, since in other preprocessors you can also write standard CSS. My error is in calling it standard when I want to refer to writing CSS syntax that will end up in the standard, since it’s part of the specification, but in a draft or release candidate state. Let’s see some examples.

The following code is not supported by current browsers, but it will be, and it’s code we can’t write with preprocessors like Sass, which wouldn’t do any kind of transformation in the compilation process.

image-set() function

This would be our CSS code that we write, to load one image or another depending on device resolution. The same thing we can do with the <picture> tag in HTML, but directly with background images in our CSS.

.example {
  background-image: image-set(
    url(img.png) 1x,
    url(img@2x.png) 2x,
    url(img@print.png) 600dpi
  );
}

We’ll be able to do this natively (standard) when we have support in all browsers, as we can see in the CSS Image module specification.

The plugin that will transform this code to CSS that all browsers understand is postcss-image-set-function and this would be the output code of our example.

.example {
  background-image: url(img.png);
}

@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
  .example {
    background-image: url(img@2x.png);
  }
}

@media (-webkit-min-device-pixel-ratio: 6.25), (min-resolution: 600dpi) {
  .example {
    background-image: url(my@print.png);
  }
}

.example {
  background-image: image-set(
    url(img.png) 1x,
    url(img@2x.png) 2x,
    url(img@print.png) 600dpi
  );
}

It would simply add the fallback to support browsers that need it.

Does this sound familiar? It’s the same scenario we have in JavaScript. Transpilers like Babel allow us to write syntax like Optional Chaining and provide coverage for Internet Explorer 11.

Will PostCSS Go Out of Fashion?

Personally, I don’t think so. PostCSS offers us the opportunity to use or write plugins to optimize our CSS, to add linters (like stylelint), create aliases, or very customized syntax according to the project.

If we add to that postcss-preset-env, which is acting as a transpiler for new functionalities, I believe PostCSS is the Babel for CSS. There will always be some new property to transpile and provide support for browsers that don’t have support for that new property.

Conclusions

The simple fact of being able to write standard CSS should be reason enough to not wonder whether to switch from Sass to PostCSS, but to ask ourselves, why are we writing CSS in a syntax that’s not native?

I’m a CSS romantic, I like writing native CSS, or Vanilla CSS as it’s also called. That’s why I prefer PostCSS, not to be cool or seem more developer-like, but because I’m writing CSS. So whenever they ask me I’ll recommend using PostCSS with postcss-preset-env, whether it’s someone starting to develop or someone who has been doing frontend development for years.

If the learning curve of configuring a PostCSS environment holds you back, stay tuned, I’ll soon announce a course to start with PostCSS from scratch, integrate PostCSS into a Sass project, and how to migrate a Sass project to PostCSS.


Previous Post
My Opinion on Tailwind CSS
Next Post
It's Curious How Forgotten and Mistreated CSS Is