Extending Standard CSS by Preprocessors

Updated Mar 29, 2021#css#guides

CSS is simple to learn and straightforward to write, it’s fast to start but slow to scale. Based on how CSS works, we can’t expect it to be developed into a powerful programming language but to build supporting tools around it.

Over the years, community has built a great ecosystem around CSS to supercharge its capability, from preprocessors like Sass and Less to methodologies like BEM and Atomic CSS, to more recent developments like CSS-in-JS.

This post will discuss a bit about three popular pure preprocessors - Sass, Less, Stylus - and a special JavaScript tool PostCSS.

Motivation

CSS is primitive and incomplete. Building a function, reusing a definition or inheritance are hard to achieve. For bigger projects, or complex systems, maintenance is a very big problem. This is where a preprocessor can help.

A CSS preprocessor is a program that lets you generate CSS from the its own unique syntax. To use a CSS preprocessor, you must install a CSS compiler on your web server.

There are many CSS preprocessors to choose from, however most CSS preprocessors will add some features that don’t exist in pure CSS, such as mixin, nesting selector, inheritance selector, and so on.


Features Sass Less Stylus
Variables Yes Yes Yes
Nesting Yes Yes Yes
Mixins Yes Yes Yes
Extends Yes Yes Yes
Functions Yes Yes Yes
If/else Yes Mixins Yes
Loops Yes Mixins Yes
Math Yes Yes Yes
Import Yes Yes Yes

Many of the features offered are incredibly similar across preprocessors, with only slight variances in syntax. Thus, you can choose pretty much any you wish, and will be able to achieve the same things. Using preprocessors brings you many benefits to boost your productivity:

  • Write less code overall
  • Make your CSS even more modular
  • Stay organized with nesting
  • Write reusable, maintainable, and extensible codes

Sass

Sass is the most mature, stable, and powerful preprocessor. It is completely compatible with all versions of CSS, very mature, feature rich, industry standard, large community, and has many frameworks built around.

Sass supports two different syntaxes. Each one can load the other, so it’s up to you and your team which one to choose.

  • SCSS — uses the file extension .scss, it’s a superset of CSS, which means essentially all valid CSS is valid SCSS as well. Because of its similarity to CSS, it’s the easiest syntax to get used to and the most popular.
@mixin button-base() {
  @include typography(button);
  @include ripple-surface;
  @include ripple-radius-bounded;

  display: inline-flex;
  position: relative;
  height: $button-height;
  border: none;
  vertical-align: middle;

  &:hover {
    cursor: pointer;
  }

  &:disabled {
    color: $mdc-button-disabled-ink-color;
    cursor: default;
    pointer-events: none;
  }
}
  • Sass — uses the file extension .sass. The indented syntax supports all the same features as SCSS, but it uses indentation instead of curly braces and semicolons to describe the format of the document.
@mixin button-base()
  @include typography(button)
  @include ripple-surface
  @include ripple-radius-bounded

  display: inline-flex
  position: relative
  height: $button-height
  border: none
  vertical-align: middle

  &:hover
    cursor: pointer

  &:disabled
    color: $mdc-button-disabled-ink-color
    cursor: default
    pointer-events: none

Less

Less (Leaner Style Sheets) is a backwards-compatible language extension for CSS. Because Less looks just like CSS, learning it is a breeze. Less only makes a few convenient additions to the CSS language, which is one of the reasons it can be learned so quickly.

@the-border: 1px;
@base-color: #111;
@red: #842210;

#concrete_header {
  color: @base-color * 3;
  border-left: @the-border;
  border-right: @the-border * 3;
}

#concrete_footer {
  color: @base-color + #003300;
}

Stylus

Stylus is a preprocessor developed by Holowaychuk and influenced by Sass and Less. It offers a wider range of features, a super-fast Node.js system under the hood, and gives users the most freedom in how they write their CSS.

border-radius()
  -webkit-border-radius: arguments
  -moz-border-radius: arguments
  border-radius: arguments

body
  font: 12px Helvetica, Arial, sans-serif

a.button
  border-radius(5px)

PostCSS

PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more.

PostCSS is not a pure preprocessor but you can use it that way if you wanted to by using along with plugins like postcss-sass, postcss-scss or postcss-less. After preprocessing you can also use PostCSS processing with other plugins.

PostCSS is a Node module that parses CSS into an abstract syntax tree; passes that AST through any number of plugin functions; and then converts that AST back into a string, which you can output to a file. Each function the AST passes through may or may not transform it; sourcemaps will be generated to keep track of any changes.

PostCSS is a low-level module that facilitates the creation of other tools; and there are no limits on what those higher-level tools (the plugins) might do.

Each plugin is only part of your build process because you put it there. If a plugin displeases you, remove it. Nobody is going to stop you.

The most compelling thing about PostCSS is it is not restricted to any one type of functionality; it represents a completely customizable and configurable set of functionality that is potentially unlimited.

The ecosystem of PostCSS plugins has been developing in an incredible speed. You can find all at this catalog of PostCSS plugins:

  • Solve Global CSS Problem: postcss-use, postcss-modules, postcss-initial.
  • Use Future CSS, Today: autoprefixer, postcss-preset-env.
  • Better CSS Readability: precss, postcss-sorting, postcss-utilities.
  • Images and Fonts: postcss-assets, postcss-sprites, postcss-inline-svg.
  • Linters: stylelint, stylefmt, colorguard.
  • Syntaxes: sugarss, posscss-sass, postcss-scss.
  • Miscellaneous: postcss-rtl, cssnano, lost.

PostCSS is well supported by all kinds of bundlers and task runners like: Parcel, Webpack, Gulp, Grunt, Rollup, etc.

// Simple setup with Gulp task runner

gulp.task(css, () => {
  const postcss = require('gulp-postcss')
  const sourcemaps = require('gulp-sourcemaps')

  return gulp
    .src('src/**/*.css')
    .pipe(sourcemaps.init())
    .pipe(postcss([require('precss'), require('autoprefixer')]))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('build/'))
})

Conclusions

Whether you like preprocessors or not, they were created for a reason of making your life easier in some ways. By far Sass is the most adopted preprocessor out there in tech industry, knowing it thoroughly will give you a big advantage as frontend developer.

CSS is simple to learn and straightforward to write, it’s fast to start but slow to scale, you probably don’t know that you’re already using CSS preprocessors cooked in built tools.

With the rise of PostCSS, my decisions have been shifted from whether to use CSS preprocessors or not to what problems I want to solve with CSS.