様々なクラス名の名づけルールがありますが、その中でもBEMはコンポーネント化のしやすさや、詳細度によるミスがないことなど、いくつか利点があります。
BEMの基本
ただBEMでの命名は分かりづらく、ルール化するのが難しいのではないかと思います。
実際BEMで検索してもルールが一つではなく、いくつも出てきます。
BEMの基本は別のサイトにお任せします。
まず私はプロジェクトに入る前に以下のサイトを読んでもらっています。
(大変お世話になっております!)
BEMの注意点
ネスト
まずBEMは役割の点でのBlock、Elementというものがあります。
これはあくまでも役割の点ということを意識する必要があります。
つまり「HTMLの構造とは違っているかもしれない」ということです。
HTML上では親子関係にある要素がBEM上はすべてElementになっている、なんてことは良くあります。
そこで押さえておきたい点として、Blockはネストできる、Elementはネストできない、という点です。
Elementはネストできないので、block__element__other-element
という名前を付けることは出来ません。
もしどうしてもネストしたい場合は、子Blockを作ります。
つまり、
<section class="block">
<div class="block-child">
<span class="block-child__element">
...
</span>
</div>
</section>
のような形にします。
この場合block-child
は違うBlockなので、block
から切り離されてもいいように作るか、block
とblock-child
は密結合していることを利用者が分かるようにしておく必要があります。
蜜結合している場合はCSS内にコメントとして残しておくか、結合元の名前を-
の前に入れるなどのルールを作っておくといいかもしれません。
ただ、密結合することを許すと、結局どんどんと密結合が生まれていき、普通のCSSと大差なくなってしまう可能性があります。
できるだけ、Blockは単体でも表示できるように作っておきましょう。
CSSのセレクタ
命名はBEMで出来たとしても結局CSS内で子孫セレクタを使ってしまうと「詳細度を均一に保つ」というBEMの目標からそれてしまいます。
どういうことかというと、
.block .block-child {
/* 詳細度は0-2-0 */
}
.block-child {
/* 詳細度は0-1-0 */
}
.block .block-child
と書いてしまうと、詳細度が上がってしまいます。
本来は詳細度を0-1-0
でそろえたいわけです。そうすると基本的に並び順だけが問題になるので判断が楽になります。
以上の2点を考えつつ、BEMの実装を行っていきます。
実際の実装
単純ですが、
- メインビジュアル
- メインビジュアルに重なるかたちで商品名とキャッチコピー
- キャンペーン部分
- 画像
- 宣伝文 という構造です。
header
はハンバーガーメニューやPC版ではナビゲーションなどが入ることを想定します。カンプにはないので割愛します。
<main class="main">
<section class="mv">
<h1 class="mv__productname">商品名</h1>
<div class="mv__catchcopy">キャッチコピーキャッチコピー</div>
</section>
<section class="campaign">
<h2 class="campaign__title">キャンペーン</h2>
<div class="campaign__container">
<picture>
<source srcset="assets/images/product_img_pc.jpg" media="(min-width: 768px)">
<img class="campaign__picture" src="assets/images/product_img_sp.jpg" alt="">
</picture>
<p class="campaign__text">
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut
labore et dolore
magna aliqua. Ut enim ad
minim veniam, quis nostrud
exercitation ullamco laboris
nisi ut aliquip.
</p>
</div>
</section>
</main>
こんな感じでしょうか。mv
= Main Visual
の略や、img
などの略された単語はありますが、概ね単語をそのまま書いています。
単語の区切れ目は-
のケバブケースにします。
先ほども書きましたが、HTMLの親子構造はBEMには適用されていません。campaign__container
の中に横並びの二つの要素がありますが、どちらもBEM上はcampaign
のElementという扱いです。
Modifier
もしこのキャンペーンBlockが複数出てきて、なおかつ背景色が違う、などの変化が出た場合は、違うエレメントを作るかModifierを使います。
今回はちょっと暗めのエリアに入るキャンペーンBlockなので--dark
というModifierを作ります。
キャンペーン内のタイトルも一緒に変える必要があります。
<section class="campaign campaign--dark">
<h2 class="campaign__title campaign__title--white">キャンペーン</h2>
</section>
こんな感じですね。
.campaign--dark
は背景色などの変化分だけ、.campaign__title--white
は文字の色などの変化分だけのスタイルを書きます。
要するにCSSにModifierのセレクタが記述されていなくても、きちんと表示できるようになっているわけです。
決して.campaing--dark .campaign__title
というセレクタで色を変えようと考えてはいけません。そうすると詳細度が変わってしまいます。
例えば、
<section class="campaign campaign--dark">
<h2 class="campaign__title">キャンペーン</h2>
</section>
.campaing--dark .campaign__title {
color: white;
}
こうして文字色を変えたとします。
その後別の人が正規の書き方でModifierを書き加えました。
<section class="campaign campaign--dark">
<h2 class="campaign__title campaign__title--yellow">キャンペーン</h2>
</section>
.campaing--dark .campaign__title {
color: white;
}
.campaign__title--yellow {
color: yellow;
}
しかし、詳細度が.campaing--dark .campaign__title
の方が高いので.campaign__title--yellow
は反映されません。
こういった事態を避けるために、必ず詳細度を均一に保つ必要があるわけです。
さいごに
BEMはコンポーネント化に役立つので利用するシーンが多いと思います。
ただ今後@scope
という新しいCSSが普及してくると、そちらに移行していく可能性があります。
BEMはクラス名が長くなるので@scope
の方がコーディングが楽だと思います。
それでも現在採用するには最善の選択肢かもしれません。
ぜひ活用していきましょう!