CSS
postcss

PostCSS まとめ

僕はPostCSSは開発当初から追いかけていて、GitHubでPostCSSチームのメンバーのひとりだったり、実際にPostCSSを使ってプラグインやツールをいくつか作ったり、ブログや雑誌で記事を書いたり、勉強会等で話したりしています。

本記事では、自分が知っているPostCSSについての事柄を共有します。

PostCSSとは何か

PostCSSとは、ロシア人の Andrey Sitnik という人が開発している、Node.js製の「CSSツールを作るためのフレームワーク」です。PostCSS製のツールとして、ベンダープリフィックスを自動で付与する「Autoprefixer」、未来のCSSの構文の一部を今のブラウザで解釈できるようにする「cssnext」、カスタマイズ性に富んでいるCSSリンターである「stylelint」などが有名です。

PostCSSは2018年2月、かなり広く使われており、GitHubではスター数が約18000スターとなっています。PostCSSを使用している企業やサービスとして、Facebook, GitHub, Google等、日本では Qiitaで導入しています

PostCSSの仕組み

実装としてはPostCSS自体はただのCSSのパーサーで、それほど大きいコードベースではありません。

PostCSSは入力としてCSSを受け取り、それをパースし独自のASTを生成します。ASTの操作はプラグインが担当しており、PostCSS自体はCSSに対して一切変更を加えません。開発者は、PostCSSのプラグインを作ることで、独自の処理をCSSにおこなうことができます。そして、変更されたASTを文字列に戻すことで、新しいCSSを出力します。

PostCSSの処理の流れ

また、PostCSSはASTを操作するためのAPIを提供しており、これらを利用することで簡単に、効率良く変換処理を書くことができます。

PostCSS製ツール

Webアプリケーションを作る業務では、PostCSSは既存のプラグインを組み合わせて使うことが多いと思います。CSSの開発フローの中から、プリプロセス、最適化、ドキュメント作成、コードリントなどのフェーズで使うPostCSSプラグインをいくつか紹介します。

PostCSSを使うメリットのひとつは、一連のCSSのビルドフローを全てPostCSSのエコシステムで解決できるところです。

プリプロセッサーとしてのPostCSSプラグイン

まずは、プリプロセッサーとして使えるプラグインについて。PostCSSにはCustom Syntaxesという機能があり、PostCSSの"Parser"と"Stringifier"の部分もカスタマイズすることができます。既存のものとしては以下のような実装があります。

  • postcss-scss: SassのSCSS記法のパーサー
  • sugarss: インデントベースの独自記法
  • postcss-js: JSのオブジェクトとして書かれたCSSのパーサー
  • midas: シンタックスハイライター (CSSコードではなくHTMLを出力)

また、独自の@ルールやプロパティをフックして言語拡張をしているプラグインもあります。ではその中からいくつか紹介します。

postcss-custom-properties

postcss-custom-propertiesは、Custom Propertiesのシンタックスでグローバル変数定義できるようにするプラグインです。PostCSSがCSSをCSSに変換する都合上、Custom Propertiesの ポリフィルではない ので注意が必要です。下記の例のように :root セレクタのルール内でのみ定義可能です。

:root {
  --mainColor: #59bb0c;
}

.Logo {
  fill: var(--mainColor);
}

postcss-custom-media

postcss-custom-mediaは、メディアクエリーのパラメーターに名前を付けられるようにするためのPostCSSプラグインです。Custom Media QueriesはMedia Queries Level 5で載る(かもしれない)仕様です。

@custom-media --mobile (max-width: 415px);

@media (--mobile) {
  .selector {
      property: value;
  }
}

postcss-apply

CSSには複数のプロパティ宣言を組み合わせることでデザイン的な意味を持つものがあり、それに名前を付けて管理するための仕様を、Custom Sets of Propertiesといいます。この仕様はTab Atkins Jr.(CSSWGのメンバーであり、Googleのソフトウェアエンジニア。FlexboxやCustom Properties等のエディタ)という人が独自に提案しているものです。Chrome Canaryではフラグ付きで実装されています。

2018/02/27 追記: Custom Sets of Properties (@apply) は仕様から落ちました

:root {
  --truncate: {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  };
}

.text {
    @apply --truncate;
}

postcss-cssnext

上記3つのような、将来的にCSSの仕様として入る可能性のあるプラグインをまとめたものが postcss-cssnext(cssnext)です。

