ぼくがかんがえたさいきょうのCSS設計

Misocaという会社でなんかしてる @merotan ともうします。
最近仕事でとある機能のUIリニューアルをおこなうことがありまして、僕はどうしてもPostCSSを使いたかったのと、現行のクソみたいになっているCSSからなんとしてでも脱却したかったので、どうすればクソなことにならずいい感じにCSSを書くことができるか考えて実践してみた結果を書いていこうと思います。

# 影響を受けているもの
参考・影響を受けているものとして[FLOCSS](https://github.com/hiloki/flocss)、[BEM](https://en.bem.info/)、[AtomicDesign](http://bradfrost.com/blog/post/atomic-web-design/)などがあります。
意識はしてないものの何かでみてあーこれ良いなと思ったものもあるかもです。

# 命名規則
命名規則はBEMです。(BEMの説明はここではしないので、上のリンクから確認していただければと)
ですが、Modifierはカスタムデータ属性を使用します。

また`Modifier`はカスタムデータ属性を活用します。
こうすることで無理にクラス名で状態等を表現することがなくなり、`HTML`でのクラス名が短くなり非常に読みやすくなります。

詳しくは
[CSS設計の類はもっとカスタムデータ属性を活用するべきでは](http://qiita.com/trkbt10/items/ae33dfd579c9cea7f056)
か
[BEMのModifierはclassで書くのやめませんか？](http://qiita.com/merotan/items/edccde6bfbd9740570d8)
で。

# 使用ツール
[PostCSS](http://postcss.org/)を使用します。
将来的に実装されるであろう機能が`PostCSS`のプラグインとして提供されているので保守性が高いと思います。

- [postcss-nesting](https://github.com/jonathantneal/postcss-nesting)
- [postcss-import](https://github.com/postcss/postcss-import)
- [autoprefix](https://github.com/postcss/autoprefixer)
- [postcss-apply](https://github.com/pascalduez/postcss-apply)
- [postcss-custom-properties](https://github.com/postcss/postcss-custom-properties)

主に使うプラグインがこれらになります。
詳細はここでは説明しませんので、Githubで確認していただければと思います。

# 基本ルール

基本的にHTMLタグに対して複数のクラスは付けないようにします。
1タグ1クラスにします。

# ファイル構成

ファイル構成は以下のようにします。

```
src/stylesheets/
  |-- main.css
  |
  |-- foundation/
  |     |-- index.css
  |     |-- reset.css
  |     `-- base.css
  |
  |-- variables/
  |     |-- index.css
  |     |-- layout.css
  |     `-- color.css
  |
  |-- units/
  |     |-- index.css
  |     |-- text.css
  |     |-- color-palette.css
  :     : 
  |
  |-- parts/
  |     |-- index.css
  |     |-- button.css
  |     |-- message-ballon.css
  :     : 
  |
  |-- components/
  |     |-- index.css
  |     |-- header.css
  |     |-- member-list.css
  |     |-- modal
  |     |    |-- index.css
  |     |    |-- confirm-window.css
  |     |    |-- alert-window.css
  :     : 
  |
  |-- layouts/
  |     |-- index.css
  |     |-- index-layout.css
  |     |-- edit-layout.css
  :     : 
  |
  |-- utilities/
  |     |-- index.css
  |     |-- margin.css
  |     |-- padding.css
  :     : 
```

`main.css`はエントリーポイントです。
基本的には

```css
@import 'foundation';
@import 'variables';
@import 'units';
@import 'parts';
@import 'components';
@import 'layouts';
@import 'utilities';
```

このように定義するだけになります。

また各ディレクトリの`index.css`では基本的には各ディレクトリのCSSファイルをインポートするようにします。

## foundation
foundationでは主に`Reset.css`や`Normalize.css`等のブラウザのデフォルトスタイルの初期化、アプリケーションのベースとなるスタイルを定義します。
アプリケーション全体の背景、フォントの設定等を行います。

### variables
ここではアプリケーションで使われるグローバルな変数を定義します。
[CSS Custom Properties](https://www.w3.org/TR/css-variables/)を使い定義していきます。
プラグインとしては[postcss-custom-properties](https://github.com/postcss/postcss-custom-properties)です。

- `layout.css`にはアプリケーションのレイアウトの`width`等の変数を定義します。
- `color.css`にはアプリケーションで使われる色を定義します。

```css:variables/layout.css
:root {
  --nav-width: 200px;
  --content-width: 700px;
}
```

```css:variables/color.css
:root {
  --text-default-color: #333;
  --text-warning-color: red;
}
```

こんな感じ。

## units
ここではアプリケーションの各 `parts` / `component` を構成するのに必要なものを定義します。
例をあげると、文字の大きさ(`font-size`)と文字の太さ(`font-weight`)の組み合わせや、背景色(`background-color`)と文字色(`color`)の組み合わせ、
のようなアプリケーションの構成要素として基本的なモノを定義していきます。
[CSS @apply Rule](http://tabatkins.github.io/specs/css-apply-rule/)を使用します。
プラグインとしては[postcss-apply](https://github.com/pascalduez/postcss-apply)です。


```css:units/text.css
:root {
  --default-text: {
    font-size: 14px;
    font-weight: normal;
    line-height: normal;
  }
}
```

```css:units/color-palette.css
:root {
  --main-color-set: {
    color: white;
    background-color: var(--main-color);
  }
  --warning-color-set: {
    color: white;
    background-color: var(--warning-color);
  }
}
```

```css:units/rectangle.css
:root {
  --rounded-rectangle: {
    border-radius: 4px;
  }
}
```

以上のように書いていきます。

## parts
ここではアプリケーションに必要最小限の構成物を定義します。
ボタンや、メッセージバルーン、タブ、テキストフィールドといった汎用的なモノを定義します。
**基本的**には子要素(BEMでいうエレメントですね)を作らないようにします。
必要最小限の構成物なので、複雑なものは作らないようにします。

```css:parts/button.css
.button {
  @apply --main-color-set;
  @apply --default-text;
  @apply --rounded-rectangle;
  
  &[data-size="large"] {
    width: 200px;
    height: 50px;
  }
  &[data-size="small"] {
    width: 20px;
    height: 20px;
  }
}
```

このように**基本的**には`unit`を組み合わせて作っていきます。
ですが基本的にはなので、ここにスタイルを書いてはだめということではありません。

こうすることで、パット見でどういうスタイルなのかがわかりやすくなります。
上の例だと、**「色はアプリのメインの色で、文字はデフォルトのもので、角丸な四角い、ボタン」**ということが、詳細をみなくてもわかるようになります。

## components
ここではアプリケーション内で使う大きい構成物を定義します。
`components`は他の`components`や`parts`を子要素として持つ場合があります。
`components`内で`components`や`parts`を子要素として持つ場合は、
`hogeArea`(この`hoge`は**基本的**には`components`名や`parts`名にしますが、大まかに左と右で分けたい等ある場合は、`leftArea`、`rightArea`とすることもあります。)をつくってその中に、`components`や`parts`を格納します。


```css:components/header.css
.header {
  @apply --clearfix;
  height: var(--app-header-height);
  
  &_logoArea {
    float: left;
  }
  &_loginButtonArea {
    float: right;
  }
}
```

```html:header.html
<header class="header">
  <div class="header_logoArea">
    <img class="logo" src="logo.png" />
  </div>
  <div class="header_loginButtonArea">
    <button class="button">ログイン</button>
  </div>
</header>
```

このような感じです。
こうすることで、他の`components`や`parts`に対してスタイルの上書きを行わないようにします。

また、似たような`components`（例えば確認ダイアログとアラートダイアログは似たような見た目かと思います）はディレクトリを切るようにします。
そのディレクトリの`index.css`にそのコンポーネント共通の`units`や`variables`、共通の親`components`等を切り出します。
こうすることで、似たようなコンポーネントだからといってむやみに`units`として切り出してしまうことを抑制でき、かつ似た`components`をまとめることができます。

## layouts
ここでは各`component`をどこに配置するかを定義します。
大枠のワイヤーフレームを書くものです。
基本的には`float`や`flexbox`、`position`を利用してレイアウトを行っていきます。

```css:layouts/application-layout.css
.applicationLayout {
  display: flex;
  flex-direction: row;
  &_navArea {
    order: 1;
    width: var(--application-nav-width);
  }
  &_contentArea {
    order: 2;
    width: var(--application-content-width);
    min-width: var(--application-content-min-width);
  }
}
```

命名規則として`hogeLayout`のように後ろに`Layout`をつけます。
また、子要素はすべて`hogeArea`(`components`のと同様に)のように後ろに`Area`をつけます。

## utilities
ここではある特定の一箇所でのみスタイルを当てたいという場合が発生した時に使うスタイルを定義します。
例えば説明文中にそこでしか使わない、特別な`margin`が必要な場合等に使います。
命名規則は特殊なものとわかりやすくするために、
`u-hoge`のように最初に**`u-`**つけるようにします。
またそのスタイルを優先(強制)させるために**`!important`**を必ずつけるようにします。

```css:margin.css
.u-description-margin-bottom {
  margin-bottom: 10px !important;
}
```

# 使ってみた感想

自分で考えたこともあるのですが、非常にやりやすかったです。
特に`hogeArea`のお陰でスタイルの上書きをすることがなくレイアウトできたのがよかったなぁとおもいました。
また`units`は良かったです。`parts`のところにも書いたのですが、人が書いたCSSでも詳細を見ることなく、`@apply`のところを読むだけで「こういう見た目になるんだろうな」というのがすぐひと目でわかるのがとても良かったです。

とはいえ、どの程度のものを`units`に切り出すか、`parts`とするかというのが難しくて悩むことが多かったです。
でも多分そのへんはどの設計でも難しいのかなとも思ったりしたり…。
また、`Layouts`の恩恵があまりうけれずこれいるのかなぁ…とおもったりしたりしました…。

まだまだ改善点がたくさんあるだろうなとつよく思い、今後も改善していこうと思いました。

世の中には色々CSSの設計思想があってどれも良いものだと思いますが、
皆さんのやりやすいやり方を見つけたり考えられたりできるといいなと思います。
これが皆さんのなにか参考になるといいなぁと思います。