CSSコンポーネント設計のアイデアの活かし方について考えてみた


[Sketchy Talks #1 CSSについて学ぶ](http://connpass.com/event/32342/ "Sketchy Talks #1 CSSについて学ぶ")の登壇資料として。
（ここに書いてたらスライドを作る時間がなくなりました。）

#なぜ”設計”が必要か？

**良いCSSを作るため。**
この一言に集約されるかなと思います。
htmlをイケてる感じにしてくれるCSSですが、そのイケてる感を出そうとすればするほど記述はどんどんと長くなり複雑化してきます。
では、「良いCSS」とは何なのか？

##良いCSSの定義

この本の記載内容によると以下の４つ。

- 予測しやすい
- 再利用しやすい
- 保守しやすい
- 拡張しやすい

#正直、結構ムズイ

言われてみれば納得。でもこれを全て叶えるCSSをつくるのってなかなか大変。
まだまだ経験値の浅い私がアレコレ意識しすぎると

**「ここってこういう風にしたほうが良かったかな・・・でも今直したら大変やんなぁ〜・・・でもでもあとあと"やっぱりこうしたい！"ってなったら大変やし・・・」**

とパニックになって本当に良いことがない（笑）

「保守のしやすさ」「拡張のしやすさ」は作るモノの規模や今後の展望と関係するような気がするので、個人的にはまず **予測しやすい** こと **再利用しやすい** の２点ぐらいを意識してやるのがいいかなと思ってます。

#とりあえずコンポーネント設計について調べてみた

参考図書は[これ](https://www.amazon.co.jp/Web%E5%88%B6%E4%BD%9C%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AECSS%E8%A8%AD%E8%A8%88%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E3%83%A2%E3%83%80%E3%83%B3Web%E9%96%8B%E7%99%BA%E3%81%AB%E6%AC%A0%E3%81%8B%E3%81%9B%E3%81%AA%E3%81%84%E3%80%8C%E4%BF%AE%E6%AD%A3%E3%81%97%E3%82%84%E3%81%99%E3%81%84CSS%E3%80%8D%E3%81%AE%E8%A8%AD%E8%A8%88%E6%89%8B%E6%B3%95-%E8%B0%B7-%E6%8B%93%E6%A8%B9/dp/4844336355?ie=UTF8&*Version*=1&*entries*=0 "これ")。

「予測しやすい」「再利用しやすい」の２つだけを意識する、とは言ったってそれだってなかなか簡単じゃない。
そこで参考になるんじゃないかとコンポーネント設計のアイデアについての章をチェックしてみたところ、「これは私もやってるわー」ってこともあれば「あーなるほどね」ってこともあったのでとりあえず **OOCSS** と **SMACSS** についてまとめてみる。

#OOCSS

###このルールを頭にいれるだけでもかなり見やすいCSSになりそう

Object Oriented CSSの略で、 **オブジェクト指向プログラミング(OOP)** の概念を取り入れてる。
[Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0 "Wikipedia")によると

>オブジェクト指向プログラミング（オブジェクトしこうプログラミング、英: object-oriented programming, OOP）とは、相互にメッセージ (message) を送りあうオブジェクト (object) の集まりとしてプログラムを構成する技法である。

らしいけど、まぁ細かいことはさておき。
私はOOPを **「よく使うヤツは塊にして、足りないものはその場で追加」**みたいな概念なのかなーと解釈しています。

##構造と見た目（スキン）をわける

こんな感じの3種類のBoxがあったとき。

![無題のプレゼンテーション.jpg](https://qiita-image-store.s3.amazonaws.com/0/109241/155f1ff8-f42e-80bd-5113-6b5985af0fba.jpeg)

見ての通り **色が違うだけ** で **ほぼ同じ形** なわけです。
これを

- 見た目（ボーダーの色）
- 構造（Boxの幅、テキスト中央揃え、角丸）

と分けて書く。

```css:common.css
/*見た目*/
.red {
	border: 1px solid red;
}
.blue {
	border: 1px solid blue;
}
.yellow {
	border: 1px solid yellow;
}

/*構造*/
.box {
	width: 10em;
	text-align: center;
	border-radius: 6px
}
```

```html:index.html
<div class="red box">redBox</div>
<div class="blue box">blueBox</div>
<div class="yellow box">yellowBox</div>
```

###メリット

<div class="" style="border:1px solid green; border-radius: 6px; text-align:center; width: 10em;">greenBox</div>
&nbsp;
<div class="" style="border:1px solid green; background-color: green; color: white; border-radius: 6px; text-align:center; width: 10em;">reversalGreenBox</div>

こんな色違いとか反転したやつとかが出てきたときに **見た目** のスタイルだけ追加すればいいのでラク。

```css:common.css
/*見た目*/
.green {
	border: 1px solid green;
}
.reversalGreen {
	border: 1px solid green;
	background-color: green;
	color: white;
}
```

```html:index.html
<div class="green box">greenBox</div>
<div class="reversalGreen box">reversalGreenBox</div>
```

##コンテナーとコンテンツを分離

<div style="border: 1px solid red">
	(.redBox)<br>
	<strong style="font-size: 1.5em">文章がはいります</strong>
</div>
&nbsp;
<div style="border: 1px solid blue">
	(.blueBox)<br>
	<strong style="font-size: 1.5em">文章がはいります</strong>
</div>

```html.index.html
<div class="redBox">
	<p>文章がはいります</p>
</div>
<div class="blueBox">
	<p>文章がはいります</p>
</div>
```


２つのdivに内包されているpタグ **"文章がはいります"** のスタイル

- `font-weight: bold;`
- `font-size: 1.5em`

を指定するとき、私の今までならコードはこんな感じ。

```css:common.css
.redBox p, .blueBox p {
	font-weight: bold;
	font-size: 1.5em;
}
```

###増えたらどうする？

<div style="border: 1px solid green">
	(.greenBox)<br>
	<strong style="font-size: 2em">文章がはいります</strong>
</div>

```html.index.html
<div class="greenBox">
	<p>文章がはいります</p>
</div>
```

しかも若干文字が大きい。

```css:common.css
.redBox p, .blueBox p {
	font-weight: bold;
	font-size: 1.5em;
}
.greenBox p {
	font-weight: bold;
	font-size: 2em;
}
```

こう？

###また増えたら？？

<div style="border: 1px solid orange">
	(.orangeBox)<br>
	<strong style="font-size: 1em">文章がはいります</strong>
</div>

```html.index.html
<div class="orangeBox">
	<p>文章がはいります</p>
</div>
```

今度は小さいだと？

```css:common.css
.redBox p, .blueBox p {
	font-weight: bold;
	font-size: 1.5em;
}
.greenBox p {
	font-weight: bold;
	font-size: 2em;
}
.orangeBox p {
	font-weight: bold;
	font-size: 1em;
}
```

ここまでくると今後も **大・中・小** の３パターンを用意しておいたほうがいいのかも、となります。
というわけで、

###場所に依存しないセレクタにする

<div style="border: 1px solid green">
	(.greenBox)<br>
	<strong style="font-size: 2em">文章がはいります</strong>
</div><br>
<div style="border: 1px solid red">
	(.redBox)<br>
	<strong style="font-size: 1.5em">文章がはいります</strong>
</div><br>
<div style="border: 1px solid orange">
	(.orangeBox)<br>
	<strong style="font-size: 1em">文章がはいります</strong>
</div>

```html.index.html
<div class="greenBox">
	<p class="big-p">文章がはいります</p>
</div>
<div class="redBox">
	<p class="middle-p">文章がはいります</p>
</div>
<div class="orangeBox">
	<p class="small-p">文章がはいります</p>
</div>
```

```css.common.css
.big-p {
	font-weight: bold;
	font-size: 2em;
}
.middle-p {
	font-weight: bold;
	font-size: 1.5em;
}
.small-p {
	font-weight: bold;
	font-size: 1em;
}
```

こうすることで場所（コンテナー）に関係なく使えるようになる、と。

#SMACSS（スマックス）

###ページ内のどのカテゴリに関する記述なのかがわかりやすくなるルール

OOCSSのコンセプトをベースに作られたフロントエンドに関するガイドライン。
OOCSSをより実践的に学ぶためのアイデアらしい。

##カテゴライズ

SMACSSではCSSの記述を次の５つのカテゴリーに分けて考える。

- Base（全体）
- Layout（レイアウト）
- Module（まとまり）
- State（状態）
- Theme（テーマ）

**Layout、State、Theme** についてはそれぞれ接頭語
`l-`、`is-`、`theme-`を付けることが推奨されている。（理由は後述）

###- Base

#####全体の背景色、フォントの種類などhtmlやbodyに書くようなものが **Base**。

###- Layout

#####ページのレイアウトに関する要素。

今までは `#header` `#footer` のように全体のレイアウトに関してはidを使っていましたが、最近社内では詳細度の問題から **「できるだけidは使わない」**方針。
とはいえ、やはりclassにすると「他の場所でも使っちゃったらどうしよー」なんて思うわけです。
そこでSMACSSが推奨している接頭語`l-`を使うといいんじゃないかなーと。

```html:index.html
.l-header {
	background-color: black;
}
.l-footer {
	background-color: blue;
	color: white;
	height: 40px;
}
```

`l-`は **"layout"**の意味なので、「これはレイアウトに関するスタイルだな！」とわかり良い感じに。
他にも **グリッドレイアウト**なんかにも使うといいっぽい。

```html:index.html
<ul class="l-grid">
	<li>てすと</li>
	<li>てすと</li>
	<li>てすと</li>
</ul>
```

```css:common.css
.l-grid {
	paddin: 5px;
	margin-top: 10px;
}
```

###- Module

#####その他のまとまり。

ボタンとか見出しとか複数の要素で構成されている **何回も使いそうなやつ**、という感じ？

###- State

#####javascriptで変わるような"状態"を表すもの。

`display:none`を指定するセレクタとかに。
あと、`is-`だけじゃ対象がどれなのか分かりにくかったりだとかもあるので`alert-`のように少し具体性があったほうがいいっぽい。

```css:common.css
.is-alert-hidden {
	display:none
}	
```

###- Theme

#####構成は同じで、複数のテーマを持たせたい（色とか）ときに使う。
先述の`.l-header`がページによって色を変えたい場合。

<div style="width: 40em; height: 3em; background-color: skyblue; color: white;">.thema-sea .l-header</div><br>
<div style="width: 40em; height: 3em; background-color: green; color: white;">.thema-sea .l-header</div>

```html:sea.html
<div class=".theme-sea .l-header">・・・</div>
```
```html:woods.html
<div class=".theme-woods .l-header">・・・</div>
```

cssは共通の`common.css`だとしたとき、こうすると良い感じ。

```css:common.css
.l-header {
	height: 60px;
	padding-top: 10px;
	padding-bottom: 15px;
}
.theme-sea {
	background-color: skyblue;
	color: white;
}
.theme-woods {
	background-color: green;
	color: white;
}
```

#まずは「破綻しにくいCSSを作る」という意識が大事そう

あくまでこれらは「良いCSSを作る」という **目的を達成するための手段。**
命名規則などの型にとらわれすぎず、ちょっとずつ取り入れていくのがCSS設計初心者には良いのかなーと思いました。