難しいOOCSS(オブジェクト指向CSS)の設計

以前記事にしたオブジェクト指向CSS(OOCSS)の設計方法について。

OOCSSとは、構造とスキンを分離してクラス定義し、それらを組み合わせてスタイルを定義する方法である。

OOCSSの考え方に基づいてスタイルシートを記述すると、パフォーマンスと再利用性、メンテナンス性の向上が見込めます。
しかし、OOCSSを上手に設計するのはけっこう難しいのです。なんとなくそれっぽく書いただけでは、OOCSSの導入を成功に導くことはできません。
TwitterBootstrapに代表されるCSSフレームワークなどは、高度に設計されたOOCSSと言えます。そのレベルまで完成度を高めようとするなら、そうとう高度な設計技術が求められます。

初心者が陥りやすいダメな例

> OOCSS?

.red { color: red; }
.blue { color: blue; }

一見「どんなサイトでも再利用できそうな汎用性のあるクラス定義で、CSSのプロパティを見なくてもマークアップできそう」ではありますが、これはダメな設計と言わざるを得ません。

なぜなら、この設計の行き着く先は「クラス=プロパティ」ということになるからです。
つまり、いずれこうなる↓

.color-red { color: red; }
.color-blue { color: blue; }
.background-color-white { background-color: white; }

もはやstyle属性でインラインでスタイルを定義するのと変わりません。
マークアップとCSSが分離している分、逆にパフォーマンスは悪くなってしまいます。

“構造とスキンを分離してクラス定義し、それらを組み合わせてスタイルを定義する。”というOOCSSの考え方のうち、 ”分離すること”だけに気を取られたための失敗と言えます。

ただ分離すればいいというわけではありません。
あくまでも構造とスキンの分離です。

OOCSSとは構造とスキンの分離である

構造とスキン

まず重要なのは、構造とスキンがそれぞれどのように区別されるのか?を明確にしておくことことだと思います。
id依存の従来の方法で記述されたCSSを元に考えます。

130606-0003

> 従来のCSS

<button id="redBtn">赤いボタン</button>

<style>
#redBtn {
	width: 100px;
	height: 50px;
	border: 1px solid red;
	color: red;
	background-color: #FFCCCC;
}
</style>

ここで指定されているCSSプロパティを、構造とスキンに分類するとどうなるでしょうか?
おおよそ以下のような区分になるでしょう。

width → 構造
height → 構造
border → 構造(border-colorはスキン)
color → スキン
background-color → スキン

CSSプロパティによって構造とスキンは区別されそうな雰囲気です。
これを踏まえてOOCSSで書き換えてみます。

> OOCSS

<button class="btn btn-red">赤いボタン</button>

<style>
.btn {
	width: 100px;
	height: 50px;
	border: 1px solid #CCC;
	color: black;
	background-color: #EEE;
}
.btn-red {
	border-color: red;
	color: red;
	background-color: #FFCCCC;
}
</style>

.btnという構造に対して.btn-redというスキンを組み合わせています。
また、.btnにはディフォルトのスキンもセットしてあるので、.btn単体でも使えるように配慮しています。

では、構造とスキンを分離できていない例をもうひとつ。

構造とスキンを分離できていないダメな例

<h1>Site Title</h1>

<style>
h1 {
	font-size: 18px;
	line-height: 24px;
	color: blue;
}
</style>

font-sizeプロパティ、line-heightプロパティは構造、colorプロパティはスキンと区別されるので、それらが混同している時点でダメですが、それよりも、h1タグ自体にスキンを定義してしまっているのがもっとダメです。
これでは、再利用性、汎用性、メンテナンス性のどれもが保持されなくなってしまます。
h1という構造に対しては構造のみ、しかもh1タグに対するディフォルトの構造のみを定義するべきです。

OOCSSで書き換えます。

> OOCSS

<h1 class="h1">Site Title</h1>

<style>
h1 {
	font-size: 18px;
	line-height: 24px;
}
.h1 {
	color: blue;
}
</style>

.h1というクラスの命名規則に違和感を覚えるかもしれませんが、これは特に問題ありません。
h1タグに対するスキンが1つであればこれでいいですし、h1のスキンが何パターンか存在するのであれば、複数のスキンクラスを用意すればよいでしょう。

さらに踏み込んだところでは、.h1クラスに font-size プロパティを定義して上書く場合は、px 指定ではなく em 指定の方が汎用性が高いと言えます。h1タグの基本構造から相対的にサブ構造を定義する、という考え方です。

構造とスキンのセットはサイトによって変化する

