この節について
前の節で作成したmod-example-0001のソースコードをもとにモジュール作成の最重要ポイントを解説していきます。
あまり細かなことまで挙げすぎるとキリがないので、この節では「とてもやさしいCSS設計」においての土台となる以下の7つの最重要ポイントに焦点を絞って解説していきます。
- 1モジュールにつき1ファイル作成する
- BEMの命名規則に則ってクラス名を決める
- モジュールの幅は固定しない
- 位置調整のプロパティはBlockクラスに設定しない
- Elementクラスの影響範囲はBlock内に絞る
- Modifierクラスは元となるクラスと一緒に付与したときだけスタイルを適用する
- 親セレクタ参照(&)をクラス名の一部として使用しない
1. 1モジュールにつき1ファイル作成する
そのままの意味ですが、ファイルを適切な粒度で分割することはCSSを管理するうえで重要な考え方です。
2. BEMの命名規則に則ってクラス名を決める
前の節で挙げた通りですが、以下の4種類の命名規則が無いと「とてもやさしいCSS設計」は成り立ちません。
- Block
- BlockのModifier
- Element
- ElementのModifier
たったの4種類なので、第3章でモジュールを作成しているうちに慣れてくると思います。
3. モジュールの幅は固定しない
モジュールを再利用しやすい状態に保つため、モジュールの幅は以下のどちらかになるようにします。
- 親要素の幅いっぱいに広がる
- 中に入っている文字数などに合わせて広がる
親要素の幅いっぱいに広がるようにするというのは、module-list.htmlをブラウザ開いて、mod-example-0001
を見ていただくとわかると思います。
中に入っている文字数などに合わせて広がるというのは、display:inline-block;
のプロパティを設定したときを想像するとわかりやすいと思います。
無駄なModifierクラスを定義しなくて済むため、コードをシンプルに保つことができ、CSSの管理がしやすくなります。
4. 位置調整のプロパティはBlockクラスに設定しない
表示位置を調整する以下のようなプロパティは、モジュールを再利用しやすい状態に保つため、Blockクラスには設定しません。
4-1. float
4-2. position、top、right、bottom、leftなどによる位置調整
4-3. margin
4-4. z-index
実際には、Blockクラスのmarginは、first-childやnot(:first-child)などの擬似クラスを使用したり、隣接兄弟要素セレクタを使用するなどして、条件付きで設定する方が編集効率の面で効果的な場合が多くありますが、今の段階では最も簡単で覚えやすい方法として「marginはBlockクラスに設定しない」と覚えておいてください。
条件付きでmarginを設定する方法の詳細は後の機会に解説していきます。
5. Elementクラスの影響範囲はBlock内に絞る
コンパイル結果であるmodule-list.css
の一部を抜粋した以下のコードを見ていただくとわかりやすいと思います。
1 | .mod-example-0001 .mod-example-0001__first-element { |
mod-example-0001__first-element
クラスは必ず.mod-example-0001
クラスよりも内側のタグに付与しないとスタイルが適用されないようにしています。
その理由については「7. 親セレクタ参照(&)をクラス名の一部として使用しない」で述べます。
6. Modifierクラスは元となるクラスと一緒に付与したときだけスタイルを適用する
コンパイル結果であるmodule-list.css
の一部を抜粋した以下のコードを見ていただくとわかりやすいと思います。
1 | .mod-example-0001.mod-example-0001--danger { |
上記のコードから、BlockとそのModifierが一緒に付与されたときだけスタイルが適用されることがわかります。
以下のコードは、コンパイル結果のうちElementのModifierを抜粋したものです。
1 | .mod-example-0001 .mod-example-0001__list-item.mod-example-0001__list-item--danger { |
こちらもElementとそのModifierが一緒に付与されたときだけスタイルが適用されることがわかります。
Modifierは元となるクラスのプロパティを上書きする役割から、元となるクラスよりも詳細度を少し高くする方がクラスを記述する順番に拘らず確実にプロパティを上書きでき、余計なことに頭を使わなくて済むことが理由のひとつです。
もうひとつの理由は「7. 親セレクタ参照(&)をクラス名の一部として使用しない」で述べます。
CSSの詳細度についてここでは説明しませんが、CSSを書くうえでは非常に重要なことのひとつですので、CSSの詳細度についてまだ知らないという方はWebで検索しておくことをおすすめします。
7. 親セレクタ参照(&)をクラス名の一部として使用しない
これは「5. Elementクラスの影響範囲はBlock内に絞る」と「6. Modifierクラスは元となるクラスと一緒に付与したときだけスタイルを適用する」にも関連していることですが、親セレクタ参照(&)について以下のような使い方をしないということです。
1 | .mod-example-0001 { |
Webページのレイアウトが崩れたときに、ブラウザの開発者ツールを使用して修正対象となるクラスを特定することはよくあると思いますが、例えばmod-example-0001__first-element
のスタイルが原因だとわかったときに、tutorial/srcディレクトリ内を.mod-example-0001__first-element
で検索すると修正対象のコードが素早く見つけられることが1つ目の理由です。
また、&をクラス名の一部として使用したときのコンパイル結果の一部を抜粋すると以下のようになります。
1 | .mod-example-0001 { |
こうなると、例えば文字の色を赤くしたいと思ったときに、どこにあるタグにmod-example-0001__list-item--danger
を付与しても赤くすることができてしまいます。
特に人数の多いチームになると、ほんの少しの軽い気持ちや思い違いでBEMのルールから外れたクラス付与を行ってしまったり、スケジュールが逼迫していることを理由に、BEMのルールの理解が不十分なままの新メンバーを実務にアサインして、Blockよりも外側のタグにクラス付与が行われることになってしまい、そのまま長期的な運用をしていくうちに他のメンバーが気付かないところで少しずつ壊れていくケースはこれまでに多く目にしてきました。
このような問題を可能な限り減らすためには、クラスをHTMLに付与する人がBEMのルールを正しく理解し、そのルールを守ることはもちろん重要ですが、それよりも前の段階、つまりCSSの書き方においてもクラスの影響範囲をチームが意図したBlock内に制限することで、Block外のタグへの誤ったクラス付与を防ぎ、CSS編集時には想定外の箇所への影響が起こらない、長期的にメンテナンスしやすいCSSになるようにしています。
少し説明が長くなりましたが、これが2つ目の理由です。
とてもやさしいCSS設計では、セレクタ毎の影響範囲を把握しやすくする意味で、特にこの2つ目の理由は重要視しており、最重要ポイントとして「5. Elementクラスの影響範囲はBlock内に絞る」と「6. Modifierクラスは元となるクラスと一緒に付与したときだけスタイルを適用する」を挙げています。
この節のおわりに
この最重要ポイントを守ってさえいれば、SCSSのコードがどんなに煩雑になったとしても、影響はBlock内だけに留められますし、設計に失敗したモジュールだけを捨てて差し替えることができるので、CSSは格段に管理しやすくなります。
ぜひこの最重要ポイントを繰り返し読み返し、しっかりと理解していただけたらと思います。
とはいえ、これではまだ土台だけであり、実際にページを完成させるまでの具体的な方法や、後で困らないmarginの設定の仕方など、まだ説明できていないこともありますので、もっと多くのモジュールやページの作成を通して、具体的に説明していこうと思います。