未来のCSSのシンタックスを書き心地を確認するのには良いものだと思います。

プリプロセッサーとしてPostCSSを使うメリット

今はSassやStylusを使っているが、「@importによるファイルの依存管理と変数定義しか使っていない」、「@mixin@extendは管理が難しいから使っていない」という人もいるのではないでしょうか。PostCSSを使うと、必要な機能だけを選択して使用することができます。その分パフォーマンスも良く、ビルドを早くすることができるでしょう。

また、PostCSSのひとつひとつのプラグインは非常に小さく、コードを読んで自分で修正、コントリビュートすることも難しくありません。自らPostCSSのプラグインを書くことによって、独自の変換処理の構文を作ることもできます。

PostCSSをプリプロセッサーとして使うメリットは以下の2点です。

  • パフォーマンス
  • カスタマイズ性

最適化のためのPostCSSプラグイン

次はブラウザが解釈可能なCSSコードを受け取り、最適化をおこなうためのプラグインを紹介します。これらのプラグインはPostCSS製のプリプロセッサーだけでなく、SassやLess、Stylusとも併用可能(プリプロセッサーの出力を入力として受け取るから)です。

Autoprefixer

AutoprefixerはPostCSSのプラグインとして最も有名なものだと思います。Can I Useのデータを利用し、サポートブラウザを指定することで、必要なベンダープリフィックスを自動で付与するツールです。

input:

.example {
  display: flex;
  user-select: none;
  -webkit-border-radius: 3px;
  border-radius: 3px;
}

output:

.example {
  display: -ms-flexbox;
  display: flex;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  border-radius: 3px;
}

cssnano

cssnanoはCSSのminifyツールです。PostCSS製のminifyツールとしては他に、CSSWringがあります。

CSSのminifyツールにも性能に差はありますが、微々たるものなので好きなもの、自分にとって信頼できるものを使うと良いと思います。

postcss-sorting

postcss-sortingはプロパティ宣言の順序をソートするためのプラグインです。CSSのプロパティ宣言の順序を揃えるのは、単にフォーマットのためだけではなく、gzip圧縮時に圧縮率を高める可能性を高める ことができます。

コードリント

CSSにおいても、JavaScriptのような一般的なプログラミング言語と同様に、コードをリントすることで、チーム開発において記述を統一することができたり、実行時のエラーを事前に防ぐことができます。今日は、PostCSS製のモダンなCSSリンターである、stylelint について説明します。

stylelintのルール

stylelintで設定できるルールの一覧を見てみましょう。

ルール名 説明
at-rule-name-case @ルール名が大文字か小文字か
color-hex-length HEX指定のカラーコードを短縮するかどうか
color-no-invalid-hex invalidなHEXカラーコードを許可するかどうか
indentation インデントサイズ
selector-max-specificity セレクタの最大詳細度

など、これらのルールを細かく指定することで、より自分好みのコーディング規約に違反しているかどうかを機械的に検知することができます。コードレビューの負担を減らすためにも、リンターの導入は検討されるべきです。

現在の最新バージョンである v9.1.1 には、180個のルールがあります。CSS、またはSassなどのプリプロセッサーのためのリンターはいくつかありますが、その中でもstylelintのルールセット数が圧倒的に多く、JavaScriptのコードリンターであるESLintのように、カスタマイズ性に富んでいることがわかります。

CSSリンターのルール数:

stylelint CSS Lint scss-lint CSSComb
180 38 62 26

また、stylelintはPostCSS製(パーサーとしてPostCSSを使っている)ため、CSSだけでなく、SassやLESS等のPostCSSがパース可能なシンタックス全てに対してリントすることが可能なのも特徴です。

設定ファイルの書き方

stylelintの設定のオブジェクトは cosmiconfig というパッケージを使って読み込まれます。stylelintの場合、以下のファイル名、形式で設定ファイルを作成できます。僕は、JSON形式で .stylelintrc という名前で作ることが多いです。

  • package.json 内の stylelint プロパティに記述する
  • .stylelintrc ファイル(JSON or YAML)
  • JSオブジェクトとして module.exports された stylelint.config.js ファイル

.stylelintrc 例:

{
  "rules": {
    "color-hex-length": "short",
    "color-no-invalid-hex": true,
    "custom-property-no-outside-root": true,
    "indentation": 2,
    "length-zero-no-unit": true,
    "media-feature-name-no-vendor-prefix": true,
    "number-leading-zero": "never",
    "selector-root-no-composition": true,
    "string-quotes": "single"
  }
}