構造とスキンの区別がわかったところで、次は、その構造とスキンをどのようにクラス定義するか?ですが、構造とスキンの最適なクラス定義はサイトによって変化します。
サイト全体を見渡して、必要な構造とスキンのクラスを定義します。

どんなサイトでも使える再利用性ばかりに気を取られると、無意味に細分化しすぎて、逆に煩雑になってしまうので注意が必要です。

130606-0004

クラスの再利用性にばかり気を取られしまったダメな例

<h2 class="h2 border-radius-4 title-pink">セクションのタイトル</h2>

<style>
/* structure */
h2 {
	font-size: 14px;
	line-height: 18px;
}

/* skin */
.h2 {
	padding: 8px;
	font-weight: bold;	
}
.border-radius-4 {
	border-radius: 4px;
}
.title-pink {
	background-color: #F00480;
	color: white;
}
</style>

「border-radius: 4px というスキンは他でも使うかもしれないし、colorとbackground-colorのセットをひとつのスキンとして定義しておけば他の構造でも…」などという理由が聞こえてきそうですが、はたして、本当に再利用するのでしょうか?

仮に再利用できたとして、メンテナンス性はどうでしょうか?

この場合は以下のような設計がいいと思います。

> OOCSS

<h2 class="divider">セクションのタイトル</h2>

<style>
/* structure */
h2 {
	font-size: 14px;
	line-height: 18px;
}
/* skin */
.divider {
	padding: 8px;
	border-radius: 4px;
	background-color: #F00480;
	color: white;
	font-weight: bold;
}
</style>

h2タグの構造に対して、.dividerというスキンをあてる。それ以上の細分化は必要なし。
この判断は、サイト全体を見渡すことで決定されます。

どのサイトでも汎用的に使えるパーツとしてのクラスと、制作サイトの固有のスキンとしてのクラスは別々に考えるべきです。つまり、

OOCSSの設計の前に、サイト設計をしっかりしておくことが最も重要。

また、すべてのスタイルをクラスで定義しなければならいと思うのも勘違いです。
idとクラスは性質が違うので、その違いをきちんと認識して設計すべきですね。

OOCSSによるコーディングのプロセスをまとめると以下のような感じでしょうか。

1. サイト全体の構造とスキンパターンを設計する
2. 構造クラスを定義する
3. スキンクラスを定義する
4. クラスを組み合わせてマークアップする
(5. クラス定義をドキュメントにまとめられればなおベター)

高度に設計されたOOCSSであれば、構造とスキンのクラス定義をドキュメントにまとめることが可能になるはずですし、誰でも初見でマークアップが可能になるはずです。

という具合に、OOCSSとひとことで言っても、その設計はかなり難しいです。
一度、TwitterBootstrapなどのCSSフレームワークのCSSをざっと解析してみることをオススメします。OOCSSの設計を考える上でおおいに助けになると思います。

(おまけ)Sass == OOCSS ?

開発環境においては、SassなどのCSS拡張メタ言語を導入しているケースも多いでしょう。
開発はSass、本番にはコンパイルしたCSSをアップする、的な。
これは開発者側のメンテナンス性、再利用性を考えたときに非常に有益なものですが、、

その前に、セマンティックなクラス名とはなにか?という議論もあったりします。
以下2つのクラス名を見比べてみてください。

パターン1

<btn class="btn twitter">
<btn class="btn facebook">

パターン2

<btn class="twitterBtn">
<btn class="facebookBtn">

どちらがセマンティックなクラス名なのか?と言われれば、パターン2の方でしょうか。
でも、OOCSSなのはパターン1の方です。パターン2の方は、SassでコンパイルされたCSSによく見られる記述ですね。
ただ、コンパイル前のSassの記述は、OOCSSっぽくなっているのも事実です。

> scss

/* structure */
.btn {
...
}

/* skin */
.twitter {
...
}
.facebook {
...
}

/* structure + skin */
.twitterBtn {
...
}
.facebookBtn {
	@extend btn;
	@extend facebook;
}

Sassだけ見れば、開発者側のメンテナンス性、再利用性には期待できそうです。
がしかし、実際にユーザ側で読み込むCSSはスパゲッティ状なのでパフォーマンスの向上は見込めそうにありません。

OOCSSはパフォーマンスの向上も目的としているので、開発者側都合のメンテナンス性、再利用性だけクリアしていれば良しとするのは違うと思います。すべてはユーザのためであることを忘れてはいけません。
あっちを取ればこっちが立たず、的に難しいですね。

こちらもどうぞ: CSSの5つの分類