【HTML5・CSS3】CSS設計のBEMを1から理解してマスターしよう!

HTML5・CSS3

BEMとは?

BEMとは、Block(かたまり)・Element(要素)・Modifier(修飾)の頭文字をとったものです。厳格なclass名の命名ルールが特徴的なCSS設計方法の一つです。

また、Webサイトで機能を持つ各パーツ(部品)の要素をまとめて成り立っていることをコンポーネント化と言いますが、BEMは、コンポーネント化する為のフロントエンド設計方法の一つとも言えます。

BEMのメリット・デメリットとは?
リンクをコピーしました

「メリット」

  • 命名規則を抑えれば、簡単に取り込む事ができる
  • BEMの厳格なclass名の命名ルールによって、HTMLを見ただけでスタイルが予測しやすい
  • 長期的なメンテナンス性が高い

「デメリット」

  • クラス名が長くなりやすい
  • 普通のCSSで書くと、冗長になってしまう

BEMを取り入れることで、長期的なメンテナンス性が高くなったり、開発スピードが上がります。クラス名が長く普通のCSSで記述が大変ですが、後述するSassを使えば解決してしまいます。

BEMを構成する3つの要素
リンクをコピーしました

BEMを構成する重要な要素に、「Block(ブロック)/Element(エレメント)/Modifier(モディファイア)」があります。

  • Block ‥‥かたまり
  • Element ‥‥要素
  • Modifier ‥‥修飾子

Block(かたまり)を構成するのがElement(要素)です。
Modifier(修飾)は、Block(かたまり)とElement(要素)のスタイルや状態を修飾します。

命名規則
1
block__element--modifier

後述、命名規則については詳しく解説しますが、「BlockとElementはアンダースコア2つ(__)」で区切り, 「ElementとModifierはハイフン2つ(--)」で区切ります。

Block(かたまり)
リンクをコピーしました

1つのWebページ(※1)は、ヘッダー、フッダー、ナビゲーション、サイドバーなどのパーツで構成されています。このパーツにあたる部分がBlockです。Blockは、コンポーネントとも捉えることが出来るでしょう。

bem_1

「Header block」の中にある「Nav block」の様に、blockは他のblockを含めることが出来ます。

(※1)Webページが分からないという方は、HTMLが使用されている具体例の補足説明を参考にして下さい。

BlockをBEMで定義する
リンクをコピーしました

検索フォームである「Search block」をBEMで書くと次の様になります。

HTML | Blockを定義する
1
2
3
4
<div class="search"> <!-- Block -->
  <input class="search__input"> <!-- Element -->
  <input class="search__btn"> <!-- Element -->
</div>

上記のコードは、searchのBlockに2つのElement(input,btn)が属しています。

BlockのsearchとElementのinputとbtnは、二重アンダースコア(__)で区切ります。

Element(要素)
リンクをコピーしました

Elementは、Blockを構成する要素です。
検索フォームのSearch blockの構成を確認して見ましょう。

「input」と「submit」は「Search block」を構成する要素(Element)になります。

BlockをElementで定義する
リンクをコピーしました

ElementはBlockに属しているので、クラス名には必ずBlock名を含めます。
これにより、どこまでがBlockなのか一目で理解する事が出来ます。

HTML | Elementを定義する
1
2
3
4
<div class="search"> <!-- Block -->
  <input class="search__input"> <!-- Element -->
  <input class="search__btn"> <!-- Element -->
</div>

Elementを繰り返し利用する
リンクをコピーしました

下記のNav blockには複数のElementが属しています。

bem_3

「Nav block」のElementの様に「ElementはBlock内で繰り返し使うことが出来ます。」

Modifier(修飾)
リンクをコピーしました

既存のBlockやElementに対して、一部見た目や状態を変えたい場合に、新規に作り直すのではなくModifierを使います。

bem_4

BlockやElementが繰り返し使われているなどで、2種類以上存在する場合にModirierを使います。

Modifierの種類とは?
リンクをコピーしました

Modifierは、「Blockに対して使うModifier」と「Elementに対して使うModifier」があります。また、Modifierは名前である「key」と値である「value」を持ちます。

Modifierの種類
1
2
3
4
5
6
7
8
9
<!-- Blockに対して修飾 -->
Block--Modifier

<!-- Elementに対して修飾 -->
Block__Element--Modifier

<!-- Modifierのkey,valueを指定する場合 -->
Block--key_value
Block__Element--key_value

