「BEM」って何となく聞いたことあるけど、よくわからない….。
普段使ってみているけど、いまいち理解できてないかも…。
私もそうでした。今回は、「BEM」について改めて深堀して、理解を深めていきましょう!
そもそも「BEM」とは何?目的は?
「BEM」(ベム)は、CSS設計のうちの1つです。命名規則とも言います。
ウェブサイトを作る際、HTMLとCSSを組み合わせて使用しますよね。
CSSはHTMLのclass名などを使用して、要素を指定することができます。
<!-- HTML -->
<p class="text">このテキストは赤いです</p>
/* CSS */
.text {
color: red;
}
このclass名、結構な厄介者。
1人で作るときは自由につけてもよいかもしれません。ですが、実務では1つのウェブサイトを複数人で分担して制作することも多いですし、作った後に他の人が更新することもあるかも。
そんな時、それぞれが自由に規則性のないclass名を付けまくっていると、作った本人以外にはHTMLコードの関連性がわかりづらくなり、更新の難易度や間違いが起こる可能性が上がります。
長い間更新しなかったサイトなら、class名を付けたはずの自分でもよくわからなくなるものです。
それを防ぐために、class名の付け方にルールを設けて、みんながそれに従って命名します。それがCSS設計。
そうすれば、誰が見てもHTML内のコードの関連性を理解できますし、そのおかげで間違いも減ります。
さらには、一度付けたclass名を展開させて色違いのバージョンを作ったりすることも簡単になります。
「BEM」の概要
「BEM」とは、それぞれBlock、Element、Modifierの頭文字です。
- Block → 要素を構成する一番大きな塊。全体を囲む大枠みたいなイメージ。
- Element → Blockの中身を構成する要素たち。
- Modifier → 修飾子のことで、モディファイアと読みます。BlockやElementのスタイルを定義。
私がBEMを勉強したてのころは、特にElementとModifierの使い方や使い分けが難しく感じて、理解するまで結構かかった記憶があります。どーゆーことやねん、って思ってました(笑)。
実践!
では、簡単に以下のような構成を作るHTMLとCSSを、BEM設計で作ってみましょう。

