[WIP] もうFLOCSSで消耗するのはやめよう！単一ファイルコンポーネント時代の新しいCSS設計

# 序章

管理可能で拡張性のあるCSSを構築するために、先人たちは数々のCSS設計や命名規約を生み出しました。
OOCSS、SMACSS、BEM、SuitCSS...
そしてそれらの考えを統合したFLOCSSが登場しました。
FLOCSSは強力なツールです。
しかし、悲しいことに強力すぎて誰も使いこなすことができなかったのです。
「これってComponentとProjectどっちだ?適当でいいか」
「最初に作った人はFLOCSSを理解していたかもしれないが、あとから保守した人が理解していなくてめちゃくちゃになった」
「サーバーエンジニアなのに急にフロントを書かないといけなくなった。FLOCSS? 覚えること多すぎて無理！」

この状況から脱出するための新しい技術が生まれました。
単一ファイルコンポーネントです。

# 単一ファイルコンポーネントって?

こういうやつです。

```html:Hello.vue
<template>
  <p>{{ greeting }} World!</p>
</template>

<script>
module.export = {
  data: function() {
    return {
      greeting: 'Hello'
    }
  }
}
</script>

<style>
p {
  font-size: 2em;
  text-align: center;
}
</style>
```

ようは、template(html)、script(js), style(css)を一つのファイルにまとめて、それを使いまわそうということです。

