CSS設計とは
ウェブサイトをパーツの集合体として考え、そのパーツごとに分けてCSSを考えること。CSSを記述する時のルールとなるもの。
「良いCSS」とは
良いCSS」の定義として、おそらく最もよく知られているのは、以下の4つです。
- 予測しやすい
- 再利用しやすい
- 保守しやすい
- 拡張しやすい
マルチクラス・シングルクラス
1つの要素に対して、複数のクラスを指定するのをマルチクラス、1つないし2つ程度のクラスを指定するのをシングルクラスと呼びます。
例えば、BootstrapをはじめとしたOOCSSはマルチクラスで、BEMはシングルクラスが適していると言われています。
ただし、これらはそこまで厳密なものではなく、BEMだから絶対にシングルクラスにすべきという事ではありません。
基本のCSS設計手法
OOCSS
OOCSS は、 Object Oriented CSSの略で、オブジェクト指向CSSなどと日本語では呼ばれます。構造と見た目、コンテナーと内容を分離し、それぞれ別のクラスで指定をします。そのため、マルチクラスで使うことが多いのが特徴です。
SMACCSなどの基礎となる考え方で、以下の2つがポイントとなります。
- Container(入れ物)とContents(中身)の分離
- Structure(基本構造)とSkin(見た目)の分離
場所に依存したスタイルを当てる、上書き、コピーし回すのはNG。。(それぞれ、h2にスタイルを当てています。メインエリアのh2にはコレ、サイドバーのh2にはコレ、お問い合わせブロックのh2にはコレ……といった指定方法です。)
Webページを、レゴの集まりで考えよ
じゃあどうするかという問題ですが、Nicole Sullivanは「Webページを、レゴの集まりで考えよ」と言います。
ページを構成するパーツを、レゴのパーツのように分け、それをページにどんどん積んでいくと考えなさい。Webページは、レゴの集まりなのです。そして、ひとつひとつのパーツは、そのパーツで完結するようにCSSを書きなさい。そうすれば、さきほど例に挙げたような破綻は起こりません、とOOCSSは言うのです。
OOCSSでは、このひとつひとつのレゴのパーツをCSSオブジェクトと呼んでいます。(またはモジュール)
このような考えを守ってコードを書けば、同じパーツを二度コーディングする必要がなくなりますし、上書き合戦のような不毛なことも起こりません。
これがOOCSSの基本的な考え方です。
BEM
BEMとは「Block」「Element」「Modifier」の略であり、要素をこの3つに分けて考える厳格な命名規則です。CSS設計で使う場合、BEMを元にしたMindBEMdingが使われます。
ウェブサイトのUIをBlockとして考え、Blockに含まれる要素をElementと、BlockやElementの見た目や動きのパターンをModifierというルールで扱います。
「.Block__Element--Modifier」
Blockは常に独立しており、ページのどこでも配置することができ、他のブロックを含んだり含まれたりすることもできます。ElementはBlockを構成する要素で、ModifierはBlockの異なる状態を表します。
例えばメニューを例とすると、以下のようになります。
- Block(かたまり) : .menu
- Element(要素) : .menu_item
- Modifier(修飾子) : .menu__item--current
なぜBEMが必要なのか
スタイルの優先順位のコントロール不能状態、汎用的に使えないスタイル、パーツを別の場所に流用すると表示が崩れる、制作者本人しかわからないclass名の命名ルール、パーツの流用時、JavaScriptが動かないなど
BEMが解決を目指すポイント
- 長期間メンテナンスできる設計で、ファーストバージョンの開発をすばやく
- チームのスケーラビリティ
- コードの再利用性
BEMで設計する目的
BEMはもともと、プロジェクトの成長にともなって、既存のページが変化していくことを前提として考え出されました。また、変更がある場合は、その対応コストをできるだけ低減することを目的としています。
- 標準規約でコーディングすることにより納品物のクオリティを上げる
- ルール統一によりチーム間連携しやすくする
- コーディング時にルールで悩まないようにする
- 標準のBEMは冗長に感じるのでミスが少なく時間のかからない手法に改良する
SMACCS
SMACSS とは Scalable and Modular Architecture for CSS の略で、「スマックス」と読みます。
SMACSSは、 Scalable and Modular Architecture for CSS の略で、OOCSSやBEMなどを参考に考案されました。
SMACSSでは、スタイルをBase, Layout, Module, State, Theme の 5つに分けて考えます。ただし、Themeはプロジェクトによっては、使われないこともあります。
- Base : 要素そのもののデフォルトスタイル
- Layout : モジュールの配置を決めるレイアウト
- Module : 再利用可能なパーツ
- State : 要素そのもののデフォルトスタイル
- Theme : サイトのルック&フィールを定義
書籍『Scalable and Modular Architecture for CSS(日本語版)』では、CSSをカテゴライズすることの目的を『デザインの中で繰り返されるパターンを体系立てるため』と解説しています。
繰り返しのパターン化によるメリットとして、次のことが挙げられています。
- コード量が少なくなる
- メンテナンス性を高める
- ユーザー体験の一貫性の向上
ベースルール
ベースルールは、サイト全体で要素そのもののデフォルトスタイルを定義します。
ベースルールでは、主に次のセレクタを使ってスタイルを適用します。要素そのものの見た目を定義するという性質のため、IDやクラスは使いません。
- 要素セレクタ(body、a)
- 属性セレクタ(input[type=text])
- 擬似クラスセレクタ(a:hover)
ここで注意したいのは、要素セレクタに対してあまりにも具体的なスタイルを指定をしてしまうと、後々その要素を使った別の見た目のモジュールを追加したくなった場合に、ベースのスタイルをすべて上書きしなければならなくなるということです。
なるべく、サイト全体で共通させたい基本的なスタイルのみに留めましょう。
例えば、tableの場合、表組みのデザインが1パターンしかないからといって、tableタグ自体にそのデザインのスタイルを直接指定してしまうと、あとからパターンを追加するときに面倒です。
レイアウトルール
レイアウトルールでは、ページのエリア分けを行います。
レイアウトを独立したルールとすることで、ヘッダやコンテンツエリアなどのエリアを分けるためのパーツと、ダイアログやナビゲーションなどのページを構成するためのモジュールを、完全に分けて管理することができます。
プリフィックス(l- / layout-)
レイアウトルールをクラス名で管理する場合は、モジュールルールや状態ルールとの区別をつけるために、プリフィックスをつけます。
サイト全体で共通していれば、どのようなプリフィックスでも自由ですが、公式で紹介されているl-xxxやlayout-xxxとしておけば、誰が見てもレイアウトルールだと理解できそうです。
レイアウトへのIDセレクタの利用
IDセレクタはCSSの詳細度を高めてしまい、場合によってはCSSを複雑にしてしまうので利用する場合は注意が必要です。
ただし、ヘッダやフッタなどの主要なレイアウトは、慣習的にIDセレクタが使われることがあるため、SMACSSではレイアウトルールでIDセレクタを利用することを禁止してはいません。
また、同じクラス名に対する分岐は、子孫セレクタを使います。
モジュールルール
モジュールルールでは、再利用可能なパーツを定義します。
モジュールは、必ずレイアウトパーツの中に配置されます。そして、別のレイアウトに移動しても再利用できるように、完全に独立させなければなりません。
また、モジュールは別のモジュールの中に含めることもできます。
-
プリフィックスはつけない
モジュールにmodule-やmod-のようなプリフィックスをつけると、冗長となってしまうため、SMACSSではモジュールに特定のプリフィックスはつけません。プリフィックスがついていない場合はモジュールだとわかるためです。
その代わり、モジュールのトップのクラス名をプリフィックスのように扱います。こうすることで、どこからどこまでがひとつのモジュールの塊なのかが、わかりやすくなります。 -
モジュールでの要素セレクタの利用
SMACSSではモジュール内のすべてのパーツにクラス名を付与しなくてもよく、場合によっては、要素セレクタに直接スタイルを指定してもよいとされています。
すべての要素に対してクラス名を付与すると、コードの見通しが悪くなり、HTMLのコード量も増えてしまうためです。
要素セレクタを利用する場合には、次のルールを守るべきとされています。
要素セレクタを使うのは、その要素がセマンティックな場合に限ります。例えば、h1やliやaなどはセマンティックなのでOKですが、divやspanなどはセマンティックではないので、クラス名を付与する必要があります。
セマンティックな場合であっても、要素セレクタの利用は、クラスセレクタの1つ下の階層にとどめます。つまり、子セレクタ(>)を利用してスタイルを指定するようにします。
こうすることで、モジュールの機能拡張やモジュール内に別のモジュールを含める場合も、要素セレクタの競合による影響を受けづらくなります。
-
クラス名をつけるタイミング
見出しに関しては、クラス名を付与した方がメリットが大きいのではないかと思います。
ただし、liやa要素などでは、すべての要素にクラス名を付与した場合、HTMLのファイルサイズへの影響も大きく、見通しも悪くなるため、要素セレクタにスタイルを指定した方がメリットが大きいかもしれません。
要素がセマンティックかどうかだけでなく、そのモジュールがどう使われるかを想定しつつ、クラス名を付与するかしないかを、ケースバイケースで使い分けるとよいかと思います。
pタグやliタグなどの子要素ができる場合には>で指定するのがベストプラクティス。 -
モジュールのサブクラス
同じモジュールを、利用する場所によってスタイルを変更したい場合、SMACSSでは、ベースモジュールにサブモジュールのクラス名を付与すること。
こうしておけば、サブカラム以外のどこに移動しても同じ見た目を維持することができますし、ほかのバリエーションも作りやすくなります。
状態ルール
状態ルールは、モジュールやレイアウトを拡張し、特定の状態によってスタイルを上書きします。
状態の切り替えはJavaScriptで制御するため、状態ルールはJavaScriptに依存すると言えるでしょう。
-
プリフィックス(is-)
状態ルールの命名では、「Is hoge?」といった疑問文に対して、結果がtrueである場合にそのクラス名を付与するというイメージをするとわかりやすいです。
そのため状態ルールのクラス名には、すべてプリフィックスis-がつきます。 -
サイト全体に属する状態ルール
状態ルールには、サイト全体に属するものと、特定のモジュールに属するものの2種類があります。
どのようなパーツにも使える汎用的な状態を表すルールは、サイト全体に属する状態ルールであると言えます。
テーマルール
テーマルールでは、サイト全体の見た目の雰囲気を統一させるための定義をします
色に関わる部分などがテーマの管理対象となるので、例えば以下のように色に関するスタイルは、独立させて記述します。
また、枠の色や背景色など、再利用性の高いものはプレフィックスにtheme-やt-を付けて用意します。
MCSS
BEMとOOCSSの原理を基にしたCSS設計が、MCSS(Multilayer CSS)です。
モジュールをレイヤー毎に分離させているのが特徴です。
CSSモジュールを3つのレイヤーに分けて考えます。
- Base : 再利用可能な標準スタイルのセット
- Project : Baseを元にしたプロジェクト毎のスタイル
- Cosmetic : 色、サイズなどわずかに影響するスタイル
Base、Project、Cosmeticのそれぞれに属するクラスを、複数指定することでUIを作成します。
MCSSは以下が詳しいです。
MCSS(日本語訳)
http://operatino.github.io/MCSS/ja/
FLOCSS
公式
https://github.com/hiloki/flocss
OOCSS, SMACSS, BEM, SuitCSS, MCSSなどの考え方を取り入れたものです。
命名規則はMindBEMdingを採用し、3つのレイヤーと、Objectレイヤーの子レイヤーで構成されます。
- Foundation : normalize.cssなどサイト全体のデフォルトスタイルを管理。
- Layout : レイアウトのスタイル。各ページを構成するサイト全体で共通したエリアを管理
- Object : コンポーネントのスタイル。サイト全体で再利用できるパターンを持つモジュールを管理
- Component : 再利用可能なコンポーネント。
- Project : プロジェクト毎のスタイル。いくつかのComponentと、他の要素によって構成される大きな単位のモジュールを管理
- Utility : clearfixやmarginなどの小さなスタイル。ComponentとProjectのモディファイア(パターン)で解決することができないスタイル、また、調整のための便利クラスなどを管理。
- theme : テーマによる色の切り替えなど、ページ単位の色違いとか
- Component : 再利用可能なコンポーネント。
CSS設計のいいとこ取りをしたいときは、FLOCSSをベースにすると良いかもしれません。
命名規則
プレフィックス
layoutならl-、Componentならc-のように、属してるフォルダ名の{頭文字}+- でプレフィックスを頭につけ、ファイル名だけでもで判断しやすくする(Foundationはリセットや下地が目的なので除く)
ファイル名=クラス名
l-header.scssにはl-headerというクラス名を定義
ファイル名、クラス名なるべくは省略しない
誰が見てもわかるようにファイル名、クラス名なるべくは省略しない
txtやbtnもNG。自分で言葉を作らないこと。
ただし、Utilityはクラス名が長くなりがちなので省略可とし、ファイル名は省略しないことで誰が見てもわかるようにする。
MindBEMdingの規則
BEMシステムのシンタックスである、Block、Element、Modifierに分類して構成される規則。
- Modifier
Modifierは原則2つまでとする
(c-button--blue,c-button--smallなど)
JavaScriptで操作され、状態を変化させるためのクラス
プレフィックスにis-をつけ、定義する
この場合、他のObjectへの変化にスタイルを当ててしまうことを防ぐために、
is-click自体にスタイルは定義せず、必ず、.c-button.is-clickにスタイルを定義する。
カスケーディング
CSS では一つの HTML *1に対して複数のスタイルシートを使えます。そして、複数のスタイルシートを結合するプロセスのことを「カスケーディング」と呼びます。ある要素のあるプロパティに対する宣言が複数あるとき,宣言の“強さ”の関係を定めて,うち 1 つの宣言だけが有効になるようにするしくみである
- モジュール間のカスケーディング、他のモジュールを親とするセレクタを用いたカスケーディングは禁止
- SASSのextend
CSS in JS
React.jsの流行と共に、広まりつつあるアイデアの1つです。HTMLをJSXとしてJavaScriptで扱えるようにしたように、CSSをJavaScriptのオブジェクトにして扱うという考えです。
Scoped CSS
Scoped CSS自体は、CSS設計ではなくHTML5で追加された scoped属性を使ったCSSの記述方法です。
基本となるのは、UIをコンポーネント化し、そのコンポーネント内でのみ適用されるCSSを記述するという考え方です。
参考
より良いCSSを書くための様々なCSS設計まとめ
https://uxmilk.jp/43386
ウェブ制作者なら意識してほしいCSS設計の基礎知識
https://ics.media/entry/15166/
知っておきたいCSS設計法 第1回 OOCSSの基本
https://app.codegrid.net/entry/oocss-1
BEMによるフロントエンドの設計
第1回 基本概念とルール
https://app.codegrid.net/entry/bem-basic-1
【HTML5・CSS3】CSS設計のBEMを1から理解してマスターしよう!
https://pikawaka.com/html-css/bem
Scalable and Modular Architecture for CSS(日本語版)
http://smacss.com/ja
SMACSSによるCSSの設計
前編 ベースとレイアウト
https://app.codegrid.net/entry/smacss-1
初心者による初心者向けのSMACSSまとめ
https://qiita.com/k_mori/items/7d3da61c712ff9513163
各CSS設計手法を取り入れる上でのメリット・デメリットをまとめてみた
https://qiita.com/nezurika/items/a964e21d3596b0ee4c9a
【CSS設計】FLOCSSを導入してみて気づいた8つのポイント
https://www.indival.co.jp/2016/08/26/3102/#:~:text=FLOCSSとは、CSSを,しましょう、という考え方です。&text=上記のレイヤーの各,なるタイポグラフィなど)を定義。
[CSS設計] 私のためのFLOCSSまとめ
https://qiita.com/super-mana-chan/items/644c6827be954c8db2c0
CSS3 のカスケーディングについてのおさらい
https://amachang.hatenablog.com/entry/20080407/1207594307
FLOCSSを使ってCSSファイルを20,000行から9,000行にした話
https://qiita.com/Atsss/items/4f9d98fb1d0546539c09