BEMについて自分用のメモ
BEMについて使う機会があったのでまとめることにしてみました。
いろいろなサイトを参考にしていますが正しい考え方になっているかは不明
この記事の目次
BEMとは
Block → ブロック Element → エレメント Modifier → モディファイア の略語です。
Webサイトのコンポーネント化のためのフロントエンド設計方法のひとつで、厳格なclass名の命名ルールの手法です。
なぜBEMが必要なのか
HTMLとCSSをつかってサイトを構築しているといろいろなトラブルに遭遇します。
これらはしっかり考え抜いていても起こりえるトラブルで、都度対処していくことでサイトを構築しています。
セレクタの詳細度による制御不能状態
id属性を使った指定や、細かい入れ子、多用される疑似クラスは詳細度の制御が難しいです。
コントロールが難しいからという理由で!importantの多用し、さらに詳細度の制御が難しくなりどうにもできなくなる人が多いらしいです。
自分でしっかりと考えて装飾している場合、!importantを使うようなトラブルは起きませんが…
汎用的に使えない
HTMLのタイプセレクタに直接スタイルを指定すると、同じ見た目のまま見出しレベルだけを変えてスタイルを使いまわしたいとき、 ナビゲーションメニューの幼児中ページだけリンクを外しつつスタイルはそのままという場合に、HTMLやCSS修正しなければなりません。
1 2 3 |
.box h2 { font-weight;normal; } |
例えば上記のような指定をしています。新しく追加したをh3の見た目を同じにしたい、場合カンマで区切って複数セレクタの形でセレクタを追加しなければなりません。
1 2 3 4 |
.box h2, .box h3 { font-weight;normal; } |
更に.boxに太字での見出しを追加したい場合、font-weight;bold;どでスタイルを上書きする必要が出てきます。
もしタイプセレクタでなく、クラスセレクタだけを使ってスタイルを指定していれば、このような問題は起こりません。
class名の命名ルール
class名の命名ルールが決まっていないと、他の人がそのHTMLを見たときに、どこからどこまでがひとつのパーツのまとまりなのかわかりません。コメントなんかを入れておくと良いと思いますがめんどくさいですよね。
流用時、見た目がおかしかったりJSが動かない
JSの挙動をセットにしてパーツ化していないと別ページに流用したときCSSとJSを正確にコピーできないかもしれません。 見た目がおかしいけどJSは動いたり、見た目は大丈夫だけどJSが動かないなどのトラブルが起こる可能性があります。
BEMで設計することで、これらの問題を解決できます。
メリット・デメリット
メリット
BEMの公式ドキュメントにBEMを理解すると、次のようなメリットがあると言ってます。
- HTMLとCSSは、いつでもデザインの変化に対応できる
- プログラマーとフロントエンドエンジニアは、お互いのコードに貢献し合える
- 皆が同じ言語でやりとりできるので、コミュニケーションが取りやすくなる
ある程度のスキルがあれば恩恵は少なくなさそうです
デメリット
- 知らない人は対応しにくい
- クラス名を考えるのに時間がかかるし、とても長くなる
- サイトの規模が小さい場合はメリットが少ない
- Sassを使えないとセレクタの指定が大変
思いついたものだけ書きました
BEMで使う3つの要素
BEMは、Block、Element、Modifierという3つの概念だけ理解してしまえば、あとはclass名の命名ルールに則って記述するだけの単純な方法ですが、名前の付け方に苦労すること間違いなしです。
Block
ブロックは独立した存在で、サイト内の「構成要素」になります。 ブロックには他のブロックを含めることもできます。
簡単に言うならばサイト内のパーツを塊単位で名前を付けたらいいと思います。
例としてここでは検索フォーム的なもので説明しますが、
入力欄と送信ボタンをまとめている要素がブロックといった形で名前を付けていきます
1 2 3 |
<div><!--パーツを構成しているのでBlock--> <input type="text"> <input type="submit"> </div> |
Blockはそのまま要素の意味を指すような単語が選ばれますのでここではformと付けてみましょう
1 2 3 |
<div class="form"><!--パーツを構成しているのでBlock--> <input type="text"> <input type="submit"> </div> |
これでとりあえずBlockは完成。要素の名前を付ける場合やタグ名をクラスで付けているケースも見受けられます。
結構適当でも、大丈夫だと思います。名前が単語と単語の組み合わせのほうが分かりやすい場合はハイフン一つでつなぎ合わせると良いでしょう
Element
Elementは、Blockの一部分であり特定の働きを持つ子要素を指します。
エレメントはブロックで付けた名前に__(アンダースコア2つ)付けそのブロック内でのみ意味をなすような名前を付けると考えやすいです。
画像のように「form」の中の子要素につけるなら入力欄のinput要素には「form__input」送信ボタンには「form__send」のように最初は気持ち悪いかもしれませんがクラス名を指定しましょう
1 2 3 |
<div class="form"> <input type="text" class="form__input"> <input type="submit" class="form__send"><!--formの子要素であることがわかるような名前を付ける--> </div> |
このような名前を付けた時に便利なのがSassのネストする書き方や「&」を使った書き方になります。
毎回毎回スタイルを指定するたびに長いセレクタを書くのは疲れてしまいますのでこの機会に使ってみるのもいいかもしれません。
1 2 3 4 5 6 7 8 9 10 |
.form{ background-color: #eee; &__input{ font-size: 20px; padding: 10px; } &__send{ font-size: 18px; } } |
特に意味のないコードですが
1 2 3 4 5 6 7 8 9 10 |
.form { background-color: #eee; } .form__input { font-size: 20px; padding: 10px; } .form__send { font-size: 18px; } |
このような形にできます。
Modifier
モディファイアは、ブロックやエレメントに追加するCSSクラスで、jsで変化をさせる変化の種類をキーワードで付けたり、少し違うパーツを量産するときにつける名前みたいです。
よく見る形はマルチクラス(一つの要素に複数のクラスを付けるという意味)にしてはブロックやエレメントで付けた名前の後に「–」ハイフン2つ繋げて名前を付けるようです。
1 2 3 4 5 6 |
<ul class="list"> <li class="list__item">LIST</li> <li class="list__item">違う色にしたいLIST</li> <li class="list__item">LIST</li> <li class="list__item">LIST</li> </ul> |
上記のようなコードがあったとします。何かの理由があって2つ目のli要素だけ色を変えていきたいと思います。
BEMの考え方では擬似クラスなどは使わないので乱暴にクラス名を付けていきます。
1 2 3 4 5 6 |
<ul class="list"> <li class="list__item">LIST</li> <li class="list__item list__item--color">違う色にしたいLIST</li> <li class="list__item">LIST</li> <li class="list__item">LIST</li> </ul> |
このコードのように半角スペースで区切り新たにモディファイア付きのクラスを指定しましょう。
親要素にモディファイアを付けて変化させるパターンも公式の方で紹介されています。
この例では、flexを使って左右入れ替える指定をするための例になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div class="box"> <figure class="box__imgbox"> <img src="○○.jpg" alt=""> </figure> <p class="box__text">段落</p> </div> <div class="box box--reverse"><!--flexで順番を入れ替えるためモディファイアを付ける--> <figure class="box__imgbox"> <img src="○○.jpg" alt=""> </figure> <p class="box__text">段落</p> </div> |
ブロックを複数同じように組んでおきます。
imgとテキストを入れ替えたいブロックにモディファイアを仕込んでおきます。
Sassは基本ネストで書くほうが良いとされているようですがこのような場合はネストさせないほうが効率が良いそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
.box { $box: & !global; display: flex; background-color: #fff; &--reverse { background-color: #ccc; } .box__imgbox { margin-right: 20px; } } .box__imgbox { #{$box}--reverse & { margin-right: 0; margin-left: 10px; order: 2; } } .box__text { #{$box}--reverse & { order: 1; } } |
親要素にくっつける場合もあるかもしれませんので覚えておくとよさそう
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.box { display: flex; background-color: #fff; } .box--reverse { background-color: #ccc; } .box .box__imgbox { margin-right: 20px; } .box--reverse .box__imgbox { margin-right: 0; margin-left: 10px; order: 2; } .box--reverse .box__text { order: 1; } |
BEMではメンテナンスしやすい設計にするのでSassを使うのがスタンダードです。
「&」を使いながらセレクタをネストさせればセレクタもある程度簡潔に書けるでしょうが冒頭にも書いた通りクラス名を考えるのが大変だったりしますので、考えることがとっても多いかと思います。
大規模な案件などではそれぞれの要素にクラスを付ければCSSで豪快にレイアウト崩れが起きす心配はないのでよく使われています。
必要に応じて利用しましょう。