· 6分で読了

期待が高まる PostCSS

この記事は中国語から自動翻訳されたものです。翻訳によりニュアンスが失われている場合があります。

SASSからPostCSSへ

およそ1年前、PostCSSはフロントエンドのエコシステムで急速に人気を集め始めた。その理由は、いわゆるプリプロセッサとしての特性、プラグインの高度なカスタマイズ性、cssnextの機能を先取りして使える点、そして各種ビルドツール(gulp、webpack)と組み合わせて非常に手軽に扱える点にある。

変数

最初にPostCSSを見たときはかなりワクワクしたものの、すぐに「本当に今すぐSASSを置き換える必要があるのだろうか?」と考え直した。

PostCSSの利点は、必要なプラグインを選んで必要なときにだけ使える点にある。例えば変数の機能を挙げると、postcss-simple-vars はSASSの変数宣言や利用の挙動を模倣できる。しかし僕からすると、どうしても違和感を覚えてしまう。なぜなら、SASSには変数の宣言だけでなく、mapやlistといった型が存在し、値の取得、条件分岐、ループ機能などの非常に充実したAPIが備わっているからだ。

$colors: (
  main: #abc,
  sub: #bac,
  word: #333,
);

.container {
  background-color: map-get($colors, $main);
  color: map-get($colors, word);
}

CSS仕様のvarを使ったとしても同様で、mapやlistから値を取得する機能はない。

:root {
  --wordColor: #333;
  --bgColor: #fafafa;
}

body {
  background-color: var(--wordColor);
  color: var(--bgColor);
}

(心の声:それに、こう書くのは正直ちょっとダサいかなりダサい)

あるいは、SASSの @function を使えば map-get をさらにラップすることもできる。

$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);
}

PostCSSのエコシステムが広大であるがゆえに、個人開発者によるプラグインの多くはメンテナンスが放置されていたり、不注意によってコンパイルエラーや細かなバグが発生したりする可能性がある。それに対して、SASS自身が持つ機能は遥かに完成度が高い。

mixinとfunction

対応するプラグインとしては、postcss-mixins や postcss-functions がある。

mixinの挙動を模倣しているものの、条件分岐と組み合わせて使おうとすると、また一苦労することになる。


@mixin state($state,$namespace: '') {

  @if ($namespace != ''){

   .#{$namespace}-#{$state} {

     text-transform: uppercase;

   }

  }

  @else {

    .${state} {

      text-transform: uppercase;

    }

  }

}

function についても同様で、純粋なCSSとPostCSSの組み合わせで書く場合、SASSネイティブの関数は使えない。JavaScriptで関数を自作できる点は確かに魅力的だが、SASSと同等の関数を模倣しようとすると車輪の再発明をすることになり、少々面倒に感じてしまう。

SASSに比べるとまだ成熟していない

SASSに比べれば、PostCSSはまだ比較的新しいツールだ。エコシステムは広くプラグインも多いが、現行バージョンは今も急速に変化しており、未解決のIssueも多く残されている。SASSはRubyで書かれているため(現在はDart Sassなどもあるが)、コンパイル速度はPostCSSより遅いものの(正直、かなり遅いが)、その安定性と洗練されたAPI、型システム、構文は、PostCSSがまだ到達できていない領域にある。

PostCSSの強み

PostCSSの強みについても触れておこう!現在僕が組み合わせて使うのが一番気に入っているのは、autoprefixerとcssnanoだ。

autoprefixerは面倒なベンダープレフィックスの付与を肩代わりしてくれる。かつてはmixinを使って解決していたが、今では完全にPostCSS任せにできるため、コードがはるかにクリーンでシンプルになった。cssnanoはCSSのminifyを行ってくれるため、gulpと組み合わせる場合は gulp-postcss、gulp-cssnano、gulp-sass などを導入するだけで、CSSのコンパイルから最小化までをスムーズに実行できる。

上記のプラグイン以外にも、素晴らしいプラグインが揃っている:

  • postcss-sorting:定義したルールに従ってCSSプロパティをソートする
  • precss:SASSライクな機能を多数搭載している
  • stylelint:CSSのLintを行う
  • stylefmt:stylelintのルールに従ってCSSコードをフォーマットする
  • doiuse:現在のCSSのブラウザ対応状況を検出する
  • livereload:webpackの強力なエコシステムと組み合わせれば、css-loader自体がHot Reloadの設定を処理してくれるため、スタイルファイルを変更するだけでページ全体をリロードせずに新しいスタイルを適用できる。

なぜ僕はいまだにSASSから離れられないのか

PostCSSとの組み合わせは確かに非常に便利だが、日常的な開発において両方を同時に導入することが工数削減につながるとは限らない。万が一エラーが発生した場合、内部の仕組みを調査するために時間を費やす必要があるからだ。PostCSSでコンパイルした後にSASSへ渡すとエラーが出るかもしれないし、どこかのパッケージのバグによってファイルが正常にコンパイルされず、一部のCSSコードが反映されないといった潜在的な問題が常に付きまとう。そのため、現在の開発では autoprefixer、cssnano、stylelint をCSSの簡略化やチェックのために利用するにとどめている。

結論

ゆくゆくはSASSが完全にPostCSSに取って代わられる日が来るのかもしれない。しかし、SASS自身が持つ完成された成熟した設計と構文こそが、僕がPostCSSへ完全に移行することを躊躇している最大の理由だ。いつかPostCSSが成熟し、SASSから完全に独立して運用できるレベルに達したとき、僕も本格的に移行するのだろう。かつてCSSを学んでいた頃、長いあいだ躊躇した末にようやくSASSを学び始めたときのように。もっとも、この2つ(SASSとPostCSS)は共存し、互いに補り合うことが可能だ。

PostCSSの高い柔軟性というメリットを享受する以上、僕たちは「抽象化の漏れ(Leaky Abstractions)」にも目を向けなければならない。プラグインは時代の変化や作者のメンテナンス停止によってバグを引き起こす可能性があるからだ。一つひとつのプラグインの機能は小さく見えても、すべて組み合わせることで節約できる時間は非常に大きい。一方で、SASSの完成された構文や変数システムは習得に一定の時間がかかるものの、統一された構文によってCSSの保守性を大幅に引き上げてくれる。

コンポーネント化が主流となった現代において、フロントエンド開発はモジュール化されたファイル(React、CSS Modulesなど)の管理へとシフトしつつある。将来的には、それほど複雑な操作(SASSの関数や変数など)を必要とせず、最も原始的な純粋なCSSへと回帰していくのかもしれない。

reference

関連記事

他のトピックを探索