2017年度・自分なりのWebサイト制作向けCSS設計論

株式会社アンティー・ファクトリーXAチーム（マークアップエンジニアチームの名称）の Advent Calendar 1日目担当の@kokushinです。
業務ではWebサイトのマークアップに加え、JavaScriptを用いた演出・機能実装などを行っております。
プライベートでは、Vue.jsを使ったWebアプリやCSSフレームワークなんかを自作して遊んでおり、最近だとサーバーサイド言語にも手を出し始めました。楽しいです。

CSS設計に関してはまだ苦手意識がありますが、OOCSS・SMACSS・BEM・FLOCSSなどの設計論や、Atomic Designといった考え方が登場したことで昔よりかは随分と良くなりましたね。

弊社では主にFLOCSSを取り入れて業務に活かしているのですが、プライベート開発のときは__「独自のCSS設計を考えて実際に使ってみよう」__と決めていたので、WebサイトのソースやGitHubで公開されているCSSフレームワークのソースを参考にしたりして、この一年間色々と試行錯誤してきました。

今回は、そんな試行錯誤の結果たどり着いた「2017年度・自分なりのCSS設計論」をご紹介したいと思います。

## 2017年度・自分なりのCSS設計論

デザイン上の要素を__「Modules（部品）__」と__「Components（部品の集合体）」__に分類し、__「Pages（ページの枠）」__に配置していくというものです。Atomic Designの考え方を参考にしていますが、本家ほど細かく別けていません。