私はこんな風に記述をしました。
スタイルの細かい記述も入れていますが、今回はそこまで重要じゃないのでサクッと読み飛ばしてもOKです。大事なのはclass名の構造です。
<!-- HTML -->
<div class="block">
<div class="block__item">
<div class="block__img">
<img src="./path/to/image/img01_01.jpg" alt="" />
</div>
<div class="block__contents">
<h3 class="block__heading">
見出し
</h3>
<p class="block__text">
テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
</p>
<div class="block__button-wrapper">
<a href="#" class="block__button">詳しくはこちら</a>
</div>
</div>
</div>
<div class="block__item">
<div class="block__img">
<img src="./path/to/image/img01_02.jpg" alt="" />
</div>
<div class="block__contents">
<h3 class="block__heading">
見出し
</h3>
<p class="block__text">
テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
</p>
<div class="block__button-wrapper">
<a href="#" class="block__button">詳しくはこちら</a>
</div>
</div>
</div>
<div class="block__item">
<div class="block__img">
<img src="./path/to/image/img01_03.jpg" alt="" />
</div>
<div class="block__contents">
<h3 class="block__heading">
見出し
</h3>
<p class="block__text">
テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
</p>
<div class="block__button-wrapper">
<a href="#" class="block__button block__button--reverse">詳しくはこちら</a>
</div>
</div>
</div>
</div>
/* CSS(SCSS) */
.block {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px;
@include mq() {
grid-template-columns: 1fr;
}
&__img {
@include mqup() {
max-width: 380px;
}
img {
aspect-ratio: 380 / 250;
object-fit: cover;
}
}
&__heading {
margin: 16px 0;
font-size: fz(28);
color: $main-color-01;
line-height: 1.2;
@include mq() {
font-size: fz(20);
}
}
&__button {
width: 180px;
margin: 22px auto 0;
padding: 14px;
display: block;
text-align: center;
border: 2px solid $accent-color;
background-color: $accent-color;
color: $text-color-white;
text-decoration: none;
font-weight: bold;
transition:
background-color 0.3s,
color 0.3s;
outline-offset: 4px;
&:hover {
background-color: $text-color-white;
color: $accent-color;
}
&--reverse {
background-color: $text-color-white;
color: $accent-color;
&:hover {
background-color: $accent-color;
color: $text-color-white;
}
}
}
}
※SCSSは変数を使った記述を掲載しています。
上記の例をもとに、Block、Element、Modifierをそれぞれ掘り下げてみましょう。
Block
今回のHTMLでは、.blockがBlockにあたります。(そのまんまですな)
上記の例ではやっていませんが、Blockの中にBlockをネスト(入れ子)しても大丈夫です。
スタイルの記述が、HTMLタグやページ上の他のブロックに影響されないようにしなければなりません。
/* NG:CSS(SCSS) */
div.block { /* ←HTMLタグがdivでなければ機能しない */
...
}
/* NG:CSS(SCSS) */
.border .block { /* ←.borderの子要素でなければ機能しない */
...
}
/* OK:CSS(SCSS) */
.block { /* ←HTMLタグや親要素を特定しない */
...
}
Element
.block__item や .block__img などがElementにあたります。
命名の仕方としては、Blockのclass名(今回は.block)と要素名にしたい単語をアンダーバー2つ(__)で繋ぎます。
Blockの名前を使用していることからも、BlockとElementは相互に関係を持っていることがわかります。
また、Elementは必ずBlockの子要素になります。Element単体では記述できません。
<!-- NG:HTML -->
<div class="block">
<div class="wrapper__item">...</div> <!-- ←Block名が親要素と一致していない -->
</div>
<!-- NG:HTML -->
<div class="block">...</div>
<div class="block__item">...</div> <!-- ←.blockの外でElementが独立している -->
<!-- OK:HTML -->
<div class="block">
<div class="block__item">...</div> <!-- ←.blockの子要素としてElementを記述 -->
</div>
ElementはBlockの中に複数存在できます。
また、Elementの中に別のElementをネストしても大丈夫です。
ただし、その場合は注意点があって、.block__element__element2 などのようにアンダーバー2つを連続させるのは好ましくありません。
別のElementをネストする場合も、それぞれは個別のElementとして命名してあげたほうが、スタイルが管理しやすくなります。
<!-- OK:HTML -->
<div class="block">
<div class="block__item">
<div class="block__img">...</div>
<!-- 省略 -->
</div>
</div>
上記の例では、.block__itemの中に.block__imgをネストしています。
この時、.block__item__imgとはしません。
Modifier
.block__button₋₋reverseがModifierとなります。
これは、通常の.block__buttonというElementの反転(reverse)バージョンという意味合いでこの命名をしています。
Modifierは、Block名やElement名と修飾子をハイフン2つ(₋₋)で繋ぎます。
特徴的なのがclass名の振り方で、Modifierだけは元のBlock名やElement名と一緒に付与します。
CSSは元のBlockやElementのスタイルを使いつつ、Modifierで変更したいスタイルだけを記述できます。
元のBlock名やElement名を併記することで、簡単にバージョン違いを作れます。
<!-- OK:HTML -->
<div class="block__button-wrapper">
<a href="#" class="block__button block__button--reverse">詳しくはこちら</a>
</div>
/* CSS(SCSS) */
.block {
&__button {
/* デフォルトのスタイル(省略) */
&--reverse {
/* デフォルトのスタイルから変えたいものだけを記述する */
background-color: $text-color-white;
color: $accent-color;
}
}
}
SCSSの書き方
BEMのメリットとして紹介されることが多いのが、SCSSとの組み合わせです。
これまでの例でも示したように、SCSSはネストして書くことができるため、HTMLの見た目と整合性があります。
<!-- HTML -->
<div class="block">
<div class="block__item">
<div class="block__img">...</div>
<!-- 省略 -->
</div>
</div>
/* CSS(SCSS) */
.block {
.block__item {
/* .block__itemのスタイル */
}
.block__img {
/* .block__imgのスタイル */
}
}
ネストの時に、SCSSは「&」を用いることで親要素の名前を表すことができます。
この特性を利用して、以下のように簡潔に書くことができるのがメリットである、と紹介されていることも多いです。
/* CSS(SCSS) */
.block {
&__item {
/* .block__itemのスタイル */
}
&__img {
/* .block__imgのスタイル */
}
}
この書き方、実は検索でclass名を探しにくいというデメリットもあります。
VSCodeなどではフォルダ内指定や全体の検索ができると思いますが、例えばそこで.block__itemを探したいと思ったとき、このまま打ってもヒットしません。
.blockを先に探して、そこから&__itemを探して…という作業になります。
これは好みの問題もあるのでどちらがより良いということは無いかなと思いますが、もし実務のチーム開発などでBEMを使用する場合は、チームでネストの書き方を認識合わせしておくべきでしょう。
あとがき:使ってみてどう?現場では?
私がいたチームでは、当初は命名規則を取り決めていなかったのですが、管理がしやすい・ハードルが低いなどの利点から、標準のルールとしてBEMを導入しました。
個人的には、BEMは比較的考え方が簡単なほうのCSS設計かなと思います。(FLOCSSとかも勉強してみたものの、結構難しかった。。)
それでも実務で使うようになって、やっとこさElementとModifierの使い分けがわかってきた感じなので、BEMもそれなりに難しくはあるのですが。
あと、BEMはあくまでもアンダーバーやハイフンでの繋ぎ方のルールであって、単語はルール化してくれていません。
これも地味に私は躓きポイントで、どの単語をどこの名前にあてはめたら最適なのかを永遠に探究しています…!
英語はそんなに苦にしていないほうですが、それでも英単語考えるの大変な時があります(泣)。
下記などを参考にしています。
CSSのクラス名を決めるときに使うリストをつくりました #CSS設計 – Qiita
codic – プログラマーのためのネーミング辞書
BEMは私が訓練校に通っていた頃(2019年)から名前を聞いていましたが、フロントエンドは流れが速いので廃れも早いです。それでも今も実務の現場で使われているので、勉強しておいて損は無いかなと思います。
ちなみに私がいるのはモダンな技術使いまくりのイケてる感じの実装がそんなに得意な環境ではないので、もしかしたらイケイケな環境ではもはや古の技術になっているかもしれません。。
あとがき
BEMについて掘り下げてみましたが、いかがでしたか?
実務ではCSS設計は肝になるところでもあるので、BEMを足掛かりにして他のCSS設計にもチャレンジしてみるとよいかもしれません。(私も勉強しますー!)
この記事を書いているうちに「Block」がゲシュタルト崩壊しました。。(笑)
コメント