2014/12/20更新

[CSS] Object Oriented CSSを学んで綺麗なコードを書く

このエントリーをはてなブックマークに追加            

こんにちは、@yoheiMuneです。
12月はたくさんのアドイベントカレンダーに寄稿しようと思っていますが、今回第1弾はCSS Architecture Advent Calendar 2014です。まだ空きがあるみたいなので、書きたいという方はぜひ!
今日はOOCSSというCSS設計についてブログを書きたいと思います。

画像

Special Thanks to https://flic.kr/p/cAM8iL




目次




OOCSSとは何か

OOCSSは、Nicole Sullivanによって2009年に発表されたCSS設計手法の1つで、Object Oriented CSSの略称です。 CSSの世界にオブジェクト指向という考え方を導入することで、CSS設計の1つの道筋を示しています。


なぜ設計を学ぶべきのか

ところでなぜ設計思想を学ぶ必要があるのでしょうか。 設計やフレームワークやアーキテクチャを学ぶことは、日本史や世界史を学ぶことに近いのではないかと私は感じています。
歴史を学ぶことで先人の知恵を学ぶことができ、それを現代に活かし発展させることで新しいものを生み出すことができます。 そのために歴史を学ぶことは重要で、同様に設計を学ぶことも重要だと考えています。

今回OOCSSをブログで扱うことを決めた理由は、CSS設計をちゃんと学んでこなかったなーと感じたからです。 2009年と少し前の考え方ですが今でもとっても役に立ちますし、多くの開発現場で知らず知らずのうちに使っている人も多い設計思想です。

それではOOCSSについてみていきたいと思います。


オブジェクト指向とは

OOCSSはオブジェクト指向を取り込んだCSSの設計手法だ、と前述で表現しました。オブジェクト指向とは何でしょうか。 オブジェクト指向についての説明はたくさんありますが、私は次の説明が好きでよく使っています。

Objectの意味を辞書で調べてみると「(1)もの、(2)対象、(3)目的」といった意味があることがわかります。 ここでは「(1)もの」という意味を用います。
世の中には様々なもの(Object)が存在します。ヒト、iPhone、会社、信号機、タオルなど全てはものです。 その中で例えばヒトは次のような特徴を持っています。目がある、足がある、しゃべる、歩く、寝る、など・・・。

つまりヒトは、いくつかの特徴を持ちいくつかのアクションを取ることができるものである、と言うことができます。 逆に言うとものは、いくつかの特徴やアクションをひとまとまりにしたもの、と表現することができます。 これがオブジェクトです。

そしてObject-oriented(オブジェクトを元にした)とは、いくつかの特徴やアクションをひとまとまりにしたオブジェクトのように物事を考えること、と捉えることができます。

ここでCSSを取り上げると、ボタン、ヘッダー要素、テーブル、タブなどはすべてオブジェクトです。 例えばボタンは四角い形をしていて(=特徴1)1つのラベルを持ち(=特徴2)ます。 つまりボタンは特徴1と特徴2を持つオブジェクトです。

なお、オブジェクトのことをコンポーネントやモジュールと呼ぶこともあります。 オブジェクト指向ではいくつかの特徴や機能をひとまとまりのものとして扱います。 後続の具体例を読むことで、より理解が深まると思います。


なぜOOCSSが生まれたのか

OOCSSが発表された当初は、CSSの実装について以下のような問題を一般的に抱えていたようです。

  • 各ページ内の要素ごとに固有のCSSが存在する
  • IDセレクタを用いて再利用性がない
  • サイト運用するとどんどんとCSSが肥大化する
  • 他サイトに転用するなんて無理!

そして当時Java言語などでオブジェクト指向が大流行していて、CSSにもオブジェクト指向を取り入れられました。 OOCSSのGithubページによるとOOCSSの目的は次の通りです。

  • 少ないコードでより多くのことを実現する
  • メンテナンスができるコードにする
  • 高速に動かす

OOCSSで設計すると、ボタンなどの各オブジェクトを各ページ固有に実装するのではなく、各ページ共通で利用できるように実装します。 同じスタイルを使えばどのページでも同じ見た目にすることができ、さらに最小限のカスケードをすることで見た目を変化させることができるようになります。

それを実現するには後述する2つの原理を用います。 それら原理に従うことでメンテナンスし易さを得ることができ、そのため運用に伴うファイルサイズの肥大化を防ぐこともできます。



OOCSSの2つの原則

OOCSSを実現するために2つの原則が存在します。 日本語のブログではこのうち1つしか扱っていないものも多いので、このブログではちゃんと説明してみたいと思います。


Separate structure and skin(構造と見た目の分離)

これが意味するところは、繰り返し定義されるbackgroundやborder-colorなどの見た目は、構造とは別に定義するべきだということです。

そしてこの原則を用いることで、HTMLタグでの意味づけの代わりに、CSSクラスによる意味づけを行う事が出来るようになります。 メディア要素にはmediaクラス、メッセージテキストにはmessageといった具合にです。 クラス名で意味づけを行うことで、将来的に画像を<img>から<svg>に置き換えたとしてもCSSを修正する必要はありません。

