The Exciting PostCSS
From Sass to PostCSS
About a year ago, PostCSS started surging in popularity within the front-end ecosystem. The reasons were obvious: preprocessor-like features, highly customizable plugins, early access to cssnext capabilities, and effortless integration with build tools (Gulp, Webpack), making everyday development a breeze.
Variables
When I first encountered PostCSS, I was quite excited, but I soon caught myself wondering: “Is it really necessary to replace Sass right away?”
The advantage of PostCSS is that you can pick and choose only the plugins you need, using them on demand. Take variables, for example: postcss-simple-vars can simulate Sass variable declarations and usage. Yet to me, it still feels awkward. Beyond standard variable declarations, Sass provides data types like maps and lists, along with a comprehensive suite of API operations—such as retrieving values, conditionals, and loops.
$colors: (
main: #abc,
sub: #bac,
word: #333,
);
.container {
background-color: map-get($colors, $main);
color: map-get($colors, word);
}
Even using CSS spec var() leads to the same limitation—there is no feature for querying maps or lists.
:root {
--wordColor: #333;
--bgColor: #fafafa;
}
body {
background-color: var(--wordColor);
color: var(--bgColor);
}
(Internal monologue: And writing it this way is kind of uglyreally ugly.)
Alternatively, Sass’s @function can wrap map-get even further:
$colors: (
main: #abc,
sub: #bac,
word: #333,
);
/* alias method for getting color from $colors map
/// @param {$key} the key you want to choose
///
/// eg:
color: c($word);
*/
@function c($key) {
@if map-has-key($colors, $key) {
@return map-get($colors, $key);
} @else {
@error "Unknown key #{$key}";
}
}
.container {
background-color: map-get($colors, $main);
color: map-get($colors, word);
}
Because the PostCSS ecosystem is vast and fragmented, many plugins from independent developers might be unmaintained or contain subtle bugs leading to compilation errors. By contrast, Sass’s built-in feature set is far more complete.
Mixins and Functions
The corresponding plugins are postcss-mixins and postcss-functions.
While they simulate mixin behavior, combining them with conditionals takes quite a bit of extra effort:
@mixin state($state,$namespace: '') {
@if ($namespace != ''){
.#{$namespace}-#{$state} {
text-transform: uppercase;
}
}
@else {
.${state} {
text-transform: uppercase;
}
}
}
The same goes for functions. If you write plain CSS paired with PostCSS, you can’t use Sass’s native functions. While defining custom functions in JavaScript is undeniably appealing, if you want to replicate Sass’s built-in functions, you end up having to reinvent the wheel, which becomes rather tedious.
Still Immature Compared to Sass
Compared to Sass, PostCSS is still a relatively young tool. Although its ecosystem is broad and plugins are abundant, versions are still changing rapidly, and many issues remain unresolved. Because the original Sass was written in Ruby, its performance is slower than PostCSS (okay, probably a lot slower), but its stability, well-rounded API, type system, and syntax are levels PostCSS has yet to reach.
The Advantages of PostCSS
Now, let’s talk about the advantages of PostCSS! Currently, my favorite tools to pair it with are Autoprefixer and cssnano.
Autoprefixer handles tedious CSS vendor prefixes for you. In the past, we resolved this with mixins; now, delegating it entirely to PostCSS produces much cleaner, simpler code. Meanwhile, cssnano takes care of CSS minification. Combined with Gulp, you can compile and minify your CSS simply by installing the necessary plugins.
Besides the plugins mentioned above, here are a few others I find great:
postcss-sorting: Sorts your CSS properties according to defined rulesprecss: Bundles many Sass-like featuresstylelint: Lints your CSSstylefmt: Formats your CSS code according to stylelint rulesdoiuse: Checks browser support for your CSS features- livereload: Under the power of Webpack,
css-loadercomes with hot reload pre-configured, applying newly modified styles instantly without a page refresh.
Why I’m Hesitant to Leave Sass
PostCSS is undeniably convenient, but running both together doesn’t necessarily streamline day-to-day development. Whenever an error occurs, you have to spend time debugging the underlying pipeline. It’s possible that PostCSS outputs code that causes Sass compilation to throw errors, or a plugin bug might prevent a file from compiling fully, causing chunks of CSS to silently fail. These are all real risks. In my current workflow, I only use autoprefixer, cssnano, and stylelint to help simplify and inspect my CSS.
Conclusion
Perhaps PostCSS will eventually surpass Sass completely. However, Sass’s mature, well-architected syntax is the main reason I’m hesitant to go all-in on PostCSS just yet. When PostCSS reaches the point where it can stand fully independent of Sass, I might make the switch—just like when I first learned CSS and hesitated for a long time before finally picking up Sass. That said, the two (Sass and PostCSS) can certainly coexist and complement each other.
While enjoying the extreme flexibility of PostCSS, we must also be mindful of leaky abstractions—plugins may break over time as specifications evolve or when authors abandon maintenance. Individually, these plugins may seem trivial, but collectively they save a massive amount of time. On the other hand, while Sass’s comprehensive syntax and variable system require an initial learning curve, they offer a unified, consistent syntax that dramatically improves CSS maintainability.
In this era where componentization thrives, front-end development is shifting toward maintaining modular files (React, CSS Modules, etc.). In the end, we might not even need such complex machinery (referring to Sass functions, variables, etc.) and may return to plain, vanilla CSS after all.
References
Related Posts
- Recreating My Room with Three.js Using React Three Fiber, I brought my real room into the browser—turning physical objects into an interactive table of contents, and using spatial memory to tell the story of my life and work over the past few years.
- Things to Keep in Mind When Using Images in Frontend Development Expanding on Jake Archibald's article, this post organizes how modern responsive images should be written: why width/height are still necessary, when to use CSS aspect-ratio, how to choose between AVIF and WebP, and using picture/source/srcset for art direction on mobile devices.
- CSS field-sizing — Auto-resize Form Elements with a Single Line of CSS Previously, auto-resizing a textarea required listening to scrollHeight in JavaScript. With CSS field-sizing: content, a single line replaces it all, supporting textarea, input, and select. This article covers the pain points of older approaches and how to use field-sizing.
- Make Your Link Underlines Look Better: text-underline-offset By default, underlines sit very close to the text. Some designers dislike this look, and personally, I don't think it looks great either.