BlockやElementの後にハイフン2つで区切って定義します。key,valueを定義する場合は、keyとvalueをアンダースコア1つで区切ります。

Blockに対してModifierを定義
リンクをコピーしました

構成要素自体を変えたい時にBlockに対してModifierを使用します。例えば、下記の様に赤枠で囲まれているContent blockがあります。

このContent blockは繰り返し使われていますが、片方だけ背景を黄色にしたい場合にModifierが必要になります。

HTML | BlockにModifierを定義
1
2
3
4
5
6
7
8
<div class="content">
        <img class="content__img" src="">
        <div class="content__txt">テキスト</div>
</div>
<div class="content content--yellow">  <!-- Modifier -->
        <img class="content__img" src="">
        <div class="content__txt">テキスト</div>
</div>

BlockにModifierを定義するときは、「Block--Modifier」でハイフン2つで区切ります。
上記のコードでは、Blockを定義するcontentのクラス名に「content--yellow」を追加しています。

Elementに対してModifierを定義
リンクをコピーしました

Elementのバリエーションを作る場合は、Modifierが必要になります。例えば、Nav blockにあるナビゲーションの様に、現在地を他のメニューと変える時にModifierを使います。

bem_6

HTML | ElementにModifierを定義
1
2
3
4
5
  <ul class="nav">
    <li class="nav__item nav__item--state_current">Home</li>  <!-- Modifier -->
    <li class="nav__item">About</li>
    <li class="nav__item">Contact</li>
  </ul>

Modifierをkey(stateは状態)とvalue(currentは現在地)を使うと、そのクラスが何を表しているのか理解出来て可読性が良くなります。

その他の例
リンクをコピーしました

Modifierの例をもう少し見てみましょう。下記の様な登録フォームはWebサイトでよく見ますが、ページによってボタンのスタイルを一部変えたい場合にModifierが使えます。

「form__button」は、Sassで下記の様にスタイルが指定されています。(Sassについては、後述します。)

bem_8

HTML | 登録フォームの1部を抜粋しています
1
2
3
4
<form class="form">
  <input input type="text" class="form__name">
  <input type="submit" class="form__button">
</form>

下記の様にボタンの背景色を赤や青に変更したり、角を丸くします。

HTML | 登録フォームの1部を抜粋しています
1
2
3
4
5
6
7
8
9
10
11
<!-- この部分に一部変更するクラスを追加します。-->
<input type="submit" class="form__button">

<!-- 背景を赤色にする -->
<input type="submit" class="form__butto form__button--red">

<!-- 背景を青色にする -->
<input type="submit" class="form__butto form__button--blue">

<!-- 角を丸くする -->
<input type="submit" class="form__butto form__button--round">

スタイルは省きますが、それぞれ「form_button--red」、「formbutton--blue」、「form_button--round」に独自のスタイルを追加します。

これにより、既存のスタイル + 独自のスタイルを取り入れる事が出来ます。

セパレーターと命名規則
リンクをコピーしました

セパレーターとは、Block、Element、Modifierを区切っている「アンダースコア2つ区切り(__)」や「ハイフン2つ区切り(--)」の区切り文字のことです。

セパレーターには、主に3種類あります。

  1. BlockとElementの区切り
  2. Block(Element)とModifierの区切り
  3. 単語区切り

セパレーターはBEMで重要な項目なので、もう一度1つ1つ整理していきましょう。

1. BlockとElementの区切り
リンクをコピーしました

BlockとElementは、アンダースコア2つ(__)で区切ります。

HTML | BlockとElementの区切り
1
2
3
4
<div class="search"> <!-- Block -->
  <input class="search__input"> <!-- Element -->
  <input class="search__btn"> <!-- Element -->
</div>

2. Block(Element)とModifierの区切り
リンクをコピーしました

Block(Element)とModifierは、Block(Element)の後にModifierをハイフン2つ(--)で区切ります。

HTML | Block(Element)とModifierの区切り
1
2
3
4
<div class="content content--yellow">  <!-- Modifier -->
        <img class="content__img" src="">
        <div class="content__txt">テキスト</div>
</div>

また、Modifierでkeyとvalueを指定する場合は、keyとvalueをアンダースコア1つ(_)で区切ります。

HTML | keyとvalueの区切り
1
2
3
4
5
 <ul class="nav">
    <li class="nav__item nav__item--state_current">Home</li>  <!-- keyとvalue -->
    <li class="nav__item">About</li>
    <li class="nav__item">Contact</li>
  </ul>