構造と見た目を分離することで少ないコードでより多くの見た目を定義することができます。
例えば以下のように定義を別々にします。
/* ボタンの構造(structure) */
.btn {
    width: 200px;
    height: 50px;
    line-height: 50px;
    text-align: center;
}
/* ボタンの見た目(skin) */
.btn-blue {
    background-color: blue;
    color: white;
}
このように分離することで、今後.btn-red.btn-greenを追加する場合にも、少しだけコードを追加するだけで実現することができます。


Separate container and content(コンテナと内容の分離)

これが意味するところは、CSSのスタイル指定にHTMLタグを使うべきではない、ということです。 例えばh2 {...}と定義するのではなく、.category {...}と定義して、<h2 class="category">と利用するべきです。

この原則に従うことで次の3つのメリット得ることができます。

  1. クラスの付いていない<h2>などのHTML要素はデフォルトスタイルを確約できる
  2. .categoryの付与されたHTML要素は、それが<h2>ではないとしても同じ見た目を提供することができる
  3. .myObject h2のスタイルにデフォルトのh2スタイルを適用したい場合に、カスケードするスタイル定義を行う必要がない

このように、HTMLタグでのスタイリングを避けクラス名でのスタイリングを行うことで、HTMLとCSSの依存関係を下げることができます。 そして結果として実装を容易にすることができます

それでは次の章ではOOCSS実例をみていきましょう。



OOCSSを実際に使ってみる

それではOOCSSの設計を実装してみたいと思います。 ここではOOCSSをより理解するために、すでにあるコードにOOCSSの2つの原則を適用してみたいと思います。

例えば以下のようなリストがあるとしましょう。
  • Good Morning
  • Hello
  • Good Night
実装は次の通りです。
<!--HTML-->
<ul class="list">
    <li>Good Morning</li>
    <li>Hello</li>
    <li>Good Night</li>
</ul>
/*CSS*/
.list {
    padding: 8px;
    list-style: none;
}
.list li {
    position: relative;
    display: block;
    padding: 4px 8px;
    font-size: 12px;
    color: #555500;
    font-weight: bold;
    border-bottom: 1px solid #aaaaaa;
    background-color: rgba(0, 0, 255, .1);
}
.list li:after {
    position: absolute;
    top: 50%;
    right: 8px;
    width: 12px;
    height: 12px;
    content: ">";
    font-size: 12px;
    line-height: 12px;
    margin-top: -6px;
}


構造と見た目の分離の原理を適用する

まずは「構造と見た目の分離」の原理を適用します。 このサンプル内での見た目の定義は.list liの中のcolorbackground-colorなので、それらを分離します。
/*「構造と見た目の分離」の原理を適用したCSS*/
.list {/*同じため省略*/}
.list li {
    position: relative;
    display: block;
    padding: 4px 8px;
    font-size: 12px;
    font-weight: bold;
    border-bottom: 1px solid #aaaaaa;
}
/*見た目だけを分離したクラス*/
.list.list-blue li {
    color: #555500;
    background-color: rgba(0, 0, 255, .1);    
}
.list li:after {/*同じため省略*/}
そしてHTMLを以下のように修正します。
<!--list-blueクラスを付与する-->
<ul class="list list-blue">
    <li>Good Morning</li>
    <li>Hello</li>
    <li>Good Night</li>
</ul>
このように実装すれば、今後同じ構造に違う見た目を定義する場合にとても簡単に対応することができます。
/*例えば赤色のリストを作る場合、以下を追加するだけで見た目を追加できる*/
.list.list-red li {
    color: #555500;
    background-color: rgba(255, 0, 0, .1);
}
構造と見た目の分離を行うことで、変更に柔軟なCSSになっていいですね。


コンテナと内容の分離の原則を適用する

次に「コンテナと内容の分離」の原理を適用します。 上記のリストではulliを使ったHTMLが前提となっていますが、例えば以下のようなマークアップで同じ見た目を行いたい場合にはどうすれば良いのでしょうか?
<!--HTML-->
<div>
    <a href="#">Good Morning</a>
    <a href="#">Hello</a>
    <a href="#">Good Night</a>
</div>
異なるHTML構造に同じCSSを使って同じ見た目を提供するためには、CSS内でHTMLタグを使った装飾をしないことです。 CSSを以下のように修正することでulliなどのHTMLタグでの装飾を省くことができます。
.list {/*同じため省略*/}

/*liの代わりに.list-itemというクラス名を用いる*/
.list .list-item {
    position: relative;
    display: block;
    padding: 4px 8px;
    font-size: 12px;
    font-weight: bold;
    border-bottom: 1px solid #aaaaaa;
}
.list.list-blue .list-item {
    color: #555500;
    background-color: rgba(0, 0, 255, .1);    
}