これの何が嬉しいのかは[vueの公式](https://jp.vuejs.org/v2/guide/single-file-components.html#関心の分離について)から引用させていただきます。

> 注意すべき重要な点の1つは、関心事項の分離がファイルタイプの分離と等しくないことです。 現代の UI 開発では、コードベースを互いに織り交ぜる3つの巨大なレイヤーに分割するのではなく、それらを疎結合なコンポーネントに分割して構成する方がはるかに理にかなっています。コンポーネントの内部では、そのテンプレート、ロジック、スタイルが本質的に結合されており、実際にそれらを配置することで、コンポーネントがより一貫性と保守性に優れています。

名前が長いので以下、単一ファイルコンポーネントはSFC(Single File Components)と呼びます。

# SFCってどうやったら使えるの?

## vue.js

vue.jsを使ったプロジェクトであれば`vue-loader`を使えばすぐに使い始めることができます。
詳しくは[公式](https://jp.vuejs.org/v2/guide/single-file-components.html)を参照してください。

## Riot.js

RiotはSFCが前提なっているため、普通に使っていけば自然にSFCになるはずです。

## React

TODO

## フレームワークなし

こちら([webpack-component-loader](https://github.com/nicholaslee119/webpack-component-loader))が使えそうです。

# 新しいSFC CSS設計、その名は**Kaom(仮)**

これから説明するSFC CSS設計を**Kaom(仮)**と名付けます。

## スタイル言語の選択

**Kaom(仮)**にはmixin機能と変数機能、import機能が必須です。
なのでスタイル言語にはこれらの機能があるものを選択しましょう。
逆に言えばこれら機能があればlessでもsassでもstylusでもなんでもいいです。
post-cssを駆使してもOKです。
(指定ディレクトリの中をまとめてimportする機能があるstylusがややオススメ。)
以下はstylusのコードで説明していきます。

## ディレクトリ構成

```
src/
├ components/
│├ TOP.vue
│└ ...
├ styles/
│├ bases/
││├ _body.styl
││└ ...
│├ mixins/
││├ _card.styl
││└ ...
│├ _bases.styl
│├ _mixins.styl
│└ _variables.styl
└─ main.js
```

### components

コンポーネントを配置します。
コンポーネント内のstyleをどのように書くかは後述。

### styles

スタイルシートを配置します。

#### bases

サイト全体の設定を行います。
ここではhtmlタグや属性を指定してスタイルを記述していきます。
クラスやIDを指定してはいけません。

例えば以下のように書きます。

```stylus:_lists.styl
ul, ol
  list-style-type: none
  margin: 0
  padding: 0

dl
  margin-bottom: $small-spacing

  dt
    font-weight: bold
    margin-top: $small-spacing
  dd
    margin: 0
```

[bitters](https://github.com/thoughtbot/bitters)というCSSがあるので、こちらを参考にするといいと思います。
そのままコピーしてきてもいいかも。


#### mixins

再利用したいスタイルをmixinで定義します。

```stylus:_shadow.styl
shadow(depth = 1)
  if      depth == 1
    box-shadow: 0  2px  5px 0 rgba(0, 0, 0, .16), 0  2px 10px 0 rgba(0, 0, 0, .12)
  else if depth == 2
    box-shadow: 0  8px 17px 0 rgba(0, 0, 0,  .2), 0  6px 20px 0 rgba(0, 0, 0, .19)
  else if depth == 3
    box-shadow: 0 12px 15px 0 rgba(0, 0, 0, .24), 0 17px 50px 0 rgba(0, 0, 0, .19)
  else if depth == 4
    box-shadow: 0 16px 28px 0 rgba(0, 0, 0, .22), 0 25px 55px 0 rgba(0, 0, 0, .21)
  else if depth == 5
    box-shadow: 0 27px 24px 0 rgba(0, 0, 0,  .2), 0 40px 77px 0 rgba(0, 0, 0, .22)
  else
    box-shadow: none
```

#### _bases.styl

basesディレクトリの中を読み込見ます。
stylusの場合、2行だけ、以下のようになります。

```stylus:_bases.styl
@import './_variables.styl'
@import './bases/*'
```

#### _mixins.styl

mixinsディレクトリの中を読み込見ます。
stylusの場合、2行だけ、以下のようになります。

```stylus:_bases.styl
@import './_variables.styl'
@import './mixins/*'
```

_basesと同じですね。

#### _variables.styl

サイト全体で使用する変数を定義していきます。
こちらも[bitters](https://github.com/thoughtbot/bitters)を参考にするとどんなことを書くのかわかると思います。

#### main.js

エンドポイントとなるファイルです。
次の章で詳しく説明します。

#### 質問: Utilityはどこに置くの?

答え: Utilityを作ってはいけません。

`.mbs { margin-bottom: 10px; }`のような汎用クラスはHTML内にスタイル情報を持ち込む悪しき習慣です。
詳しくは[こちら(お前ら今すぐそのCSSフレームワーク使うのやめろ!)](http://qiita.com/isuke/items/e132669d54523c934b96)に書きました。

再利用したいスタイルはmixinを使いましょう。

## 各ファイルの読み込み方法

webpackを使った場合の各ファイルの読み込み方法です。

```js:main.js
//
// styles
//
import 'normalize.css'; // 必要な場合
import './styles/_bases.styl';
```

エンドポイントなる`main.js`では`normalize.css`などのリセットCSSと先程説明した`_bases.styl`のみ読み込みます。

`_variables.styl`や`_mixins.styl`は以下のようにします。

```coffee:webpack.config.coffee
# webpack 2.0

path = require('path')
webpack = require('webpack')

module.exports =
  entry: './src/main.js'
  output:
    path: path.resolve(__dirname, './dist')
    publicPath: '/dist/'
    filename: 'build.js'
  module:
    rules: [
      {
        test: /\.vue$/
        use:
          loader: 'vue-loader'
          options:
            loaders:
              stylus: [
                {
                  loader: 'style-loader'
                  options: sourceMap: true
                }
                {
                  loader: 'css-loader'
                  options: sourceMap: true
                }
                {
                  loader: 'stylus-loader'
                  options: sourceMap: true
                }
                {
                  loader: 'stylus-resources-loader'
                  options:
                    resources: [
                      path.resolve(__dirname, './src/styles/_variables.styl')
                      path.resolve(__dirname, './src/styles/_mixins.styl')
                    ]
                }
              ]
      }
```

こうすることですべてのコンポーネントから`@import`の記述無しで変数とmixinが使えるようになります。

## コンポーネントの記述

著者の宗教上の理由により
- framework: vue.js
- template : pug
- script : CoffeeScript2
- style : stylus
をつかって説明させていただきます。

### スタイルガイド

[Vue.js コンポーネント スタイル ガイド](https://github.com/pablohpsilva/vuejs-component-style-guide/blob/master/README-JP.md)を全面的に採用します。
Riotの場合は[RiotJS Style Guide](https://github.com/voorhoede/riotjs-style-guide)を参照してください。

### ファイル名

[Vue.js コンポーネント スタイル ガイド](https://github.com/pablohpsilva/vuejs-component-style-guide/blob/master/README-JP.md)に従い、2または3語で命名します。
それをUpperCamelCaseでファイル名にします。例) `UserList.vue`

### コンポーネント内のテンプレートとスタイル
#### CSS 命名規約

命名の一貫性を保つために命名規約を導入しましょう。
命名規約は色々有りますが、どれを使えばいいでしょうか?

単一ファイルコンポーネントでは、コンポーネントごとにスタイルが独立しているので名前の衝突の危険はありません。
この危険を回避するための意味合いが強いBEMなどは不要です。

[rscss](http://rscss.io/index.html)がわかりやすく、大げさでなく、使いやすいのでおすすめです。

#### **Kaom's Primacy(仮)**

上で「単一ファイルコンポーネントでは、コンポーネントごとにスタイルが独立しているので名前の衝突の危険はありません。」と言いました。
これは`scoped`オプションによる力です。
どのような力かこちら[vue-loader](https://vue-loader.vuejs.org/ja/features/scoped-css.html)から引用して説明します。

```html
<template lang="pug">
  .example hi
</template>

<style lang="styl" scoped>
.example
  color: red
</style>
```

これをコンパイルするとこうなります。

```html
<template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>

<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style>
```

ここで追加された`data-v-f3f3eg9`という文字列はコンポーネントごとに固有のものです。
つまり、ランダムな文字列を付与することによって、別のコンポーネントへ影響を与えることを防いでいるのです。

このように自動的にセレクターにランダムな文字列を付与することでスタイルの漏れを防ぐことを**Kaom's Primacy(仮)**と呼ぶことにします。

#### **Kaom's Roots(仮)**

templateはコンポーネント名と同じ名前(dash-case)のクラスで全体を囲みましょう。
このクラスを持ったタグを**Kaom's Roots(仮)**と呼ぶことにします。

```:UserList.vue
<template lang="pug">
.user-list //- <- これがKaom's Roots(仮)
 h1 hello
</template>

<style lang="styl" scoped>
.user-list
  background-color: $theme-color;
</style>
```

以下のように**Kaom's Roots(仮)**が複数あるのはNGです。

```html:UserList.vue_NGパターン
<template lang="pug">
.user-list1
  h1 hello
.user-list2
  h1 goodbye
</template>
```

**Kaom's Roots(仮)**は`div`である必要はありません。
以下のように`header`, `footer`, `main`, `form`, `ul`などを自由に使ってください。

```html:MainHeader.vue
<template lang="pug">
header.main-header
  h1 hello
</template>

<style lang="styl" scoped>
.main-header
  background-color: $theme-color;
</style>
```



**To be continued...**

# See also

[Vue.js命名規則、命名のコツ](https://qiita.com/isuke/items/3572e3b1c3677961f127)

---

# TODO

- [ ] 説明加筆
  - [ ] 各フレームワークでのSFCの実装方法について
  - [ ] マジックナンバーの使用について
- [ ] 用語の統一
- [ ] 例の追加
- [ ] 名前をつける(必要なら)