kanke

SassとPostCSSを組み合わせて作るCSS開発環境

突然ですが、僕はずっとPostCSSを誤解していました…
このたび晴れて誤解が解けたので、記念に記事を書きたいと思います。

Sassの代わりではない

はい、これです。
この記事で言いたいことは、これがほぼ全てです。

僕は、PostCSSを、コンパイルしてCSSを生成するSassのようなものだと思っていました!
ですが、そもそもSassを使っていたので全くと言っていいほど必要性を感じてませんでした。

PostCSSは自分で必要な機能だけを選べるからカスタマイズ性がある!楽しい!軽い!
とか言われても、Sass遅くないし、むしろ必要な機能を選んで構成するのがめんどくさいと思ってました。というか今も思ってます。

ポストプロセッサーとしてのPostCSS

PostCSSというくらいなので、ポストプロセッサーとして、生成されたCSSに対して後処理をすることに使えます。
(導入するプラグインによっては、Sassのようなプリプロセッサー的な使い方も出来ます)

そのため、使い慣れているSassでコードを書きつつ、コンパイル後のCSSの最適化にPostCSSの様々なプラグインを使用するといったことが可能です!

そんなことに今更ながら気づき、Sass + PostCSSでCSSの開発環境を構築したので紹介します!

今回のデモはGithubにアップしています。
何をやっているかを、この記事で詳しく紹介していきますので、興味が湧いた方はぜひ触ってみてください。

ちなみにこの記事ではPostCSSについては詳しくは説明しないので、気になる方はmorishitterさんのこちらの記事をどうぞ。

環境準備

とりあえず、GulpでSassとPostCSSが使える環境をサクッと構築します。
今回は、以下の環境で動作の確認をしました。

  • OS: macOS Sierra
  • Node: 8.9.0

まず、以下のコマンドでパッケージをインストール。

$ npm i gulp gulp-sass gulp-postcss -D 

gulpはこんな感じです。

const gulp = require('gulp'); 
const sass = require('gulp-sass'); 
const postcss = require('gulp-postcss'); 

gulp.task('css', function () { 
  return gulp.src('./src/*.scss') 
    .pipe(sass({ 
      outputStyle: 'expanded' 
    })) 
    .pipe(gulp.dest('./dest/')); 
}); 

とりあえず、これでSassのコンパイルができる環境ができました!

ここから、PostCSSのプラグインを入れていきます!

今回は、5個のプラグインを導入したので順に紹介していきます。

autoprefixer

もう説明不要ですね。これが

.foo {
  display: flex;
}

こうなります。

.foo {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
}

npmでプラグインをインストールします。

$ npm i autoprefixer -D 

gulpfile.js でSassのコンパイル処理後に続けてPostCSSの処理を書いていきます。

postcss() の引数に使用するプラグインを配列で指定してあげればOKです。
ハイライトされているのが追加したコードです。

const gulp = require('gulp');
const sass = require('gulp-sass');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');

gulp.task('css', function () {

  const plugin = [
    autoprefixer({
      browsers: [
        'last 2 versions'
      ]
    })
  ];

  return gulp.src('./src/*.scss')
    .pipe(sass({
      outputStyle: 'expanded'
    }))
    .pipe(postcss(plugin))
    .pipe(gulp.dest('./dest/'));
});

以下のコマンドでタスクを実行します。

$ gulp css

ベンダープレフィックス付きのCSSが生成されればOKです!

参考:autoprefixer npm

css-declaration-sorter

CSSのプロパティの順番を良い感じに並び替えてくれるプラグインです。

アルファベット順や smacss のルールに沿った順番などが選べます。

これが

.bar {
  color: #C55;
  display: block;
  border: 0;
  padding: 20px;
}

こうなります。

.bar {
  display: block;
  padding: 20px;
  border: 0;
  color: #C55;
}

今まで、 csscomb で自分で並び順など設定してましたが乗り換えることにしました。

npmでインストール。

$ npm i css-declaration-sorter -D 

使用するには、gulpfile.js 内でプラグインを読み込んで、先ほどのプラグインの配列に足していけばOKです。

const gulp = require('gulp');
const sass = require('gulp-sass');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssDeclarationSorter = require('css-declaration-sorter');

gulp.task('css', function () {

  const plugin = [
    autoprefixer({
      browsers: [
        'last 2 versions'
      ]
    }),
    cssDeclarationSorter({
      order: 'smacss'
    })
  ];

  return gulp.src('./src/*.scss')
    .pipe(sass({
      outputStyle: 'expanded'
    }))
    .pipe(postcss(plugin))
    .pipe(gulp.dest('./dest/'));
});

参考:css-declaration-sorter npm

css-mqpacker

同じメディアクエリーをまとめてくれるプラグイン。
生成されるCSSの容量削減が期待できます。

これが

.hoge {
  width: 240px;
}

@media screen and (min-width: 768px) {
  .hoge {
    width: 576px;
  }
}

.fuga {
  width: 160px;
}

@media screen and (min-width: 768px) {
  .fuga {
    width: 384px;
  }
}