.list li:after {/*同じため省略*/}
<!--list-itemクラスを用いて装飾を行う-->
<div class="list list-blue">
    <a class="list-item" href="#">Good Morning</a>
    <a class="list-item" href="#">Hello</a>
    <a class="list-item" href="#">Good Night</a>
</div>
このようにHTML要素に依存しない定義を行うことで、異なるHTML構造に同じスタイルを適用できるようになるので、CSSの実装が少なくなります。



OOCSSの難しいところ

さてここまでOOCSSを学んできましたが、実戦で使うにはいくつか悩んでしまう点が存在します。 この章では難しいと感じる事例をいくつか紹介したいと思います。


何が構造で何が見た目なのか

第1原則の構造と見た目の分離とありますが、CSSプロパティのうち何が構造で何が見た目なのでしょうか。 基本的には色味に関するスタイル(color, background, border-color, など)が見た目に関するもので、それ以外は構造を定義するものと考えれば良いと思います。

しかしサイトのデザインによって、構造として扱うべきか見た目として扱うべきか変わるCSSプロパティもあると思います。 例えばborder-radiusの場合、丸みがサイト内で統一されていれば構造に入れて良いと思いますし、丸みの異なるボタンなどが複数存在するのであれば見た目に入れても良いと思います。

何が構造で何が見た目なのか、プロジェクトに合わせてある程度柔軟に対応する必要があります。


サイト全体で使う共通スタイル

多くのプロジェクトでは、以下のようなサイト全体で用いるグローバルスタイルを定義します。
/*フォント色の定義*/
.fc-red   {color: #ff0000 !important;}
.fc-blue  {color: #0000ff !important;}
.fc-green {color: #00ff00 !important;}
.fc-gray  {color: #333333 !important;}
.fc-gray2 {color: #777777 !important;}
/*マージン定義*/
.mt-0  {margin-top: 0 !important;}
.mt-10 {margin-top: 10px !important;}
.mt-20 {margin-top: 20px !important;}
.mt-30 {margin-top: 30px !important;}
.mt-40 {margin-top: 40px !important;}
/*横幅*/
.w-60p  {width:  60% !important;}
.w-80p  {width:  80% !important;}
.w-100p {width: 100% !important;}
/*など共通スタイルが続く*/
基本的にはOOCSSでスタイル設計しつつ、イレギュラーなものはグローバルスタイルでスタイリングすると、OOCSSに固執しすぎずに実装ができて良いと思います。 ただし、グローバルスタイルばかりを使ってマークアップするとstyle属性を使ったマークアップとあんまり変わらないので、そこはさじ加減が必要です。

OOCSSに固執しすぎずに柔軟にCSS設計ができると、よりサイトの特性に合った実装ができて良いですね。


構造にバリエーションがある場合はどうする

サイト制作ではよく、同じ構造だがサイズが違う(通常ボタンと大きいボタン)といった構造のバリエーションが存在します。 この場合はどうすれば良いでしょうか。

これは、オブジェクトの単位を考えることで解決できます。
例えばサイズごとに違うオブジェクトだと考えば、以下のようなCSSになるでしょう。
.btn {
    width: 200px;
    height: 40px;
    /*その他省略*/
}
.btn-large {
    width: 200px;
    height: 50px;
    /*その他省略*/
}
しかし多くの場合、「ボタン = 1オブジェクト」と考えて以下のように実装する方が良いです。
.btn {
    width: 200px;
    height: 40px;
}
.btn.btn-large {
    height: 50px;
}
Bootstrapはこのような考えで、構造のバリエーションを.btn-lgなどのクラス定義で対応しています。

同じ機能で構造にバリエーションがある場合は、慎重にオブジェクトの単位を考えて設計していきたいものです。



参考資料

このブログを書くために以下の記事を参考にしました。ありがとうございました。

Object Oriented CSS | github.com

An Introduction To Object Oriented CSS | www.smashingmagazine.com/

Object Oriented CSS | www.slideshare.net/

OOCSS(オブジェクト指向CSS)のススメ | hijiriworld.com



他のアドベントカレンダー

今回の記事も含め、以下の記事を2014年アドベントカレンダーとして執筆しました。 気になる記事がありましたら幸いです。

- [CSS] Object Oriented CSSを学んで綺麗なコードを書く

- [MongoDB] フロントエンドエンジニアにオススメなデータベース、MongoDBに入門

- [MongoDB] フロントエンドエンジニアにもできるMongoDBを使ったログ分析

- [JavaScript] 最近のjQueryとの付き合い方いろいろ

- [フロントエンド] スキャフォールド機能を提供するYEOMANに入門する

最後に

さていかがでしたでしょうか?オブジェクト指向を取り込んだCSS設計、なかなか楽しいですね!
設計思想やフレームワークを学ぶことで芸術的なコードを書くことができるようになるので、これからもドシドシ勉強してこのブログにアウトプットしたいと思います。

では、CSS Architecture Advent Calendar 2014の記事は以上です。次は誰だろうー。

今後も本ブログでは、フロントエンドに関する情報を書きたいと思います。気になった方はぜひ、本ブログのRSSTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。