Switching from SASS to PostCSS

Switching from SASS to PostCSS

Tl;dr: If starting out with a new project, it can pay off to fully embrace PostCSS. In existing workflows, SASS has no particular drawbacks and can easily be extended using PostCSS.

While toying around with PostCSS in early 2015, I never really saw the big advantages PostCSS gets me over SASS. I now took the time to revisit the ecosystem and possibilities around PostCSS. If you thinking about switching yourself, this post is for you.

Our old approach: SASS

We used SASS extensively for many years, but ran into problems when compilation times were becoming a serious issue. Libsass basically fixed this, as it replaced the painfully slow ruby sass compiler with a C++ implementation.

What we use SASS for currently:

  • Imports for Modularization of our CSS Files (using SMACSS Architecture)
  • Nesting of CSS Rules (which I couldn’t live without, seriously)
  • Using Variables (All our internal SASS-Libraries depend on a common subset for easier adaptability)
  • Building more flexible definitions using @extend Syntax
  • Defining mixins and helper functions
  • Automated media-query grouping with breakpoint-sass
  • Color transformations

Other tools we use in our CSS Buildstep:

  • Autoprefixer was a welcome addition to our gulp-based workflow, because it allowed us to simply use the standard-compliant css definitions - vendor prefixes would get added automatically without having to use custom mixins (The compass framework provided those for example). What I didn’t know was, that autoprefixer in itself was already based on PostCSS.
  • CSSNano to minify the CSS output. This has a lot of magic built in and since I ran into an issue where a z-index got minified to a lower value (which you can easily prevent) I am a bit cautious. You can’t argue with the enormous file size savings, though!

While we don’t experience any particular pain points in our current workflow there are a few areas that could be further automated. Lets see what PostCSS can do for us:

Our updated approach: PostCSS

PostCSS is described as a CSS postprocessor (while SASS and LESS are preprocessors) which means that it takes in a valid CSS stylesheet and performs various transformations on it. SASS in comparison takes in a special *.sass or *.scss file and outputs a CSS file.

PostCSS is organized in plugins (of which autoprefixer tends to be the most well-known) and can be extended easily.

A big part of the story is, that upcoming css specifications already address many problems that sass solves by introducing it’s own syntax, so why not write this next-level CSS directly and postprocess this into currently supported syntax?

I like how this is conceptually closer to what we do with babel and javascript, but a downside is that there is still next to no consensus on the details of many specifications. If you don’t want to take the plunge just yet, alway remember that it is absolutely viable to just use certain PostCSS plugins in tandem with your existing SASS-based build step.

Getting up to speed

To make PostCSS a viable replacement I first try to replicate the functionality I’ve come to depend on in SASS. When possible, I’ll try to replace SASS-specific with forward-facing syntax.

Imports and Nesting

Getting back a big part of the functionality of our SASS-based stack is just a matter of including the postcss-nested and postcss-easy-import plugins. This covers imports of partials (using a prefix, so they won’t get processed as an individual file) and using nesting in your style rules.

As a nice addition postcss-import (which postcss-easy-import uses) already has built in support for importing packages from npm’s “node_modules”-folder, which is extremely useful to avoid having to define those complex relative urls.

Variables

The syntax of the current specification for “custom properties” (Variables) in CSS is a bit different than in SASS, but as this is fairly stable updating your stylesheets in this manner should future-proof this for a later client-side implementation. The PostCSS plugin you are looking for is postcss-custom-properties. To my surprise custom properties are already well supported.

If you don’t want to deal with custom properties, you can always use postcss-simple-vars which basically gives you sass-like variables.

Extends

A pretty accurate equivalent to the sass @extend function is the new @apply syntax. While basically no browser other than chrome even has plans to implement this, is provides us with a syntax in the spirit of custom properties. The postcss-apply plugin works the magic here.

Mixins

The story for mixins is a bit different. Since there is no effort to integrate this into browsers by extending the css specification it leaves me with a little bit of headache. For the less syntactically squeamish, the postcss-mixins plugin allows for sass-like mixins, that can even be defined via javascript.

Media-Query Grouping

Since nesting media-queries in style rules is already covered by postcss-nested, the use of breakpoint-sass mainly covered grouping and provide variables with predefined breakpoint configurations. While grouping seems to be a job for a css minifier like cssnano, predefined breakpoints can be done with postcss-custom-media.

Color transformations

The color specification which is available through postcss-color-function provides a wide range of color transformation. Once again this means rewriting your sass syntax.

Better CSS with PostCSS

All the PostCSS plugins discussed up to this point mainly serve replicating the existing functionality already present in SASS. But what can we achieve with additional PostCSS plugins? Postcss.parts provides us with an unofficial catalogue with plugins for various tasks. Here are a few PostCSS plugins that I added to our build process:

  • postcss-flexbugs-fixes: Since there still are a few really annoying inconsistencies, we use this plugin to provide IE11 with a few syntax specifics we would otherwise have to add manually.
  • postcss-sorting: While this is a PostCSS Plugin we don’t use this as part of our build step as this actually makes sense for applications used to edit the source files. Luckily there is a sublime and an atom plugin available. What this does is, that it sorts the different CSS properties in a consistent manner, which greatly improves readability.

While all of the following tools provide a PostCSS plugin, I integrated them through other means:

  • Stylelint via gulp-stylelint: Having consistent css formatting is a pain and if different developers collaborate on the same stylesheets inconsistency is almost inevitable. To avoid having regular shout matches and knive fights over syntactical correctness one could use stylelint to provide everyone with concrete feedback about possible formatting problems.
  • stylelint-selector-bem-pattern: This incorporates postcss-bem-linter as a stylelint plugin, which integrates the feedback in the other stylelint hints. What this actually does is, that it checks the naming conventions for adherence to the BEM or SUIT naming patterns, which is great for bringing structure to your stylesheets.
  • CSSStats via gulp-cssstats: This enables useful statistics about your css files. While I don’t recommend adding this to your default build routine, this is very useful as a separate action.

Conclusion

There aren’t that many game-changing advantages to be had in switching from SASS to the PostCSS equivalent. It is a good thing to rely on and get used to the proposed next-generation CSS syntax, but it is still mainly a cosmetic choice as the syntax rarely provides more features than SASS and “native” browser support is still very patchy (and will be for possibly years to come).

The true power in PostCSS lies in its extensibility. Writing your own plugins is easy and PostCSS is a great platform for others to provide useful plugins. The individual plugins also seem to be a little more active than SASS as a whole.

As you can easily combine the two technologies I would recommend adding a few PostCSS plugins (at the very least autoprefixer) to your existing SASS workflow and adopt a more complete approach when you start a new project from scratch.

If you have any pointers or questions, I’m happy to hear from you on twitter.