3. 単語区切り
リンクをコピーしました

BlockやElementのクラス名を、2つ以上の単語で表す場合に、ハイフン1つ(単語-単語)で区切ります。

HTML | 単語区切り
1
2
3
4
<div class="content-left"> <!-- 単語区切り -->
  <img class="content-left__img" src="">
  <div class="content-left__txt">テキスト</div>
</div>

BEMとSass
リンクをコピーしました

BEMのデメリットとして、クラス名が長くなってしまうのでCSSで記述する際は冗長になってしまう点が挙げら挙げられました。

しかし、BEMと親和性の高いSassを利用することで、CSSよりも非常に効率良くコーディングする事が出来ます。(Sassが分からない方は【HTML5・CSS3】Sassを攻略してコーディングを効率良く書こう!を参考にしてください。)

セパレーターの親子関係
リンクをコピーしました

BEMでは、Block、Element、Modifierに対してセパレーターを使って区切っていました。この「区切り元と区切り先」はそれぞれ「親と子」の関係になります。

HTML | セパレーターで見る親子関係
1
2
3
4
<div class="search"> <!-- Block -->
  <input class="search__input"> <!-- searchが区切り元、inputが区切り先 -->
  <input class="search__btn"> <!-- Element -->
</div>

search__inputの場合は、「searchが親」で「inputが子」になります。
この親子関係をSassの「&」を使うことによって、効率的に記述出来るのです。

BEMをSass(SCSS)で定義する
リンクをコピーしました

BEMで定義した親子関係に対して、Sassの「&」を使うと、ネスト構造(入れ子)で記述することが出来ます。

SCSS | BEMを使ったSCSS
1
2
3
4
5
6
7
8
9
10
11
.search {
  margin: 30px;

  &__input {
    font-size: 18px;
  }

  &__btn {
    color: red;
  }
}

上記がCSSにコンパイルされると、下記の様になります。CSSで書くとこの様に助長になってしまいます。

CSS | CSSへコンパイルした場合
1
2
3
4
5
6
7
8
9
.search {
  margin: 30px;
}
.search__input {
  font-size: 18px;
}
.search__btn {
  color: red;
}

ネストした「&」の後にセパレーターを忘れてしまうと、親子関係とみなされずCSSが上手くコンパイルされないので注意してください。

「&」を使う際の注意点
リンクをコピーしました

BEMでは、Blockの中にBlockを含める事が出来ました。
下記の例では、「Header block」の中に「Logo block」や「Nav block」が含まれています。

bem_7

しかし、SassではBlockをネストしてスタイルを記述してはいけません。
何故なら、Blockはどこかに依存する事なく、完全に独立させなければいけないからです。別の場所に移しても単体で動作する必要があります。

「Modifier」と「placeholder selector」
リンクをコピーしました

placeholder selector(プレースホルダーセレクタ)とは、再利用できるスタイルセットを%キーワードで指定する@extend専用のセレクタです。(@extendについては、@extendディレクティブを参考にしてください。)

SCSS | プレースホルダーセレクタを定義する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
%default-item {
  // 共通するスタイルを定義
  background-color: yellow;
  color: #53579F;
  padding: 10px;
}

.nav {
  &__item {
      @extend %default-item;

    &--state_current{
      //Modifierのスタイルを定義
      @extend %default-item;
      background-color: pink;
    }
  }
}

Modifierは、placeholder selectorを使って差分のみ記述します。上記がCSSにコンパイルされると下記の様になります。

CSS | CSSへコンパイルした場合
1
2
3
4
5
6
7
8
9
.nav__item, .nav__item--state_current {
  background-color: yellow;
  color: #53579F;
  padding: 10px;
}

.nav__item--state_current {
  background-color: pink;
}

placeholder selectorで定義した共通のスタイルを@extendで継承して、Modifierの箇所で変更するスタイルを定義する事で、保守性のある綺麗なコードを保つことが出来ます。

まとめ

  • BEMとは、Block(かたまり)・Element(要素)・Modifier(修飾)の略語です
  • BEMの厳格なclass名の命名ルールによって、HTMLを見ただけでスタイルが予測しやすいメリットがあります。
  • Block、Element、Modifierを区切っている「アンダースコア2つ区切り(__)」や「ハイフン2つ区切り(--)」の区切り文字のことをセパレーターと言います。