From SASS to PostCSS
About a year ago, PostCSS started gaining popularity in the frontend ecosystem. It offers features like a preprocessor, highly customizable plugins, the ability to use cssnext functionality, and seamless integration with various build tools (gulp, webpack), making it a breeze to work with.
Variables
Although I was initially excited when I first encountered PostCSS, I started to question whether it was really necessary to immediately replace SASS.
The advantage of PostCSS lies in its ability to choose the plugins you need and use them when necessary. Let's take variables as an example. postcss-simple-vars can simulate the variable declaration and usage behavior of SASS. However, it feels a bit awkward to me because SASS not only allows variable declarations, but also supports map and list types, along with a comprehensive set of API operations such as value retrieval, conditionals, and loops.
$colors: (
main: #abc,
sub: #bac,
word: #333,
);
.container {
background-color: map-get($colors, $main);
color: map-get($colors, word);
}
Even when using CSS spec's var, it lacks the ability to retrieve values from a map or list.
:root {
--wordColor: #333;
--bgColor: #fafafa;
}
body {
background-color: var(--wordColor);
color: var(--bgColor);
}
(Oh, and writing it like this is actually a bit uglyvery ugly)
Alternatively, SASS's @function can further wrap the map-get
function.
$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);
}
Due to the extensive ecosystem of PostCSS, plugins developed by independent developers may not be well-maintained or may have small bugs due to negligence. In comparison, SASS itself has a more complete set of features.
Mixins and Functions
Corresponding plugins for mixins are postcss-mixins and postcss-functions.
Although they can simulate mixin behavior, using them with conditionals requires some extra effort.
@mixin state($state,$namespace: '') {
@if ($namespace != ''){
.#{$namespace}-#{$state} {
text-transform: uppercase;
}
}
@else {
.${state} {
text-transform: uppercase;
}
}
}
As for function
, if you're using pure CSS with PostCSS, you can't use SASS's native functions. Although you can define custom functions using JavaScript, it can be quite cumbersome to simulate the corresponding SASS functions.
Less mature compared to SASS
Compared to SASS, PostCSS is still a relatively new tool. Although it has a wide ecosystem and many plugins, the current version is still undergoing rapid changes, and there are still many unresolved issues. SASS, on the other hand, is written in Ruby and may be slower (well, probably much slower) but it offers a stable and comprehensive API, along with a complete syntax that PostCSS has yet to achieve.
Advantages of PostCSS
Let's talk about the advantages of PostCSS! Currently, my favorite features to use in combination with it are autoprefixer and cssnano.
Autoprefixer takes care of the hassle of CSS prefixes. Previously, mixins were used to solve this, but now it can be handled entirely by PostCSS, resulting in cleaner and more concise code. cssnano, on the other hand, helps with CSS minification. By using gulp and installing gulp-postcss, gulp-cssnano, and gulp-sass, you can easily compile and minify CSS.
In addition to the above plugins, some other great plugins include:
postcss-sorting
: Sorts your CSS properties according to defined rules.precss
: Includes many Sass-like features.stylelint
: Lints your CSS.stylefmt
: Formats CSS code according to stylelint rules.doiuse
: Detects browser support for CSS properties.- livereload: With the power of webpack, css-loader already sets up hot reload configuration for you. Whenever you make changes to style files, the new styles are applied without having to reload the page.
Why I'm hesitant to leave SASS
Although it is very convenient to use PostCSS, I don't think using both simultaneously reduces the daily development effort. After all, once something goes wrong, you have to spend time investigating the underlying mechanisms. It is possible that there may be errors when SASS compiles the code after PostCSS compilation, or a bug in a package may result in incomplete compilation and certain CSS code not taking effect. These are potential issues. Currently, I only use autoprefixer
, cssnano
, and stylelint
to simplify and check CSS.
Conclusion
Perhaps SASS will eventually be completely overtaken by PostCSS, but the comprehensive and mature architecture and syntax of SASS are the main reasons why I am not ready to completely switch to PostCSS. When PostCSS becomes mature enough to be completely independent of SASS, I might consider making the switch, just like when I hesitated to start learning SASS when I was initially learning CSS. However, these two (SASS, PostCSS) can coexist and complement each other.
Since we enjoy the flexibility of PostCSS, we also need to be concerned about abstraction penetration, as plugins may have errors due to changes in the times or the lack of maintenance by developers. Although these plugins may seem small in functionality, the time saved by using them collectively can be significant. On the other hand, SASS's complete syntax and variable system, although requiring some time to learn, can greatly improve CSS maintainability with a unified syntax.
In this era of componentization, frontend development is gradually moving towards maintaining modular files (e.g., React, CSS modules), and in the end, there may not be a need for such complex operations (referring to SASS functions, variables, etc.), and we may return to the basics of pure CSS.