HTML & CSS
Article
By Craig Buckler

7 PostCSS Plugins to Ease You into PostCSS

By Craig Buckler

We’ve featured PostCSS many times before on SitePoint, yet it continues to confuse many. To summarize it in one sentence:

PostCSS handles tedious jobs so you don’t have to.

It is subtly different to a pre-processor such as Sass, Less and Stylus which provide an alternative, more concise programming language which compiles to CSS. Part of the confusion is caused by:

  • Its name. PostCSS can perform actions on files either before and/or after a pre-processor has compiled its source code to real CSS.

  • PostCSS could replace your pre-processor. There are plugins which implement constructs such as variables, nesting, mixins and extends.

However, while you can build your own pre-processor, there’s little reason to do so unless you want to limit the functionality and increase compilation speed. Personally, I use Sass followed by a sprinkling of PostCSS seasoning to enhance my CSS.

How Do You Use PostCSS?

PostCSS can be used within standalone JavaScript files, Gulp, Grunt, Broccoli, Brunch and a wide range of task runners I’ve never heard of!

On its own, PostCSS does nothing but parse a CSS file into JavaScript objects and tokens. The real magic happens with plugins which examine, manipulate, add or change properties and values before the final CSS file is written.

To use PostCSS in Gulp, you need to set-up your project then install both modules:

npm init
npm install --save-dev gulp gulp-postcss

You can then add the plugins you require, e.g. autoprefixer and cssnano:

npm install --save-dev autoprefixer cssnano

A gulpfile.js can be created. It defines a task which loads the CSS source and pipes it through PostCSS. Plugins and any required options are passed to PostCSS in an array. Finally, the CSS is output to a destination file:

// Gulp.js configuration
var gulp = require('gulp'),
    postcss = require('gulp-postcss');

// apply PostCSS plugins
gulp.task('css', function() {
  return gulp.src('src/main.css')
    .pipe(postcss([
      require('autoprefixer')({}),
      require('cssnano')
    ]))
    .pipe(gulp.dest('dest/main.css'));
});

The task can be run from the console with:

gulp css

All we need now is a handy list of PostCSS plugins…

1. Autoprefixer

If you use nothing else, install Autoprefixer:

npm install --save-dev autoprefixer

Browser-specific prefixes such as -webkit-, -moz- and -ms- are gradually dying out as standards become better supported and vendors opt for alternatives such as flag-based property enabling. Unfortunately, you cannot avoid vendor prefixes but it’s difficult to know when they’re always required, (e.g. for user-select), sometimes required (e.g. for 3D transformations), or never required (e.g. border-radius).

You need never worry about prefixing again with Autoprefixer. You just need to define non-prefixed CSS, then state which browsers you want to support. Autoprefixer will check caniuse.com before adding the necessary prefixes — the following code specifies the last two versions of any mainstream browser, or any exceeding 2% market share:

.pipe(postcss([
  require('autoprefixer')({
    browsers: ['last 2 versions', '> 2%']
  })
]))

This is a superior option to pre-processor library functions which normally require special coding and apply vendor prefixes regardless. Your prefixed code will be removed in future PostCSS runs as browser standards evolve.

Autoprefixer is so useful and widespread, it is possible you’re already using without realizing it is a PostCSS plugin.

2. PostCSS Assets

PostCSS Assets provides a number of useful image-handling functions:

npm install --save-dev postcss-assets

The options include:

  • URL resolution: Given a file name, PostCSS Assets replaces resolve(image) with a root path or fully-qualified URL.
  • Dimension handling: PostCSS Assets replaces references to width(image), height(image) or size(image) with a pixel equivalent.
  • Image inlining: PostCSS Assets replaces inline(image) with a Base64-encoded string.
  • Cache-busting: PostCSS Assets can append a random query string to an image reference to ensure the latest file is loaded.

3. cssnext

cssnext allows you to use the latest CSS syntax today.

npm install --save-dev postcss-cssnext

