「BEM」CSSの設計・命名規則をおさらいする
BEMはBlock・Element・Modifierの3つの要素からなるCSSの命名規則で、block__element--modifierで並べたclass名で全体がすぐに把握できます。
Blockはその内容を示す名称にし、使い回しできる様に独立させます。Elementの名称は重複して書いてもOKですがどんなに入れ子になっても子孫セレクタでは書きません。
ModifierはElementの差分を表現する装飾子ですので、必ずElementのクラスの後に追加で記述されます。
CSSの設計・命名規則「BEM」
CSSを設計するにあたり一番の課題は、その管理が煩雑になる事ですね。
自由に設計・クラス名の付与ができる分、その設計者の個性が入り混じったものになりがちです。
時には自分で何故そのようにしたのかすら、わからなくなる場合もあります。
ルールをもって設計共有する
特にチームでCSS設計をするとなれば、自分勝手な設計規則は致命的になります。
グループで共通の規則をもって設計命名する必要がありますね。
そうしないと、グループでサイトを修正する際のメンテナンス性が格段に悪くなります。
全てはメンテナンス性の向上
大切なのは「他人が作った膨大な量のWEBファイルでも、すぐに対象箇所のCSSを修正する事ができる事」でしょう。
全てはこのメンテナンス性を向上させる事です。
そして修正対象以外のところに影響が及ばない様にする、CSSスコープの徹底ですね。
本記事では、代表的なCSSの命名規則である「BEM」についてご紹介します。
BEMとは
BEMは、Block(ブロック)・Element(エレメント)・Modifier(モディファイ)をそれぞれ指しています。
B…Block(ブロック要素)
E…Element(ブロック内の要素)
M…Modifier(変化した内容)
それぞれの頭文字を取ってBEM(ベム)と名付けられています。
BEMは、この3つの柱を中心に厳格な命名規則をおこなうCSS手法です。
BEMのメリット
・設置されたクラス名からその内容が視覚的に明確になる
・そのクラス名の役割が予測しやすい
・そのスタイルのスコープがブロック内で収まる
・レイアウトが変わっても修正箇所が少なくて済む
・修正対象箇所がすぐにわかる
いろいろありますが、一つずつ見ていきましょう。
Block(ブロック)
・Blockは一つ一つが独立したパーツとして設計
・Block名は重複しない
・空間系のスタイルは入れない
Blockはコンテンツを内包する「外枠」としての役目があります。
ですのでクラス名をつける際には、そのブロックが「何に関するエリア」なのかがわかる様に命名します。
<div class="block"> </div> 例えばニュースリリースの欄なら <div class="newsrelease"> </div>
完全独立したパーツ
Blockは「汎用枠」であるため、どのページでも使い回せる様に独立させます。
配置場所の影響を受ける事なく、正常に動く様にするためです。
パーツとして独立していれば、どこに書いてあっても対象CSSをすぐに探す事ができます。
Block名は重複しない
完全独立パーツですから、名前が重複する事はあってはいけません。
数字の1・2などで連番をつけるようなことも避けましょう。
空間系のCSSはスタイルしない
Blockは空間に影響を及ぼすmargin,padding,positonなどのプロパティは設定しません。
これを設定してしまうと、そのBlockが来る場所によっては微妙に位置がずれるためです。
この部分については後述します。
Element(エレメント)
・必ずBlockの中に存在する
・Element名は重複してもOK
・CSS上、Elementの中に入れ子でElementを入れる書き方はダメ
ElementはBlock枠の各内容を構成する要素です。
例えば以下の様に、block内に複数のElement構成を入れることができます。
<div class="block"> <div class="block__element"></div> <div class="block__element"></div> <div class="block__element"></div> </div> <div class="block"> <div class="block__element1"></div> <div class="block__element2"></div> <div class="block__element1"></div> <div class="block__element2"></div> </div>
対象ブロック内でのみ機能する
ElementはBlockの外で使う事はできませんし「対象Block以外のブロック」で使う事も無い訳です。
Elementのクラス名は、その先頭に必ず「Blockのクラス名称」を継承して書く決まりになっています。
Blockが「information」の場合、中のelementクラスは「information__element」となります。
これにより対象の外枠(Block)の内側にある要素であることがわかりますね。
Element名は重複OK
Block名さえきちんと独立していれば、それに続くElement名は既に別の所で使っている名称でも大丈夫です。
さすがにElement名までオリジナルで唯一の名称という訳にはいきませんからね。
imageやtext・boxなど一般的な名称の方が良いと思います。
ElementのCSSは子孫セレクタで書かない
Elementはそのレイアウトの状態により、様々な入れ子ソースになる事があります。
ただしその入れ子状態は、CSS上で表現してはいけません。
この部分についても後述します。
Modifier(モディファイ)
Modifierは「修飾子」という意味で、パーツの基本構成はElementと同じになります。
ただし対象となる一部分のみ、その見た目や動作を変える場合に使われます。
<div class="block"> <div class="block__element"></div> <div class="block__element"></div> <div class="block__element block__element_end"></div> 最後の要素だけmodifierが入った状態 </div>
・基本はElementと同じCSS
・色(color)や大きさ(large)の装飾
・アクティブ、非アクティブ(active、disable)の演出
・特殊な空間(margin-bottom: 0)など
特定部分だけ違うデザインにしたり余白を消したりする、スポット要素です。
Elementと同様BlockやElementの外側で使用する事はできません。
1つのBlockやElement要素に対して、複数のModifierが使えます。
BEMの主な書き方
BEMの命名規則では、各3つの要素は下の様な書き方をします。
Block…class="block名" Element…class="block名__element名" Modifier…class="block名__element名--modifier名"
特徴的なのは「__」と「--」の部分ですよね。
・Element名は間に「__」アンダースコア2つをつける
・Modifier名は間に「--」ハイフン2つをつける
この様にBEMは常に3つの項目が連動した命名規則にする事で、メンテナンス性能を向上させている訳です。
block名を見ただけで、その領域の全容がほぼ把握できるメリットがあります。
この辺りを実際の書き方を参考に解説していきます。
Blockの書き方
まずBlockのクラス名は、その要素を表す英単語を入れましょう。
例:<div class="information"></div>
上の例ではインフォメーション用エリアとして、クラス名を「information」としています。
その領域が何を示すのかを命名する
例えば画像が並ぶブロックであれば「image」、キャンペーン情報を掲載する部分なら「campaign」にしましょう。
見た目の状態ではなく、その領域が「何を示しているのか」がわかる様に命名する訳です。
どこにそのブロックが移動しても、その命名内容は変わりません。
そして一度使った名称は、絶対に他で使わない様に完全独立させます。
空間に関するスタイルは書かない
それから先程も言いましたが、marginやpaddingは設定しない様にします。
わかりやすい例を一つ紹介しましょう。
例えばWEBページAでは中央部に設置されているブロックを、ページBの一番上にも設置する事になったとします。
ここでページAでの直前のコンテンツとのスペースを確保するために「margin-top: 40px」等の余白をつけていたとしましょう。
それをページB上にも複製設置すると、最上部に40pxの余白ができてしまいますよね。
空間の確保が必要な場合は別クラスで
かといってページB向けに、margin-top: 0の類似CSSを追加で作るのはよくありません。
どうしても空間を調整する必要がある場合は、2つ目として調整専用クラスを入れるようにしましょう。
<div class="information mt-0"></div> .mt-0{ margin-top: 0px; }
こうすればBlockのCSSスタイルは、共通して1つで済みます。
この規則が念頭にないと、その場その場で数値の違うBlockを複数作ってしまう訳です。似たようなBlock名が並ぶと、検索して探す事になりメンテナンス性が低くなります。
Blockの中に入れ子でBlockを入れてもよい
Blockは完全独立している訳ですから、入れ子で書いても問題はありません。
Blockは中に入れても外に出しても問題ない設計になっているはずです。
意図しない影響を与えないのが、Blockの考え方です。
Elementの書き方
中に入るElement要素は、先程のBlock名の後ろにアンダースコア2つ「__」を足しつつ、Element名をつけたものにします。
<div class="information"> <div class="information__image"></div> //image要素 <div class="information__text"></div> //text要素 <div class="information__text"></div> //text要素 <div class="information__text"></div> //text要素 </div>
Element名は「information__text」の様に、必ずその外側を囲むBlock要素の名前が先頭に入ります。
Elementは、パーツごとに様々な種類をたくさん用意する事になるでしょう。
CSSは全て同階層で書く
レイアウトによっては、Element内に別のElementが「入れ子」で入る事があります。
HTML上でElementが入れ子になるのは、全く問題ありません。
Elementが入れ子になっているソース
<div class="information"> <div class="information__text"> <span class="information__text__sub"></span> </div> <div class="information__text"> <span class="information__text__sub"></span> </div> </div>
ただしCSS上では、Elementの要素内にElementを入れ子で書いてはいけません。
上記ソースの場合、CSSのinformation__textの子孫セレクタで「information__text__sub」を書いてしまう場合があります。
子孫セレクタで書いた状態
.information__text .information__text__sub{ //cssスタイル }
そうなると両者の関係が固定されてしまうのでよくありません。
いざ入れ子が解除された時に、修正が必要になるためです。
例えばHTML上でネストされた状態であっても、CSS上ではいずれも同階層で書きましょう。
同位置でCSSを書く
.information__text{ //cssスタイル } .information__text__sub{ //cssスタイル }
Blockの子孫セレクタにもしない事
同様に、Block要素の子孫セレクタとしてElementを書かない様にしましょう。
仮にBlockの名称が変わってしまった場合、セットで書き換える必要が出てくるためです。
直接クラス名を設定していれば、Block名が変わっても影響を受けずに済みます。
この様に特定コンテキストに依存しない事で、レイアウトの変化に柔軟に対応できる様になります。
Modifierの書き方
Modifier要素が入る場合は、Element名に続けてハイフン「--」を足して単語をつけたものにします。
<div class="information"> <div class="information__image"></div> //image要素 <div class="information__text"></div> //text要素 <div class="information__text"></div> //text要素 <div class="information__text information__text--red"></div> //Modifier要素(赤色) <div class="information__text information__text--blue"></div> //Modifier要素(青色) </div>
上記の例では4つ目と5つ目のElement要素に、色が変わる装飾が入っています。
クラス名が長くなる
Modifierは常に、Block+Element+Modifierが1セットとなるクラス名です。
通常のElementクラスの「派生」の扱いになりますね。
必ず先に通常のElementクラス名が入り、そのあとに続けてModifierクラス名が入ります。
結果クラス名は最低2個以上になり、相当長くなります。
class="information__text(Element) information__text--blue(Modifier)"
このように2つは必ず並ぶルールになります。
Modifierは差分のみを指定する事
ModifierはElementの派生ですから、Elementの一部分が違うだけの要素です。
ですのでCSSでは、従来のElementスタイルと違う部分のみ(差分)を書くようにしましょう。
差分のCSS
.information__text, .information__text__red{ //cssスタイル } .information__text__red{ color: #ff0000; }
「SCSS」の方がもっとうまく差分を掛けますので、特にBEMの場合はSCSSを活用するべきとされています。
名称が複数単語になる場合
先ほどの例で紹介したように「information」など単語1つで命名できる場合は楽です。
しかしその内容によっては、名称が複数単語になる場合がありますよね。
その場合は、単語と単語の間をハイフン1つ「-」で区切ります。
・image-list
・campain-block
シングルハイフンですので、「__」や「--」の規則とは明確に区別されます。
シングルハイフン「-」
これはElementやModifierも同様です。
例えばuser-areaというblockの中にuser-titleというElementをつける場合があるとしましょう。
その時のElementクラス名は「user-area__user-title」になります。
これにModifierまでつけると「user-area__user-title--button-hover」などになります。
複数単語によるBEMソース例
<div class="user-area"> <div class="user-area__user-title"></div> <div class="user-area__user-title"></div> <div class="user-area__user-title user-area__user-title--button-hover"></div> //Modifier <div class="user-area__user-title user-area__user-title--button-hover"></div> //Modifier </div>
この様に見るとハイフンばかりで見にくく感じますが、慣れればきちんとした規則性のもとに記述されている事がわかります。
初めて命名規則を設けるのなら、まずはBEMを採用していくべきでしょう。