こうなります。

.hoge {
  width: 240px;
}

.fuga {
  width: 160px;
}

@media screen and (min-width: 768px) {
  .hoge {
    width: 576px;
  }
  .fuga {
    width: 384px;
  }
}

npmでインストール。

$ npm i css-mqpacker -D 

gulpfile.js に足してあげます。

const gulp = require('gulp');
const sass = require('gulp-sass');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssDeclarationSorter = require('css-declaration-sorter');
const mqpacker = require("css-mqpacker");

gulp.task('css', function () {

  const plugin = [
    autoprefixer({
      browsers: [
        'last 2 versions'
      ]
    }),
    cssDeclarationSorter({
      order: 'smacss'
    }),
    mqpacker()
  ];

  return gulp.src('./src/*.scss')
    .pipe(sass({
      outputStyle: 'expanded'
    }))
    .pipe(postcss(plugin))
    .pipe(gulp.dest('./dest/'));
});

参考:css-mqpacker npm

cssnano

定番ですがCSSの圧縮をしてくれます。

npmでインストールして

$ npm i cssnano -D 

gulpfile.js に足せばOKです。

const gulp = require('gulp');
const sass = require('gulp-sass');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssDeclarationSorter = require('css-declaration-sorter');
const mqpacker = require("css-mqpacker");
const cssnano = require("cssnano");

gulp.task('css', function () {

  const plugin = [
    autoprefixer({
      browsers: [
        'last 2 versions'
      ]
    }),
    cssDeclarationSorter({
      order: 'smacss'
    }),
    mqpacker(),
    cssnano({ autoprefixer: false })
  ];

  return gulp.src('./src/*.scss')
    .pipe(sass({
      outputStyle: 'expanded'
    }))
    .pipe(postcss(plugin))
    .pipe(gulp.dest('./dest/'));
});

autoprefixerの機能もついているらしいのですが、autoprefixerは既に実行された状態なので、ここでは実行されないように false にします。
前後のコードはのせませんが、実行するとminifyしたCSSを生成してくれます。

参考:cssnano npm

stylelint

最後にCSS用のLintツールのstylelintを導入しました。

これは今まで紹介したものと違って、実際にコーディングするScssファイルのチェックをしてほしいので、Sassでコンパイルする前に実行されるようにします。

npmでインストールします。stylelintのプラグインだけではなく、CUIにLintの結果を表示するために postcss-reporter も必要なので一緒にインストールします。

$ npm i stylelint postcss-reporter -D 

gulpfile.js で、Sassが実行される前に追加してあげます。

const gulp = require('gulp');
const sass = require('gulp-sass');
const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssDeclarationSorter = require('css-declaration-sorter');
const mqpacker = require("css-mqpacker");
const cssnano = require("cssnano");
const stylelint = require('stylelint');
const reporter = require('postcss-reporter');

gulp.task('css', function () {

  const plugin = [
    autoprefixer({
      browsers: [
        'last 2 versions'
      ]
    }),
    cssDeclarationSorter({
      order: 'smacss'
    }),
    mqpacker(),
    cssnano({ autoprefixer: false })
  ];

  return gulp.src('./src/*.scss')
    .pipe(postcss([
      stylelint(),
      reporter()
    ]))
    .pipe(sass({
      outputStyle: 'expanded'
    }))
    .pipe(postcss(plugin))
    .pipe(gulp.dest('./dest/'));
});

Lintのルールはプロジェクトルートに .stylelintrc を作成して記述します。

Lintのルールを一から書くのはめんどくさいので、既存のルールセットがいくつも公開されているので、今回はその中の stylelint-config-standard というルールセットをベースに作ってみました。

他のルールセットはstylelint-configのタグから探せます。

stylelint-config-standard もnpmでインストールします。

$ npm i stylelint-config-standard  -D 

インストールできたら .stylelintrc を作成します。

{
  "extends": "stylelint-config-standard",
  "rules": {
    "at-rule-no-unknown": [ true, {
      ignoreAtRules: [
        'extend', 'at-root', 'debug',
        'warn', 'error', 'if', 'else',
        'for', 'each', 'while', 'mixin',
        'include', 'content', 'return', 'function'
      ]
    }],
    "no-invalid-double-slash-comments": null
  }
}

extendsstylelint-config-standard を指定してルールを継承します。
また、このままだとSassの、// のコメントや @mixin の書き方がエラーになってしまうので、そのルールを上書きします。

これで実行すると…

怒られました。ちゃんと実行されますね!

参考: ここがすごいぞ! stylelint!

まとめ

社内で聞くと、僕と同じ勘違いをしている人が数人いたので、他にもいるんじゃないかと思って書いてみました。

今回紹介したプラグイン以外にもPostCSSの便利なプラグインはたくさんあると思うので、色々探してみようと思います。
自分で作ることもできるようなので、機会があればプラグインを作ったりもしてみたいと思います!

新しいウェブ体験を作ろう TAMのPWA開発
お問い合わせはこちら