The plugin has a long list of features including support for:

  • var variables
  • #rrggbbaa colors
  • Color functions
  • Filters
  • Fallbacks

When it executes, cssnext translates code to a syntax commonly supported in today’s browsers.

4. Rucksack

Rucksack offers a range of functions which, the developer claims, makes CSS development fun again!

npm install --save-dev rucksack-css

Options include:

  • Responsive typography which adjusts font sizes and line heights with a single font-size: responsive declaration.
  • Quantity pseudo-selectors such as li:at-least(4) which targets any list with four or more items.
  • Property aliases such as defining bg as background which can be used throughout your CSS.
  • A set of pre-defined easing functions.

5. Stylelint

Stylelint reports CSS errors based on 140 rules designed to catch common mistakes, implement style conventions and enforce best practices. There are many options to configure Stylelint to your liking — Pavels Jelisejevs’ article Improving the Quality of Your CSS with PostCSS walks you through the set up process.

6. CSS MQPacker

MQPacker optimizes your media queries into single rules when possible:

npm install --save-dev css-mqpacker

Pre-processors such as Sass make it easy to use media queries within a declaration, e.g.

.widget1 {
  width: 100%;

  @media (min-width: 30em) {
    width: 50%;
  }

  @media (min-width: 60em) {
    width: 25%;
  }
}

.widget2 {
  width: 100px;

  @media (min-width: 30em) {
    width: 200px;
  }
}

This compiles to:

.widget1 { width: 100%; }

@media (min-width: 30em) {
  .widget1 { width: 50%; }
}

@media (min-width: 60em) {
  .widget1 { width: 25%; }
}

.widget2 { width: 100px; }

@media (min-width: 30em) {
  .widget2 { width: 200px; }
}

To reduce file sizes and (possibly) improve parsing times, MQPacker packs multiple declarations into one @media rule, i.e.

.widget1 { width: 100%; }
.widget2 { width: 100px; }

@media (min-width: 30em) {
  .widget1 { width: 50%; }
  .widget2 { width: 200px; }
}

@media (min-width: 60em) {
  .widget1 { width: 25%; }
}

Hot tip: ensure the first media query declaration in your code defines all possible options in the order you want them even if there’s no actual difference. This guarantees MQPacker will define rules in the correct order.

MQPacker also provides options for sorting media queries and outputting source maps.

7. cssnano

cssnano compacts your CSS file to ensure the download is as small as possible in your production environment. Install it via:

npm install --save-dev cssnano

The plugin works by removing comments, whitespace, duplicate rules, outdated vendor prefixes and making other optimizations to typically save at least 50%. There are alternative options but cssnano is one of the best. Use it!

Want More?

A searchable index of PostCSS plugins is available at postcss.parts and the PostCSS usage documentation provides a list of recommended options. You’ll find plugins for almost any CSS task you can imagine although be aware there is some cross-over and duplication — for example, cssnext also includes Autoprefixer.

If that’s not enough, you can develop your own PostCSS plugins in JavaScript. The PostCSS documentation explains how to write a plugin and provides an API reference.

PostCSS makes CSS development easier regardless of whether you use a pre-processor. The CSS development time it saves more than outweighs the initial installation and configuration effort.

  • Craig Buckler

    PreCSS is good but you cannot necessarily expect all SCSS files to work.

    An alternative is node-sass: https://github.com/sass/node-sass – a Node wrapper for the fast libsass C++ executable which is closer to the Ruby implementation of Sass.

    • xwero

      Currently precss is not a one on one replacement for sass, that’s for sure.

      The point i was trying to make is that it’s javascript, not another language. Most problems I experienced with frontend development had to do with using other languages.

      • Craig Buckler

        Understood. But, if you need an (almost) one-to-one non-Ruby version of Sass, node-sass is the way to go for now. PostCSS will almost certainly get there eventually, though – and it’ll allow you to add additional syntaxes.

Recommended
Sponsors
Get the latest in Front-end, once a week, for free.