はじめに
谷拓樹さんのWEB制作者のためのCSS設計の教科書を読み、自分なりにまとめたものです。
自分のメモとして残しておきたいので、詳細を多少端折っていますので、気になる方は購入してみてください。
数回に分けて投稿する予定です。
SMACSS
元YAHOO!のデベロッパーの、ジョナサン・スヌークによって、OOCSSのコンセプトをベースに作られたフロントエンドのガイドラインである。
※SMACSSはCSSフレームワーク、ライブラリのように設計やページ構築を容易にしてくれるものコードセットがあるわけではない。
以下SMACSSの特徴について
カテゴライズ
ポイントの一つは、パターンを抽出しやすくするためのカテゴリを容易していること。単純な例を挙げると、散らかったものを片付けるためには、何かしらのカテゴリに分類したケースを用意して。条件に合うものをそのケースに入れていく方が容易であるということに似ている。
以下はSMACSSが提案するゆるいカテゴリである。
- Base
各要素のデフォルトのスタイル。
reset.css
normalize.css
body要素に適応する全体の背景や、フォントサイズなど
基本的にBaseに定義されたものは、他の要素全てに影響を与えることになってしまうので、よほどのものが無い限りは書き換えることはない。
それ故に、widthやmargin、paddingなどは持たせないようにするのがよい。
- Layout
ここに属するものは、慣習的にいえば、IDやを用いて定義されるようなヘッダー、フッター、コンテンツエリア、サイドバーというような構成の大枠、セクションをつくる要素へのルールなど。
基本的にはページごとに1つしか存在しないようなものをLayoutに記載する。
l-grid {
overflow: hidden;
margin-left: -5px;
…...
}
Layoutカテゴリのコンポーネントであるということを示すために、命名規則として、"l-“をつけることを推奨している。
しかし、それがどういった意図を持つのかを伝えることが重要なので、"layout-“でも、チーム内で定めてもよい。
- Module
Layoutのパターンを除けば、ページを構成するほぼ全てがこのカテゴリに属すると考えてよい。ボタン、見出し、リンクなどあらゆる再利用できるオブジェクトがModuleに記載される。
Layoutのように接頭辞をつけることは特に推奨していないが、"m-“や”module-“と付けても構わない。
- State
Javascriptなどによる制御によって切り替わるような状態を表すルールが該当する。
display: none;を適用させるための、.js-hiddenというようなクラス
"is-“ というプレフィックスをつけるのもポイントである。
.tab is-active {
background-color: #489;
color: #FFF;
}
.is-active {
background-color: #489;
color: #FFF;
font-weight: bold;
}
注意すべき点は、.is-activeのような要素に色や、サイズなどの指定をもたせるべきではない。というのも他の意図でつけられた.is-activeにスタイルを汚染される可能性があるからである。もし指定するものであれば、上記の.tab is-activeのように限定的にするべきである。
また、スマートフォンなどの多岐にわたるディスプレイサイズに対応するようなメディアクエリもStateに記述する要素である。
- Theme
いわゆるテーマを切り替えたりするような機能が求められるCSSのときに考慮するといいカテゴリである。
Layoutなどと同様に、theme-のような接頭辞のクラスを付与することが推奨されている。
命名規則
alert-success {
….
}
alert-warnig {
….
}
alert-error {
….
}
ポイントは.alertというコンポーネントがあったときに、その構造をベースとしたwarningという拡張をするときには、ベースとなるコンポーネント名を名前空間として継承した命名にすること。
こうした名前空間に加えた命名によって解決できるのは次の3つ。
- クラス名の重複によるスタイルの競合と汚染のリスク減
- クラス名をみて、どのコンポーネントの拡張かわかる
- セレクタの詳細度を減らせる
クラス名がやや冗長になることはあるが、これらの問題を解決できることはCSSのにおいては大きなメリットになる。
BEM
CSSの設計の最も難しいとも言える命名規則において、独特なアプローチによって問題を解決している。
BEMはフロントエンド開発手法で使われている命名規則。
ロシアのYandexというポータル、Webアプリケーションを提供している会社のフロントエンド開発チームが考えた開発手法。
Block、Element、Modifierの略で、ページを構成する要素、つまりオブジェクト/コンポーネントをこの3つに分類して考える。
Block
BlockはSMACSSの解説に用いた、アラートメッセージのパターンでいうところの.alertがBlockに該当する。
Element
ElementはBlockを構成する要素。こちらもアラートメッセージの例で説明すると、.alert-titleや、alert-bodyといったものがElementに当たる。
命名の際には、.alert__title、alert__bodyのようにアンダースコア__を2つつなげる。
Block__Element
Modifier
BlockまたはElementのバリエーションの違いを表すときに利用される。.alert-warningはalertのバリエーションの違いのものなので、BEMではModifierに当たる。
Elementの場合はアンダースコア__2つでつなげたの対して、Modifierはアンダースコア_1つで名前を区切るというルールを設けることによって、役割を明白にする。
Block__Element_Modifier
Block_Modifier
SMACSSの中でも説明したように、コンポーネントを構成する要素に対しては、そのコンポーネント名を名前空間として扱い、クラス名に接頭辞をつかぬことで、どれがコンポーネントを構成する要素か明らかにでき、スタイルを汚染するリスクを抑えている。
ここで更にBEMの命名規則を重ねる事によって、
・マークアップを見れば、どのクラスがコンポーネントのどのような機能を持つのか、どういった構造になっているのかが明らかになる。
・通常よりもユニークに命名されているので、スタイルの汚染リスクが減る
といったメリットが生まれる。
慣れないうちは、見慣れない命名に気持ち悪さや冗長さを感じるかもしれないが、それ以上に他の開発者が見ても明確さがあるのはBEMの強みである。
BEMの利用に重要なのは、ElementかModifierかといった、役割の明確さを示すことであり、クラス名にアンダースコアを使うかどうかはあまり重要ではない。開発するグループ全体でそのルールが一貫しているかどうかということ。
BEMの命名規則をより、見た目でわかりやすくしたものの中に、MindBEMdingというものがある。
本来、ElementとModifierの間はアンダースコア_1つでつなげるというのが慣習であるが、これでは見た目で判断するのが難しいときもある。そこでMindBEMdingはElementとModifierの間をハイフン--2つでつなげるというルールにしている。
Block__Element--Modifier
Element--Modifier
なぜ二つなのかというと、ハイフン1つのときは複数単語の区切りなどに利用される為である。
search-box--alert
search-box__button
あらゆる開発者がこういった形で独自のフレームワークやライブラリを開発し、Githubに公開している。
米Yahoo!が公開しているPureやAdobeのTopCoatも注目。
pure http://purecss.io/
Topcoat http://topcoat.io/
MCSS
MCSS (Multilayer CSS)の略。複数のレイヤー構成を元にしてCSSのを設計する。
そのレイヤー構成のルールさえ従えば、SMACSSなどと同様に、特別なツールを必要とせずに拡張性の高いCSSを書くことができる。
↓
Foundation
Base
Project
Cosmetic
Context
Foundationから順に上にレイヤーが重なっていくイメージ。
基本原則
コンポーネントの持つスタイルは、1つのセクションの中でまとめられる、BEMでいう、Blockと、そのElementとModifierはまとめて同じ箇所に記述されるべき、ということ。
.alert {...}
.alert .__warning {...}
.alert_title {...}
ポイントはModifierの記述。ElementについてはオリジナルのBEMと同じく、アンダースコア_1つだが、Modifierに関しては、Block名を省きアンダースコア__2つから始まる命名で、Blockのクラスと結合したセレクタになっている。
- 命名上、Blockを省略することによって、コードがシンプルになる。
.alert__warning .alert_title__warning {...}
.alert .alert_title .__warning {...}
- マークアップ上、ElementとModifierとの区別がつきやすくなる。
.alert__warning .alert_title {...}
.alert .alert_title .__warning {...}
しかし、__warning単体のセレクタのルールを書いてしまうと、それがいずれかのコンポーネントのスタイルを汚染してしまう可能性がある。
.alert {...}
.alert .icon {...}
.icon {...}
.alert .icon {…} #次のような記述はしない
他に推奨事項として、可能な限りクラス名を略語にすることが挙げられている。
ただし、あまり一般的でない略語や短すぎて衝突(重複)するようなものは避けたほうがよい。
Icon module
.icn {...}
Button module
btn {...}
Foundation
SMACSSでいうところのBaseカテゴリと同様。
プロジェクトの土台として、reset.cssやnormalize.cssを用いた各要素のスタイルの初期化を行う。
読み込み順としても、Foundationとなるスタイルは最初に読み込まれなくてはならないことに注意が必要である。
Base
SMACSSでいう、Moduleカテゴリに近い。プロジェクトの各所で再利用でき抽象的である要素が該当する。理想を言えば、他のプロジェクトでも利用できるくらい、抽象的である要素が該当する。
例えば、単純なボタン、フォーム、シンプルなリストやナビゲーションといったもので、他のレイヤーから容易に拡張・変更できるようなものである必要がある。
さらに、世の中でよく使われているBootstrapやその他のグリッドCSSのフレームワークの一部分をこのレイヤーに含めるといいとされている。
Baseレイヤーにおけるカスケーディングは、次のようなルールである。
- BaseレイヤーコンポーネントからBaseレイヤーコンポーネントを上書きできる。
- Baseレイヤーコンポーネントから一つ上のProjectレイヤーコンポーネントを上書きできない。
このように下層のレイヤーから上書きを禁止することによって、レイヤーの混同とそれによる複雑化、破綻のリスクを抑えるとができる。
Project
Baseコンポーネントよりも具体的な、ページを構成する要素を含む。それらは登録フォームやログインエリアのブロック、コメントリストのような要素である。
Projectレイヤー内で、1つ下層のBaseレイヤーを用いるような場合、クラスを組み合わせ上書きすることが可能。
以下がその例
#Base Layer
.block-list {...}
.block-list_item {
border-bottom 1px solid #EEE;
padding: 0.3em 1em;
}
#Project Layer
.comment-list {...}
.comment-list .block-list_item {
padding: 0.5em 1em;
}
Projectレイヤーにおけるカスケーディングは、次のようなルールである。
・ProjectレイヤーコンポーネントからBaseレイヤーコンポーネントを上書きできる。
・Projectレイヤーコンポーネントから一つ上のProjectレイヤーコンポーネントを上書きできる。
理想をいえば、Baseレイヤーで作られる抽象的な汎用的なコンポーネントによって構成できればいいのだが、現実的にはProjectレイヤーが厚くなり、このレイヤーのコンポーネントで構成されることになる。
Cosmetic
ちょっとしたスタイルがここのCosmeticに含まれる。他の設計やフレームワークなどでは、ヘルパーやユーティリティなどと呼ばれるような汎用的なスタイルを持つクラスが有り、それに近い。
- リンクカラー
- 少数プロパティで構成されるCSSのクラス
- グローバルなModifier
.al {#Action Link
color: #C90;
}
.font-size_XL{
font-size; 48px;
}
hidden {
display: none;
}
このようにどこのページでも汎用的に利用できるものが記載される。
しかしこのCosmeticレイヤーのスタイルに頼りすぎないことも大切。これらのルールは、多くとも1つの要素に3つまでと言うようなルールもドキュメントには記載されている。
Cosmeticレイヤーにおけるカスケーディングは、次のようなルールである。
- Cosmeticレイヤー自信を含め、例外のコンテキストレイヤー以外のレイヤーから上書きできない。
たとえばfont-size_XLのようなルールが、あるProjectレイヤーのときにだけサイズが変わってしまったら、混乱を招きそうだと言うことは想像がつくことである。
Context
特定のブラウザや、デバイス向けあるいは、ログイン中のときメディアクエリによる特定条件化にある場合などに例外的なスタイルを用意するためのレイヤー。
他のレイヤーとは異なり、Contextレイヤーとしてのセクションは基本的に持たずに、各コンポーネントのセクション内で記述されるべきである。