【CSS】共通パーツには「BEM」の命名規則を使おう
WEBサイトの運用・保守時や大規模サイトの構築時には致命的になりかねないそんなモジュールのスタイルのバッティング問題。その解決方法の1つである「BEM」に関して今回はご紹介したいと思います。
複数のページに共通して登場するデザイン(以降モジュールと呼びます)のCSSを共通CSSファイルに書いたら、ページ毎のCSSとバッティング(名前が被ること)して困った経験は無いでしょうか?
WEBサイトの運用・保守時や大規模サイトの構築時には致命的になりかねないそんなモジュールのスタイルのバッティング問題。その解決方法の1つである「BEM」に関して今回はご紹介したいと思います。
具体的な例を上げて説明
モジュール作成
例えばこのようなパーツのデザインカンプがあったとします。
このデザインは複数のページに登場するため、モジュールとしてHTMLとCSSは以下のように記述したとします。
<div class="panel"> <p class="photo"><img src="~" alt=""></p> <p class="txt">テキストテキストテキストテキストテキスト</p> </div>
.panel { border: 1px solid #000; padding: 10px; } .panel .photo { margin-bottom: 10px; } .panel .txt { font-size: 14px; line-height: 1.5; }
運用時に問題発生
サイトを運用していると、次のようなマークアップの箇所にpanelモジュールを入れることになりました。
<section class="mainSect"> <h2 class="sectTit">セクションタイトル</h2> <p class="txt">セクションのテキスト</p> <!-- ここにpanelモジュールを追加したい! --> </section>
先ほどのpanelモジュールをそのまま入れると以下のようになります。
<section class="mainSect"> <h2 class="sectTit">セクションタイトル</h2> <p class="txt">セクションのテキスト</p><!-- クラス名が被ってる! --> <div class="panel"> <p class="photo"><img src="~" alt=""></p> <p class="txt">テキストテキストテキストテキストテキスト</p><!-- クラス名が被ってる! --> </div> </section>
ソースを見ていただければ分かる通り「.txt」クラスが被ってしまいました。
このようにモジュールのような「どこに入るかわからない」パーツに被りやすいクラス名を付けてしまうとバッティングが頻繁に発生してしまいます。
今回のようにバッティングが発生した場合の対処法は、
- モジュールの「.txt」を違うもっと被りにくい名前に変える。
- モジュールを入れる先のページにあった「.txt」を違う名前に変える。
の2パターンになるかと思います。前者が出来れば以降panelモジュールに関してはバッティングが発生しにくくなるのですが、もう既に多くの箇所でpanelモジュールが使われていた場合はその全てにおいて「.txt」のクラス名を変更しなくてはなりません…。
また、後者の場合は修正はすぐ済むのですが、根本的な解決にはなってないのでまた別の場所でpanelモジュールを使うときに同様のバッティングが発生して対処に追われるかもしれません。
このようにモジュールに適当な名前を付けた場合、後々面倒な問題になることがありますのでモジュールの命名にはかなり気を使う必要があります。
被りにくいモジュールの命名規則
そこでpanelモジュールのマークアップを以下のように変えるとどうでしょう?
<div class="panel"> <p class="panel_photo"><img src="~" alt=""></p> <p class="panel_txt">テキストテキストテキストテキストテキスト</p> </div>
このように「(モジュールのクラス名)_(パーツのクラス名)」という命名規則にした場合、先ほどのパターンは次のようになります。
<section class="mainSect"> <h2 class="sectTit">セクションタイトル</h2> <p class="txt">セクションのテキスト</p> <div class="panel"> <p class="panel_photo"><img src="~" alt=""></p> <p class="panel_txt">テキストテキストテキストテキストテキスト</p><!-- 被らない! --> </div> </section>
これだと名前が被りませんね!
このように、モジュールの中の要素に対して「(モジュールのクラス名)_(パーツのクラス名)」といった命名をすると次のようなメリットがあります。
- クラス名のバッティングが発生しにくい。
- 単純な命名規則のため、命名に時間がかからない。
- 「panel_photo」というクラス名を見た瞬間「これはpanelモジュールのパーツなんだな」と属しているモジュールがすぐわかる。
モジュールのバリエーションが欲しくなった場合は?
さらにサイトを運用していると「特定のpanelモジュールを目立たせたいのでボーダーの色が違うバージョンが欲しい」という要望が発生し、以下の様なpanelモジュールを作る必要が出たとします。
そこで、以下のようにマークアップしたとします。
<div class="panel red"> <p class="panel_photo"><img src="~" alt=""></p> <p class="panel_txt">テキストテキストテキストテキストテキスト</p> </div>
この場合、
.red { color: red; }
のような形でテキスト色の変更のために「red」クラスが使われているとまたバッティングが発生してしまいます。(そもそもこんな被りやすいクラスをこんなCSSの書き方で宣言するのがかなり問題あるのですが…それはそれとして)。
そこで、モジュールのバリエーションを作る際には「(モジュールのクラス名)-(バリエーション)」という命名規則にすることにします。
<div class="panel panel-red"> <p class="panel_photo"><img src="~" alt=""></p> <p class="panel_txt">テキストテキストテキストテキストテキスト</p> </div>
この命名規則のメリットはほとんど先ほどと同様ですが、
- クラス名のバッティングが発生しにくい。
- 単純な命名規則のため、命名に時間がかからない。
- 「panel-red」というクラス名を見た瞬間「これはpanelモジュールの赤いバリエーションなんだな」どんなクラスなのかすぐわかる。
ところでBEMは?
タイトルに「BEM」と書いたものの、ここまでBEMに関して全く言及しませんでしたが、実は今までの内容がBEM(正確にはBEMの命名規則をアレンジしたもの)です。
「BEM」は「Block」「Element」「Modifier」の頭文字をとったもので、それぞれ
- Block: モジュール全体のこと(今回の「.panel」のこと)
- Element: モジュール内のパーツのこと(今回の「.panel_photo」「.panel_txt」のこと)
- Modifier: モジュールのバリエーションのこと(今回の「.panel-red」のこと)
を表しています。
BEMに関して詳細に説明するとかなりややこしくなってしまうのですが、命名規則に関しては単純明快で
- Elementは「Block名 + 区切り文字 + Element名」
- Modifierは「Block名 + 区切り文字 + Modifier名」
という命名規則にしようというものです。(ElementとModifierの区切り文字は区分するために別のものを採用する必要があります。今回は「-」と「_」で区別してましたね。)
ちなみに、一時期話題になった「mindBEMding」は区切り文字に「–」「__」を採用していました。
<div class="panel panel--red"> <p class="panel__photo"><img src="~" alt=""></p> <p class="panel__txt">テキストテキストテキストテキストテキスト</p> </div>
正直区切り文字を連続させる書き方はほぼ見ないので、かなり気持ち悪い書き方ではあるのですが、「Block,Element,Modifierの関係を気持ち悪いほど目立つ区切り文字で区切ることによってより明確にする」という意味では理にかなってはいます。
それと、クラス名にスネークケースを採用している場合は連続させないと単語の区切りなのかBEMの区切りなのかわからないという事情もあったかと思います。(自分はクラス名にキャメルケースを採用しているのでBEMの区切り文字は1つで済ませています。)
BEMに関してより深く知りたいという場合は、以下の記事を参考にしていただければいいかと思います。
- Definitions / Methodology / BEM. Block, Element, Modifier / BEM(英語)
- Definitions / Methodology / BEM. Block, Element, Modifier / BEM(日本語訳)
- 【BEMによるフロントエンドの設計】基本概念とルール | CodeGrid
(おまけ)Sassを使用している場合のBEMの書き方
BEMは構造上、Block名を何度も書く必要があって面倒なのですが、Sass(SCSS)を使用している場合はCSSは以下のように書くことで簡略化できます。
.panel { &_photo { ~ } &_txt { ~ } &-red { ~ } }
これはコンパイルされると
.panel { ~ } .panel_photo { ~ } .panel_txt { ~ } .panel-red { ~ }
のようになります。
Sassで「&」は「親と同じ」という機能になっており、今回の場合は「.panel」が参照されてコンパイルされたような結果になります。
「&」を使っておくとBlock名に変更が生じた場合でも1箇所変更するだけで済みますし、記述も楽なので使うことをオススメします。
以上
「普段小規模なサイトの制作しかしていないからCSSの命名規則とかそんなに気にしなくてもなんとかなっているし…」という方も多いかと思います。
ただ、今は小規模なサイトばかりでも、いつどんなタイミングで命名規則を気にしないと制作が困難になってしまうような大規模案件や保守運用を見越した案件が舞い込んでくるかわかりません。(案件を選べる立場の人ならいいでしょうが、そんな人は中々少数派かと思います。)
いつそんな案件が来ても対応出来るように、命名規則を出来るだけ早く意識するようにしましょう!
以上、たにっぱでした〜