[kokushin/css-architecture](https://github.com/kokushin/css-architecture)

- 単体で機能する最小限の部品が「Modules」（例：ボタン、インプット要素など）
- 「Modules」の集合体が「Components」（例：ヘッダー・フッターなど）
- Webページとして「Components」「Modules」を配置する枠が「Pages」

つまり、粒度は `Pages > Components > Modules` となります。

Webページは Components の集合体となり、共通のスタイルを簡単に使いまわすことができ、部品単位で管理ができるためメンテナンス性も向上します。


## ディレクトリ構造

Sass(SCSS)の利用を前提としています。

```
├── imports.scss
├── components
│   ├── _imports.scss
│   ├── content.scss
│   ├── footer.scss
│   ├── header.scss
│   └── sidebar.scss
├── core
│   ├── _imports.scss
│   ├── core.scss
│   ├── mixins.scss
│   └── variables.scss
├── modules
│   ├── _imports.scss
│   ├── button.scss
│   ├── input.scss
│   └── typography.scss
└── pages
    ├── _imports.scss
    ├── index.scss
    └── single
        └── index.scss
```

構成は 

- __「imports」__
- __「cores」__
- __「modules」__
- __「components」__
- __「pages」__ 

に別けられます。

### importsファイル

各ディレクトリにある _imports.scss が該当します。
各scssファイルを @import するためのファイルで、特にルートに存在している imports.scss は、プリプロセッサのエントリーポイントとして機能する最重要ファイルです。

```scss
/**
 * 1. cores
 */
@import "cores/_imports";

/**
 * 2. modules
 */
@import "modules/_imports";

/**
 * 3. components
 */
@import "components/_imports";

/**
 * 4. pages
 */
@import "pages/_imports";
```

### coresディレクトリ

variables.scss や mixins.scss、reset.scss などが該当します。
変数や@mixinなど設定ファイル、リセットCSSなどWebサイト全体に影響するようなスタイルが含まれます。
そのため、imports.scss 内では最初に読み込ませなければなりません。

### modulesディレクトリ （Modules）

ボタンやタイポグラフィといった、「部品」単位で機能する最小限のスタイルを専用のモジュールクラスに適用させます。
大きさや色など、バリエーションは細かく分解して用意しておきます。

```scss
.btn {
  /* base styles */
}

.btn-large {
  /* module styles */
}

.btn-primary {
  /* module styles */
}
```

### componentsディレクトリ (Components)

ヘッダーやフッターなど、「製品」単位で機能するスタイルを専用のコンポーネントクラスに適用させます。
こちらもバリエーションが存在している場合は細かく分解して用意しておきます。
前述したように、Components ごとの細かいスタイル調整が必要な場合は、各 Modules のスタイルを上書きしてもOKです。

```scss
.header {
  /* component styles */

  .logo {
    /* override module styles */
  }

  .btn {
    /* override module styles */
  }
}
```

### pagesディレクトリ (Pages)

Webサイトの各ページのディレクトリ構造に合わせてファイルを作成し、そのページごとのユニークな要素に対してスタイルを適用させます。マージン調整が主になるかと思います。
こちらも、ページごとの細かいスタイル調整が必要な場合は、各 Components, Modules のスタイルを上書きしても構いません。

```scss
.header {
  .pages-single & {
    /* override page styles */

    .logo {
      /* override page styles */
    }

    .btn {
      /* override page styles */
    }
  }
}
```

## 命名規則

基本的にOOCSS+SMACSSを組み合わせたものを利用しています。

- 接頭辞の付与はどちらでもよい。クラス名の競合が懸念される場合は付与する
- ネストが深くならない場合に限り p や li などはクラス名の付与を省略してもよい
- 詳細度はなるべく低く保てるように最小限のHTML構成が求められる
- クラス名を考えるときは英単語のシソーラス検索などを利用し、なるべく理解しやすいものを採用する
- 単語はキャメルケースで繋ぐ
- Modifierはハイフン一つで繋ぐ

__例: 基本__

```css
.header
.header.is-fixed
.header .logo
.header .description

.menu
.menu.is-active
.menu .item
.menu .item.item-1
```

__例: 略語__

```css
.btn
.txt
.pic
.img
.nav
.typo
```

__例: 接頭辞__

```css
/* modules */
.m-className

/* components */
.c-className

/* state */
.is-className

/* JavaScript */
.js-className
```

BEMでも良いのですが、冗長的になってしまいがちなので、__共同作業が発生する場合など大規模な案件のときに採用__します。

## 実装フロー

1. まずはデザインをチェック。要素を__「Modules」__と__「Components」__に分類する。
2. パーツとなる__「Modules」__から実装する。
3. コンポーネントとなる__「Components」__を実装。必要に応じて__「Modules」__を取り込み、調整する。
4. 大枠となる__「Pages」__を実装。必要に応じて__「Components」__と__「Modules」__を取り込み、調整する。

## 実例

プライベートな制作物ですが、自作CSSフレームワークを開発する際にこの考え方を取り入れてみました。※

[UNY - A modern CSS framework](https://unys.github.io/uny/)

感想としては、コンポーネント単位で分割してCSSを書いていくので、__一つのコンポーネントのスタイル調整に集中できる__というのが気持ちよかったです。
基本的にCSSさえ書いてしまえば、あとはHTMLを組み立てて行くだけなのでWebページの制作も非常にスムーズでした。

このコンポーネントだけ機能を増やしたい！という時も、どのscssファイルを触ればいいか明確ですし、これはページ固有のスタイルだから、「Pages」で調整しちゃおう！と素早く判断できたのも良かったです。

共同開発でも、コンポーネントごとに作業分担してscssファイルを触ればいいので同時進行が可能です。非常に効率的です。

※上記CSSフレームワークでは「Pages」は含んでいません。また、「Modules」は「Elements」としていますが考え方は同じです。

## まとめ

- デザイン上の要素を__「Modules（部品）」「Components（部品の集合体）」「Pages（ページの枠）」__に分類する
- CSSファイルのディレクトリ構造を上記3つの要素に紐付けて管理する
- 命名規則はOOCSS+SMACSS推奨。BEMは案件規模に応じて採用
- 冗長的にしない。省けるものは省いていく

近年はSPAなどの流行もあり、__「コンポーネント指向」__が身近なものになってきていますね。将来的にWeb Componentsが当たり前の技術になったら、スタイルをコンポーネント毎にカプセル化できるようになるので、こういったCSS設計論は不要になるかもしれませんが、それでも学習したり自分で考えてみたり、実際にそれを使ってみたりすることは決して無駄ではないと思っています。

上記の考え方は、もうちょっとプライベート開発で実践してブラッシュアップしてから会社に提案してみようと思っています。

最後まで読んでいただき、ありがとうございました。
何か部分的にでも参考になりましたら幸いです。
もっとこうした方が良いんじゃない？というご意見がありましたら、ぜひコメントを頂けると嬉しいです。

次回は@untspringkさんの「Webpack」に関するお話です！お楽しみに。