PostCSSの基本的なプラグインについて

自分のサイトのSCSSをPostCSSに書き換えたので、そのときに調べたことをメモしておく。プラグインパックであるcssnextはなにがどう変換されているか把握できなくなりそうなので使わずに、個別でインストールしていく方針。どんなサイトでも基本的に使うだろうな、というものだけメモしておく。

ここで書いたもので不足を感じたときに[Readmeに書かれているもの](https://github.com/postcss/postcss/blob/master/docs/plugins.md)なり[PostCSS.parts](http://postcss.parts/)にあるプラグインを試せばいいとおもう。ただ最後にもすこし触れるけど、なんでも便利そうだからと入れて使うのはやめたほうがいいとおもう。

SCSSからの移行であれば[precss](https://www.npmjs.com/package/precss)がよさそう。ただ自分が使ったときはcssnanoと併用したときに、importしたファイルをうまくminifyできていませんでした。

## プラグイン

### 記法

#### [postcss-import](https://github.com/postcss/postcss-import)

`@import`したファイルを展開する。最初によみこまないと以降に紹介するpostcss-simple-varsやpostcss-mixinsをimportしたときエラーになるので、最初に読み込ませておく。

#### [postcss-simple-vars](https://github.com/postcss/postcss-simple-vars)

SCSSっぽいシンプルな`$`を使った変数が使える。使い方は大体同じ。

```css
$theme-color0: #fff;
$body-bgcolor: $theme-color0;

$font-family-base: Meiryo, Arial, sans-serif;
$font-family-heading: 'Hiragino Kaku Gothic ProN', $font-family-base;
```

変数をプロパティの値以外で使うときにはSCSSとはちょっとだけ記法が違う。

```css:input.css
$name: Box;

.$(name)-list { }
```
```css:output.css
.Box-list { }
```

変数のスコープは以下のような挙動になり特に警告がでるようなこともないので、LESSからの移植の場合注意が必要になるかもしれない。

```css:input.css
$color0: #000;

.foo {
  $color0: #fff;
  color: $color0;
}

.bar {
  color: $color0;
}
```
```css:output.css
.foo {
  color: #fff;
}

.bar {
  color: #fff;
}
```

この挙動が問題になるのであれば[postcss-nested-vars](https://github.com/jedmao/postcss-nested-vars)を使うというのもいいかもしれない。

JavaScriptに設定を持たせることもできる。CSS Modulesで使いやすいのだろうか、普通のCSSでそういった使い方をすることはあんまりないとおもう。

#### その他の変数のためのプラグイン

- [postcss-custom-properties](https://github.com/postcss/postcss-custom-properties)
- [postcss-css-variables](https://github.com/MadLittleMods/postcss-css-variables)

これらは仕様に近い記述ができます。

```css
:root {
  --theme-color0: #fff;
  --body-bgcolor: var(--theme-color0); /* postcss-css-variablesではエラー */
  --font-family-base: Meiryo, Arial, sans-serif; /* たぶんどちらでもエラー */
}
```

こういった記述のほかにもプロパティの値以外で変数が使えなくなるというのもちょっときついかな、と思う。仕様的にはすくなくとも上は問題なかったはず。下はちょっと怪しいので普通にextendするべきかな。

- [CSS Custom Properties for Cascading Variables Module Level 1](https://www.w3.org/TR/css-variables/)

どうしてもこだわりがあるのであれば、[postcss-media-variables](https://github.com/WolfgangKluge/postcss-media-variables)や[postcss-font-pack](https://github.com/jedmao/postcss-font-pack)といったものも使わないと使いにくそうだなと感じた。ただpostcss-font-packはpostcss-importとうまく使えなかった。使う予定はなかったのであまり詳しく調べたりはしなかった。

#### [postcss-nested](https://github.com/postcss/postcss-nested)

SCSSでもあるCSSの入れ子。

```css:input.css
.cats {
  &-list {
    list-style-type: none;
    .cat {
      margin: 1rem;
    }
  }
  .container & {
    margin: 0;
  }
}
```
```css:output.css
.cats-list {
  list-style-type: none;
}
.cats-list .cat {
  margin: 1rem;
}
.container .cats {
  margin: 0;
}
```


#### [postcss-mixins](https://github.com/postcss/postcss-mixins)

mixinsを使える。SCSSよりも便利なところは以下のようなことができるところ。

```css
@define-mixin foo {
  &::after {
    content: "foo";
  }
}
```

LESSでもこの記述は問題なく可能なので、twbs4でもLESSからSCSSへの移植でこのあたりの記述がかなりゴチャゴチャになってた気がする。

#### [postcss-extend](https://github.com/travco/postcss-extend)

placeholderを使える。

```css:input.css
@define-placeholder simple-list {
  list-style-type: none;
}
.cats-list {
  @extend simple-list;
}
.dogs-list {
  @extend simple-list;
}
```
```css:output.css
.cats-list, .dogs-list {
  list-style-type: none;
}
```

#### [postcss-color-function](https://github.com/postcss/postcss-color-function)

仕様と同じの`color`関数。

```css:input.css
.foo {
  color: color(#000 a(10%));
  background-color: color(#000 l(50%));
  border-color: color(#fff b(50%));
}
```
```css:output.css
.foo {
  color: rgba(0, 0, 0, 0.1);
  background-color: rgb(128, 128, 128);
  border-color: rgb(170, 170, 170);
}
```

#### [postcss-calc](https://github.com/postcss/postcss-calc)

`calc`関数。

```css:input.css
$foo: 20px;

.foo {
  width: calc($foo * 2);
  height: calc(20% - $foo);
}
```
```css:output.css
.foo {
  width: 40px;
  height: calc(20% - 20px);
}
```

#### [postcss-comment](https://www.npmjs.com/package/postcss-comment)

`//`のコメントアウト。

```css:input.css
// コメント
```
```css:output.css
/* コメント */
```

### その他

だいたい以下の2つとpostcss-importは毎回確実に使っています。

#### [autoprefixer](https://www.npmjs.com/package/autoprefixer)

説明は不要であろうautoprefixer。

#### [CSSWring](https://www.npmjs.com/package/csswring)

CSSのminify。autoprefixerなどの機能もついているcssnanoなんかもあるんだけれど、プラグインの機能は多くありすぎても使いにくいので、cssnanoは使わずにCSSWringを使っています。

## なぜPostCSSを使うのか

自分がPostCSSを使う理由は変換の早さではなくて、SCSSやLESSの多機能性を求めていなかったことにあるとおもう。特に最近はJSXとか.vueとかPolymerなんかでCSSをコンポーネント化することが多くて、まずネストは使わなくなるし、変数すら使わなかったりする。Polymerなんかは変数もmixinも自身の機能として提供されているしね。変数のプラグインで使うにしてもSCSSライクなものよりは仕様通りのものを使ってくれていたほうがありがたいかなあとおもう。

ただ、かといってCSSをそのまま書くのはどうせautoprefixerは使うし、minifyもするし、importでconcatはしてほしいし、場合によってはextendやcolorも使いたい。そういうわけでそのあたりを一括でプラグインで管理できるPostCSSが便利だなーと感じて最近ではPostCSS以外使うことはなくなりました。

PostCSSでprecssやnextcssに加えてプラグインをあれもこれもと大量に導入して……なんてやるならたぶん素直にSCSSやLESS、Stylusなんかを使ったほうがいいんじゃないかなーという気はします。すくなくともそういうCSSを自分は見たいと思わない。