はじめに
CSSの設計手法については、数年前からたくさんのブログや書籍で詳細に取り上げられています。
今回はバックエンドからフロントエンドに来られたエンジニアさんや、コーディングに知識のあるディレクター・企画職の方にナレッジを共有したいと思い、まとめてみました。
定番のOOCSS,SMACS,BEMに加え、2016年に普及し始めたECSSについても取り上げます。
なぜCSS設計が必要なのか
CSSは単純で多くの人が簡単に操作することができるという素晴らしい特性を持っています。
しかしその特性のために、複数人の関わる大規模なサービスや、長期的なメンテナンスが必要なサービスではすぐに破綻してしまう(なんでCSSすぐ死んでしまうん?)という弱点も抱えています。
大規模なサービスの初期デザインをコーディングに起こす際は、自分以外の人でも容易に理解できてメンテナンスしやすい設計を行う能力が必須です。
また、複数の設計手法についての知識を持っておくことで、慣れ親しんだ設計手法と異なるものが採用されているプロジェクトにジョインするときも、即戦力になることができます。
ということで、よく利用されている4つの設計手法を下記にまとめます。
OOCSS
Object Oriented CSS
コーダー利用率:15.7% 1
概要
・オブジェクト指向をCSSに取り入れる
・構造とスキン(見た目)を分離する
・コンテナと内容を分離する
構造とスキン(見た目)の分離とは
Webサイトには必ずある、ボタンを例にして考えます。
構造とは、ボタンの形を作るものです。
width,height,border,padding,margin
などにあたります。
そしてスキンとは見た目、スタイルになります。
color,border-color,background-color
などです。
構造をスキンと分離することで、機能によって色が違うボタンを作ったり、それをサイト全体で再利用したりするのが簡単で便利になります。
/* 構造 */
.btn {
width: 100px;
height: 20px;
line-height: 1.5;
text-align: center;
}
/* スキン */
.btn-caution {
background-color: red;
}
.btn-submit{
background-color: green;
}
.btn-plane{
background-color: gray;
}
<a class="btn btn-caution">注意ボタン</a>
<a class="btn btn-submit">送信ボタン</a>
<a class="btn btn-plane">普通のボタン</a>
コンテナと内容の分離とは
HTML要素や構造、コンポーネントが存在する「場所」に依存しないようにします。
webサイトによくある見出しを例に考えます。
下記は悪い見本です。
ヘッダー内にある見出しにスタイルを当てるときこのようにすると、他のsectionにも同じ見出しを入れたい...という時に再利用できなくなります。
.header .heading {
font-size: 18px;
font-weight: bold;
text-align: center;
color: red;
}
このため、OOCSSでは以下のようにコンテナにclassをつけてスタイルを当てることが推奨されます。
.heading {
font-size: 18px;
text-align: center;
}
.heading .heading-big {
color: red;
font-weight: bold;
}
これで、他のsectionに見出しをいれたいときはdivタグなどを置いて.heading .heading-big
というclassを当てるだけでスタイルを流用することができます。
ディレクトリ構成の例
├── common
│ ├── css ── common.css
│ ├── img
│ └── js
│
└── page
├── css
│ ├── p01.css
│ └── p02.css
├── img
└── js
メリット
使えるものはどんどん共通化することで、CSSのコード量を減らせます。
デメリット
コードが複雑になります。共通化によってどこにどのスタイルが当たるのか、CSSの見通しは悪くなることがあります。
特に、CSSファイルの切り分けがうまくできていなかったり、どのパーツが共通化されているのかわかるガイドがない場合、新しくプロジェクトに参加するメンバーは初めに時間をかけてコードを読み、苦心して設計思想を理解することになります。
SMACSS
Scalable and Modular Architecture for CSS
コーダー利用率:14.7%
概要
・スタイルをベース、レイアウト、モジュール、ステート、テーマの5つに分割する
・レイアウトにはlayout-, .l- などの接頭辞をつける
・ステートにはis- 接頭辞をつける
・テーマにはtheme- 接頭辞をつける
・モジュールにはmod-, m-などの接頭辞はつけない
ベースとは
要素セレクタbody、li
など、属性セレクタinput[type=button]など
、擬似クラスセレクタa:hoverなど
です。セレクタそのもののみが対象で、idはベースには記述しません。
また、CSSリセット(reset.cssやnormalize.cssなど)もベースに含まれます。
レイアウトとは
セクションやエリアなど、大きな区切りとなる部分を定義します。
(.layout-header, .layout-footer, .layout-nav, .layout-mainなど)
モジュールとは
部品ごとのスタイルを指定します。(.logo, .tabs, .box, .list, .formなど)
接頭辞をつけないので、「接頭辞がなければモジュール」とすぐに認識することができます。
モジュール内のパーツには全てclassをつける必要はなく、h1,li,aなどは要素セレクタにスタイルを当ててもOKです。
ステート(状態)とは
JavaScriptで状態を変化させるときのパターン分けなどに使います。
(.is-disabled, .is-active, is-errorなど)
テーマとは
あまり利用されません。ページ全体のカラーやテーマなどを選択して変えられるサイトで使います。
ディレクトリ構成の例
├── style.scss
│
├── base
│ ├── _base.scss
│ └── _mixins.scss
│
├── layout
│ ├── _top.scss
│ ├── _product.scss
│ └── _grid.scss
│
└── module
├── _btn.scss
├── _logo.scss
└── _nav.scsss
注) SMACSSはSassの利用を前提とし、ファイルをモジュールやレイアウトごとに細分化した後にすべてstyle.scssに@importしてコンパイルすることを推奨しています。
メリット
コード量が少なくなり、メンテナンス性が向上します。
例えば「ヘッダーのデザインと、submitボタンの色を変えたい」などというとき、どのファイルを修正すればいいのか一目瞭然です。
デメリット
生のCSSのみを使うプロジェクトでは、ファイルを切り分けてメンテナンス性を向上させるという恩恵が受けられません。
BEM
Block Element Modifier
⭐️ コーダー利用率:38.4%
概要
・Block(塊)、Element (要素)、Modifier (修飾) の3つに分ける
・命名規則は.block--element__modifierとする
・原則としてスタイルは全てclassに当てる
・Elementのclass名には必ずBlock名を含める
Blockとは
ヘッダー、ナビゲーション、記事、フッター、リストなどの大きなパーツです。
Elementとは
ナビゲーション(パーツ)の中の検索ボタン、検索フィールドなどの部品です。
Modifierとは
Blockにも、Elementにも適用されます。
ボタン(部品)のエラー状態と通常状態の色、記事(パーツ)の囲みがあるものとないものなど、装飾を表します。
メリット
メンテナンスやチームでの作業に適しています。BEMは一目見ればすぐにでそのタグがどこのブロックに属しているかがわかるので、別ページのHTMLをコピーして同じスタイルを当てたい時などに大変重宝します。再利用性が高い設計手法です。
また現状もっとも普及している手法なので、新しくコーダーがジョインした場合やエンジニアとコーダー、デザイナーが密に協業する場合も、BEM自体の基礎知識を持っていれば、すぐに全員がプロジェクトのCSS設計を理解し、スムーズに対応することができます。
デメリット
一つのclass名が長くなります。ハイフンとアンダースコア、キャメルケースが混在するので、人によってはすごく気持ち悪く見えます。
また、BlockなのかElementなのか判断がつけにくく、BlockとElementに汎用的な名前をつけようとするととても難しいです。
ECSS
Enduring CSS
コーダー利用率:3.6%
概要
・名前空間、モジュール(コンポーネント)、子ノードにわける
・BEMの影響を強く受けており、モジュール(コンポーネント)がBlock、子ノードがElementにあたる
・名前空間にハイフンを足して、接頭辞として使う
- 例:tp-Carousel(トップページのカルーセル)
名前空間とは
プログラミングでいうところの名前空間のような感じです。
思わぬところに影響しないよう、スタイルの適用範囲を一定の部分に閉じ込めるために使います。ECSSでは接頭辞をつけています。
ECSSでは汎用的なモジュールを作ることは推奨されませんが、どうしても汎用化したいモジュールについては、st-(Structure)という接頭辞の名前空間が用意されています。
モジュールとは
BEMのBlockとほぼ同じです。
子ノードとは
BEMのElementとほぼ同じです。
ディレクトリ構成の例
├── Top
│ ├── css
│ ├── js
│ └── img
├── Page2
│ ├── css
│ ├── js
│ └── img
├── Page3
│ ├── css
│ ├── js
│ └── img
└── Page4
├── css
├── js
└── img
メリット
特定の一ページ、一部分のデザインの変更に柔軟で強いCSSを書くことができます。
上位に名前空間があるので、モジュールや子ノードの命名をBEMほどには考えなくても問題がありません。
汎用的にまとめるという考え方がないので、デザイナーがより自由にWebデザインを考えることができます。
デメリット
ECSSはとにかく「分ける」ということを大切にするので、コードが増えます。ボタンのようなサイト全体で何度も出てくる部品も汎用化しないため、同じCSSのコードを何回も書くことになります。
OOCSSのように、ボタンのような汎用的な小さいモジュールを作ることは推奨されていません。変更があった時に修正に時間がかかります。
おまけ:Sass
コーダー利用率:70.6%
OOCSSが広がったのちの2013-2014年頃から使われるようになったCSSプリプロセッサです。
Sassのメリットは冗長になりがちなBEMの記法や、手動では面倒なOOCSSモジュールの継承をネストやmixin,extendによって簡単に実現できることです。
maesblogさんの記事がCSS設計での便利な使い方をわかりやすく解説してくださっています。
終わりに
PostCSSについても書きたかったのですが、途中で力尽きました。
CSS設計についての本は『CSS設計の教科書』が決定版です。
また、本文の中の「コーダーの利用率」のデータはコーダー白書を参考にしています。
これはCSS Nite Corder's High 2016 で集計・発表されたもので、現場のリアルな統計がまとめられた貴重な資料です。
最後のペルソナ設計までとても見応えがあるので、コーダー・マークアップエンジニアやコーダー寄りのフロントエンドエンジニアの方が見ると、きっと面白いかと思います。