stylelintおすすめルール・プラグイン

CSSの記法やルールを運用でカバーしていくのはキツいなと誰しも思っているところだと思います。よく巷ではなんとかlintが流行っていますが、実際導入するときどんなルールで運用すればいいか迷いますよね。自分は迷いました。

そこで、今回は自分が関わっているプロジェクトで採用した [stylelint](https://stylelint.io/) でどんなルールやプラグインを採用しているかを紹介します。

# 前提
- どんなルールが最適かは各チームによるので、細かい調整はチームメンバーで話し合ってください。
- 採用したルールをすべて記載しているわけではなく、特に良いなと思ったのをピックアップして紹介しています。

# stylelintとは
stylelint は、CSSの書き方をプログラマーに指摘してくれるnpmモジュールです。rubyでいう [RuboCop](https://docs.rubocop.org/en/latest/) と似たものですね。公式ドキュメントによると、160以上のルールが用意されているそうです。デフォルトだと .css のみが対象なのですが、設定をいじくれば、 .scss や `<style>` タグ内も対象にすることができます。

## 使い方
stylelint を実行するには、自前で以下のような設定ファイルを用意する必要があります。
それぞれ、

`plugins` … stylelint で予め用意しているルール以外で、有志が拡張して作った独自のルール
`rules` … stylelint で予め用意しているルール

を指定することができます。詳細は公式ドキュメントの https://stylelint.io/user-guide/configuration/ あたりを確認してください。

```yml:stylelintrc.yml
plugins:
  - stylelint-declaration-block-no-ignored-properties
  - stylelint-no-unsupported-browser-features
rules:
  color-no-invalid-hex: true
  font-family-no-duplicate-names: true
  font-family-no-missing-generic-family-keyword: true
  ~ 省略 ~
  no-eol-whitespace: true

  # plugin rules below
  plugin/declaration-block-no-ignored-properties: true
  plugin/no-unsupported-browser-features:
    - true
    - browsers: [
      "> 5% in JP",
      "Last 2 Safari versions",
      "Last 2 iOS versions",
      "Last 2 Chrome versions",
      "Last 2 ChromeAndroid versions",
      "IE 11",
      "Last 2 Edge versions",
      "Last 2 Firefox versions",
      "Last 2 FirefoxAndroid versions",
      ]
    - severity: "warning"
```

なお、 [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard) のように、予め必要そうなルールをまとめたものを使うこともできますが、思いの外ルールが多かったので、仕方なくルールを一つ一つ読んで選んでいきました。

# 良いなと思ったルール
### "font-family-no-missing-generic-family-keyword": true
`font-family` を書く時、ブラウザに実装されている総称ファミリは末尾につけるようにしようってルールです。総称ファミリーというのは、指定したフォント何もない！って時にフォールバックとして適用してくれるフォントタイプです。 `serif|sans-serif|monospace` とかがそれです。

```css
/* bad example */
a { font-family: 'Times'; }
```
```css
/* good example */
a { font-family: 'Times', sans-serif; }
```

参考: https://developer.mozilla.org/ja/docs/Web/CSS/font-family
https://stylelint.io/user-guide/rules/font-family-no-missing-generic-family-keyword/


### "declaration-block-no-shorthand-property-overrides": true
ショートハンドプロパティで上書きしちゃうの避けましょうってルールです。よくやりがちなのは、 `background` プロパティで上書きしてしまう時でしょうか。ショートハンドプロパティで指定しなかった値は初期値になってしまうので、意図しないスタイルが当たってしまう可能性があります。

たとえば、Qiitaのナビメニューの背景色には `background-color: #55c500;` が使われていますが、これで `background: #55c500;` で上書きすると以下のようになります。
![スクリーンショット 2018-10-04 0.48.38.png](https://qiita-image-store.s3.amazonaws.com/0/156176/95de75c2-8a66-f17a-7144-b1abf97a21a3.png)
ちなみに、ショートハンドプロパティ**を**一部上書きするのはアリです。

```css
/* bad example */
a {
  padding-left: 10px;
  padding: 20px;
}
```
```css
/* good example */
a {
  padding: 20px;
  padding-left: 10px;
}
```
https://stylelint.io/user-guide/rules/declaration-block-no-shorthand-property-overrides/


### "declaration-block-trailing-semicolon": "always"
プロパティの値の末尾には必ずセミコロンをつけておきましょうってルールです。最終行のプロパティの値にはセミコロン要らないって仕様になってる（正確に言うと`;`は`プロパティ:値`同士を区切るために使っている）んですが、新しい値を書き加えようとする時にエラーになっちゃいます。

```css
/* bad example */
p { 
  margin: 0 0 20px;
  font-size: 1rem /* <- ここセミコロンつけ忘れ！ */
  color: #555;
}
```
```css
/* good example */
p { 
  margin: 0 0 20px;
  font-size: 1rem;
  color: #555;
}
```
参考: 
https://stackoverflow.com/questions/11939595/leaving-out-the-last-semicolon-of-a-css-block
https://www.w3.org/TR/CSS2/syndata.html#declaration


### "selector-pseudo-element-colon-notation": "double"
疑似要素使う時にコロンつけると思うんですけど、コロン1個だけってのは実は古い仕様で、コロン2個が正しいです。擬似クラスと区別するためって意図もあるので、ここはちゃんと書き分けたいですね。

```css
/* bad example */
a:before { color: pink; }
```
```css
/* good example */
a::before { color: pink; }
```
https://stylelint.io/user-guide/rules/selector-pseudo-element-colon-notation/

※ 以下MDNとW3Cに記載があるので引用しておきます。
https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
> Note: As a rule, double colons (::) should be used instead of a single colon (:). This distinguishes pseudo-classes from pseudo-elements. However, since this distinction was not present in older versions of the W3C spec, most browsers support both syntaxes for the original pseudo-elements.
（意訳: 擬似クラスと区別するために、シングルコロンではなくダブルコロンを使用してください。ただ、W3Cの古い仕様ではこの区別について言及されていなかったため、ほとんどのブラウザは両方の記法をサポートしています。）


https://www.w3.org/TR/selectors/#pseudo-element-syntax
> Because CSS Level 1 and CSS Level 2 conflated pseudo-elements and pseudo-classes by sharing a single-colon syntax for both, user agents must also accept the previous one-colon notation for the Level 1 & 2 pseudo-elements (::before, ::after, ::first-line, and ::first-letter). This compatibility notation is not allowed any other pseudo-elements. However, as this syntax is deprecated, authors should use the Level 3+ double-colon syntax for these pseudo-elements.
（意訳: CSS Level 1 と CSS Level 2 では、擬似要素と疑似クラスの記法を一緒くたにしていたため、Level 1 とLevel 2 から定義されていた ::before, ::after, ::first-line, ::first-letter に関しては、シングルコロンの記法も許可されています。しかし、他の擬似要素では許可されていません。いずれにせよ、この記法はもう非推奨であるため、擬似要素にはダブルコロンを使用するようにしてください。）

# 作った人天才か？と思ったプラグイン

### stylelint-declaration-block-no-ignored-properties
displayの値によって無視されてしまうプロパティを見つけてくれるpluginです。たとえば、`display: inline` の要素にいくら頑張ってもwidthの値はシカトされるんですが、そういう無効な組み合わせを検知してくれるようです。こいつ天才か。
https://github.com/kristerkari/stylelint-declaration-block-no-ignored-properties

### stylelint-no-unsupported-browser-features
ブラウザ非対応のプロパティがないかを検知してくれるpluginです。裏ではbrowserslistを使っているらしく、以下のように対応ブラウザのバージョン、地域などを定義すると、それらのブラウザでサポートされていないプロパティを自動的に指摘してくれます。クロスブラウザ対応を漏れなく行うのは結構大変なので、これは助かりますね。

```yml:stylelintrc.yml
  plugin/no-unsupported-browser-features:
    - true
    - browsers: [
      "> 5% in JP",
      "Last 2 Safari versions",
      "Last 2 iOS versions",
      "Last 2 Chrome versions",
      "Last 2 ChromeAndroid versions",
      "IE 11",
      "Last 2 Edge versions",
      "Last 2 Firefox versions",
      "Last 2 FirefoxAndroid versions",
      ]
```
https://github.com/ismay/stylelint-no-unsupported-browser-features

他にもこんなプラグインおすすめです！などがありましたら、ぜひ教えていただけるとありがたいです！☺️