Web developers love the Sass CSS preprocessor. According to the Sass opinions in the State of CSS Survey, every developer knows what it is, 89% use it regularly, and 88% have high satisfaction.
Many web bundlers include Sass processing, but you may also be using PostCSS without realizing it. PostCSS is primarily known for its Autoprefixer plugin, which automatically adds
-ms vendor prefixes to CSS properties when required. Its plugin system means it can do so much more … such as compiling
.scss files without having to use the Sass compiler.
This tutorial explains how to create a custom CSS preprocessor which compiles Sass syntax and supplements it with further features. It’s ideal for anyone with specific CSS requirements who knows a little Node.js.
An example PostCSS project can be cloned from GitHub. It requires Node.js, so run
npm install to fetch all dependencies.
Compile the demonstration
src/scss/main.scss source code to
npm run css:dev
Auto-compile whenever files are changed using:
npm run css:watch
Then exit watching by pressing Ctrl | Cmd + C in the terminal.
Both options also create a source map at
build/css/main.css.map, which references the original source files in the developer tools.
Production-level minified CSS without a source map can be compiled using:
npm run css:build
Refer to the
README.md file for further information.
Should You Replace Sass with PostCSS?
There’s nothing wrong with the Sass compiler, but consider the following factors.
The latest Dart version of Sass can be installed globally using the Node.js
npm package manager:
npm install -g sass
.scss code with:
sass [input.scss] [output.css]
Source maps are automatically generated (
--no-source-map will switch them off) or
--watch can be added to auto-compile source files when they change.
The latest version of Sass requires less than 5MB of installation space.
PostCSS should require fewer resources and a basic Sass-like compiler with auto-prefixing, and minification needs less than 1MB of space. In reality, your
node_modules folder will expand to more than 60MB and increase rapidly as more plugins are added. This is mostly
npm installing other dependencies. Even though PostCSS may not use them, it can’t be considered as a lightweight alternative.
However, if you’re already using PostCSS for Autoprefixer or other purposes, Sass may not be necessary.
The slow, Ruby-based Sass compiler has long gone and the latest edition uses a compiled Dart runtime. It’s fast.
However, this speed difference will be less noticeable if you’re already running PostCSS after Sass. A two-stage process can be slower than using PostCSS alone, since much of its work involves tokenizing CSS properties.
The Sass language includes a large set of features including variables, nesting, partials, mixins, and more. There are downsides:
You cannot easily add new features.
Perhaps you’d like an option convert HSLA colors to RGB. It may be possible to write a custom function, but other requirements will be impossible — such as inlining an SVG as a background image.
You can’t easily restrict the feature set.
Perhaps you’d prefer your team not to use nesting or
@extend. Linting rules will help, but they won’t stop Sass compiling valid
PostCSS is considerably more configurable.
PostCSS can be used with webpack, Parcel, Gulp.js, and other build tools, but this tutorial shows how to run it from the command line.
If necessary, initialize a new Node.js project with
npm init. Set up PostCSS by installing the following modules for basic
.scss parsing with plugins for partials, variables, mixins, nesting, and auto-prefixing:
npm install --save-dev postcss postcss-cli postcss-scss postcss-advanced-variables postcss-nested autoprefixer
Like the example project, PostCSS and its plugins are installed locally. This is a practical option if your projects are likely to have differing compilation requirements.
postcss-cli module provides a wrapper that can be called from the command line. The postcss-scss module allows PostCSS to read
.scss files but doesn’t transform them.
Autoprefixer uses browserslist to determine which vendor prefixes are required according to your list of supported browsers. It’s easiest to define this list as a
"browserslist" array in
package.json. The following example adds vendor prefixes where any browser has at least 2% market share:
"browserslist": [ "> 2%" ],
Your First Build
You’ll typically have a single root Sass
.scss file which imports all required partial/component files. For example:
// root Sass file // src/scss/main.scss @import '_variables'; @import '_reset'; @import 'components/_card'; // etc.
Compilation can be started by running
npx postcss, followed by the input file, an
--output file, and any required options. For example:
npx postcss ./src/scss/main.scss --output ./build/css/main.css --env development --map --verbose --parser postcss-scss --use postcss-advanced-variables postcss-nested autoprefixer
- outputs to
- sets the
NODE_ENVenvironment variable to
- outputs an external source map file
- sets verbose output and error messages
- sets the
postcss-scssSass parser, and
- uses the plugins
autoprefixerto handle partials, variables, mixins, nesting, and auto-prefixing
Optionally, you could add
--watch to auto-compile when
.scss files are modified.
How to Use PostCSS as a Configurable Alternative to Sass