CSS設計思想のBEMについて解説していきます。「予測がしやすい」「拡張性がある」「保守性がある」という理由で近年多くのプロジェクトで利用されているCSS設計です。
英語で書かれた公式のドキュメントもありますので、一度本記事を読み終えたらこちらも参照してより理解を深めてみてください。
INDEX
BEMとは
CSSのスタイルの役割を下記のような「Block」「Element」「Modifier」という3つの概念に分けて構成するCSSの設計思想で、Block__Element--Modifier
の形で名前をアンダーバーとハイフンで繋げてclass名を作成していきます。
BEMの一番の特徴はこの命名規則にあり、このような厳格な命名規則があることで誰が見てもわかりやすく、破綻しにくいコーディングが可能になります。
<div class="block"><!-- ★Block -->
<div class="block__element"></div><!-- ★Element -->
<div class="block__element block__element--modifier"></div><!-- ★modifier -->
</div>
それでは「Block」「Element」「Modifier」についてそれぞれ解説していきます。
Block(ブロック)とは
Blockとは機能ごとに独立した再利用可能なモジュールで、どのページでも使いまわせることを前提にしたパーツのことです。
下記の.card
の様に一つのパーツとして独立しているためBlockとして定義できます。
<div class="card-list"><!-- ★Block -->
<div class="card"><!-- ★Block -->
<figure class="card__image-wrapper">
<img class="card__image" src="image.jpg">
</figure>
<div class="card__body">
<h2 class="card__heading">
<p class="card__description">
</div>
</div>
・
・
・
</div>
Element(エレメント)とは
ElementとはBlockを構成する要素で、Blockの中だけで利用できるパーツです。
下記の.card
以外の子要素全てがエレメントに該当します。
<div class="card">
<figure class="card__image-wrapper"><!-- ★Element -->
<img class="card__image" src=""><!-- ★Element -->
</figure>
<div class="card__body"><!-- ★Element -->
<h2 class="card__heading"></h2><!-- ★Element -->
<p class="card__description"></p><!-- ★Element -->
</div>
</div>
Modifier(モディファイア)とは
ModifierとはBlockもくしはElementの見た目や状態、振る舞いを定義するスタイルです。
Elementと違い必ずしも存在する必要はなく、パターン違いを作成する時に使用します。
下記のようにシャドウを付けたいパターンが発生したら、Block(もしくはElement)にModifierを付け加えます。
<!-- ○ BlockとModifier両方をつける -->
<div class="card card--shadow"><!-- ★Modifier -->
<figure class="card__image-wrapper"></figure>
<div class="card__body"></div>
</div>
<!-- × Modifierのみつける -->
<div class="card--shadow">
<figure class="card__image-wrapper"></figure>
<div class="card__body"></div>
</div>
BEMの基本ルール
IDを使ってはいけない
スタイルを当てる際はidでの指定は推奨されていないため、必ずclassでスタイルを当てます。
理由は詳細度を均一に保つためです。
BEMにとってこの詳細度とうい概念は大切なルールの一つで、全てのスタイルの詳細度を統一することで意図しない挙動が発生させないという思想で設計されいます。
<!-- ○ idで指定しない -->
<div class="card">
<figure class="card__image-wrapper"></figure>
<div class="card__body"></div>
</div>
<!-- × idで指定している -->
<div id="card">
<figure id="card__image-wrapper"></figure>
<div id="card__body"></div>
</div>
スタイル(css)は全てclassに対して指定する
CSSでスタイルを適用する際は全て単一のclassに対してスタイルを当てます。これは上記でも説明しましたが詳細度を均一に保つという厳格なルールがあるからです。
下記の例のようにclassではなくBlockの子要素などにスタイルを指定するその部分だけ詳細度が上がってしまいます。
/* ○ classに対してスタイルを当てている */
.card {
border: 1px solid #333;
}
.card__image-wrapper {
margin-bottom: 10px;
}
/* × class以外にスタイルを当てている */
div.card {
border: 1px solid #333;
}
div.card figure {
margin-bottom: 10px;
}
「::before」などの擬似要素はclassを指定することができない為、そのままスタイルを適用します。
単語が複数ある場合はケバブケース
class名をつける時に単語が複数ある場合は下記のようにハイフンで単語を繋げるハイフンケースを利用します。
<div class="card-item">
<figure class="card-item__image-wrapper"></figure>
<div class="card-item__body"></div>
</div>
キャメルケースなどの別の命名規則を利用したい場合は、そのプロジェクトごとに必ずルールを統一してください。
Blockの中にBlockもいれていい
Blockの中にはElementとModifier以外に別のBlockを入れることも許されています。
下記のように.card
Blockの中に.button
Blockが入っているのは、.button
自体が他のページでも単独で使いまわせるパーツのためBlockとして定義しています。
このようにBlockとBlockを組み合わせることで拡張しやすいコーディングが可能になります。
<div class="card"><!-- ★Block -->
<figure class="card__image-wrapper">
<img class="card__image" src="">
</figure>
<div class="card__body">
<h2 class="card__heading">
<p class="card__description">
<a class="button"><!-- ★Block -->
</div>
</div>
Blockにはmargin
・position:absolute
を指定しない
Block要素は一つ一つが独立したパーツであり、他のページでも繰り返し利用されるパーツとして扱うため、別の場所で利用した際に意図しない挙動が発生する可能性があるのでmargin
とposition:absolute
の指定は避けましょう。
もちろんmargin
の指定ができないとレイアウトを調整できないという問題が発生します。
その場合はのちほど紹介する「Mix」というテクニックを利用してレイアウトを調整していきますので安心してください。
必須ではありませんが「width」もBlockには指定せずコンテンツ幅に合わせる方がパーツとしての再利用性が高まります。
BEMの応用テクニック
Mix(ミックス)
MixとはBlock自体が持つべきではないレイアウトなどに関する指定をElementを利用して指定する、BEMにとって最も重要なテクニックです。
例として下記のようなa
タグに.button
というBlockと.card__button
というElementの二つのclassが付与されている要素があります。
このように複数のclassでスタイルの役割を変えるやり方がMixというテクニックです。.button
自体が持つべきではない、レイアウトに関する指定を.card__button
が担当しています。
<div class="card">
<figure class="card__image-wrapper"></figure>
<div class="card__body">
<h2 class="card__heading">
<p class="card__description">
<a class="button card__button"><!-- ★Mix -->
</div>
</div>
/* ○ Elementでレイアウトを指定 */
.card__button {
margin-left:auto;
margin-right:auto;
}
/* × block自体にレイアウトに関するスタイルを指定している */
.button {
margin-left:auto;
margin-right:auto;
}
Sass(サス)で書く
BEM自体の話と少しそれますが、BEMでコーディングする際はSassを利用することで、より効率的にBEMを運用することが可能です。
Sass とは
Sassとはcssを効率的に書くができるように開発されたメタ言語で、変数や外部ファイル読み込みなど、cssではできない機能利用することができるコーディングの方法です。
Sass自体はブラウザで読み取ることができないため、利用する際はSassファイルをcssファイルへと変換して利用します。
下記のようなhtml構造の場合、Sassでcssを書くとこのようにBlock自体がグループ化されます。
親要素のBlockの文字列を引き継ぎ、コードの記述がすくなくなり記述ミスが減り効率も上がるため、BEMに慣れてきたらSassの知識をつけることもおすすします。
<div class="card">
<figure class="card__image-wrapper"></figure>
<div class="card__body">
<h2 class="card__heading">
<p class="card__description">
<a class="button">
</div>
</div>
.card {
&__image-wapper {}
&__body {}
&__heading {}
&__description {}
&__button {}
}
/* cssではこのようにコンパイルされます */
.card__image-wapper {}
.card__body {}
.card__heading {}
.card__description {}
.card__button {}
Block全体にかかるModifier
Blockと子要素全体のElementに対してのModifierは、それぞれのElementに指定するのではなく、Blockに対してのみ指定しBlockの子要素としてスタイルを適用します。
/* ○ */
.card--shadow .card__image-wapper {}
.card--shadow .card__body {}
.card--shadow .card__heading {}
/* × */
.card__image-wapper--shadow {}
.card__body--shadow {}
.card__heading--shadow {}
このテクニックが許される理由としては詳細度が上がったとしても、利用されるシーンがものすごく限定的であるということです。
先ほどのBEMの基本ルールで全て単一のclassに対してスタイルを適用すると説明しましたが、今回は例外のテクニックとして紹介しました。