また、npmで、stylelint-config のキーワードを付けて登録されているパッケージは、stylelintの設定集です。その中でも、以下のパッケージが有名です。

stylelintのルールは今180個あり、それらを1つずつ調べて自分で1から設定ファイルを作るのは骨が折れます。
そこで、 stylelint-config-* パッケージを継承することで、公開されている設定ファイル集をベースに自分のプロジェクトでの調整を加えることができます。

{
  "extends": "stylelint-config-primer",
  "rules": {
    "indentation": 2,
    "string-quotes": "double"
  }
}

また、stylelintのルールは、全てPostCSSのプラグインとして実装されています。そこで開発者は、独自のstylelintのルールを作って、それをstylelintのプラグインとして公開することができます。

例として、SassのSCSS記法のための、stylelint-scss というプラグインがあります。

{
  "plugins": [
    "stylelint-scss"
  ],
  "rules": {
    "scss/dollar-variable-pattern": "^foo",
    "scss/selector-no-redundant-nesting-selector": true
  }
}

stylefmtによる自動整形

約180個あるstylelintのルールですが、"indentation""string-quotes", "color-hex-length" など、大半はコードフォーマットに関するルールです。これらのフォーマットに関するルールは、ESLintの --fix オプションのように自動修正することが可能です。

PostCSSのエコシステムでは、stylefmt というツールを使うことで、stylelintの設定ファイルから、フォーマットに関するルールに従いコードを自動整形することができます。ちなみに、前はCSSfmtという名前でした

stylefmtにはデフォルトのフォーマットルールが存在し、僕はstylelintの設定ファイルにはフォーマットに関するルールは一切書かず、stylefmtのデフォルトのルールに従っています。

その他PostCSS製ツール

PreCSS

SCSS-likeなシンタックスを持つプリプロセッサーです。約1年間更新されておらず、ベンチマークもnode-sassと変わらないので、node-sass、もしくはdart-sassを使うことをオススメします :)

doiuse

doiuseは、Can I Useのデータと入力するサポートブラウザを元に、サポート対象外のプロパティや@ルールを使っていないかをリントするツールです。Autoprefixerと同じ記法でサポートブラウザを指定することができます。

CSS Modules

CSS Modulesという、CSSのルールセットの影響範囲がグローバルスコープである問題を解決するためのアプローチがあります。CSS Modulesを使って定義されたルールセットはデフォルトでローカルスコープ(ファイルスコープ)を持ち、composesというキーワードにより異なるスコープ間でのスタイルの共有も可能です。

ここではCSS Modulesの使い方や詳しい仕組みについては説明しませんが、セレクタ名にハッシュ値を付ける処理や、composesキーワードの実装にPostCSSが使われています。

参考: CSS Modules 所感

小ネタ

最後に、PostCSSについての小ネタを紹介します。

歴史

PostCSSのようなプラグインアーキテクチャーなCSSパーサーは、PostCSSがはじまりではありません。PostCSSの元となったのは、TJやNicolas Gallagherらが始めた、rework というプロジェクトです。

PostCSSの作者のAndreyは、reworkを使ってrework-vendorsという、ベンダープリフィックスを自動で付与するためのプラグインを書きました。これが後のAutoprefixerとなります。しかし、当時reworkにはブラウザハックをパースできないバグがあったり、TJに「AutoprefixerはAPIがイケてない」、「CoffeeScriptだからダサい」等とDisられたことで、Andreyはreworkのようなツールを自分で作り、PostCSSが誕生しました。

今では、PostCSSはreworkよりもパーサーとしても優秀で、実行速度も速く、AST操作のための便利なAPIも提供されているので、多くのツールがPostCSSから作られるようになりました。

ポストプロセッサー?

PostCSSはreworkとの差別化のために、PostCSSで作られたAutoprefixer等を「ポストプロセッサー」と命名し、PostCSSはポストプロセッサーを作るためのツールとしていました。しかし、cssnextやPreCSSといった言語拡張(プリプロセス)のためのツールも作られるようになり、PostCSSチームは「ポストプロセッサー」という単語を使わないことになりました。

参考: CSSのプリプロセスとポストプロセス、そしてReworkとPostCSS


CHANGELOG

2018/02/27

  • 紹介しているライブラリを最新のバージョンに対応