はじめに

CSSの開発において「同じクラス名を使ってしまい、意図しない箇所のスタイルが崩れた」「クラス名から役割がわからず、修正箇所を特定するのに時間がかかった」といった経験はないでしょうか。

これらの問題を解決するのがBEM(Block Element Modifier)記法です。BEMは、Yandex社が開発した命名規則で、Google、BBC、JetBrainsなど世界中の企業で採用されています。

本記事では、BEM記法を基礎から実践まで体系的に解説します。

  • BEM記法の基本概念(Block、Element、Modifier)
  • BEMの命名ルールと記法パターン
  • 実践的なコンポーネント設計手法
  • BEMのメリットと注意点
  • よくあるアンチパターンと対処法

前提条件

本記事を読み進めるにあたり、以下の知識があることを前提としています。

  • CSSの基本構文(セレクタ、プロパティ、値の関係)
  • CSSセレクタ(要素、クラス、ID、属性セレクタ)の使い方
  • CSSの詳細度とカスケードの基礎知識

CSS設計の基本原則については、CSS設計の基本原則 - 保守性の高いスタイルを書くためにを参照してください。

動作確認環境

  • Google Chrome 131以降
  • Firefox 133以降
  • Safari 18以降
  • Microsoft Edge 131以降

BEM記法とは

BEMの3つの構成要素

BEMは「Block」「Element」「Modifier」の頭文字を取った命名規則です。UIを3つの概念に分解し、それぞれに明確な役割を持たせることで、予測可能で再利用しやすいCSSクラスを設計できます。

graph TD
    A[BEM記法] --> B[Block<br/>独立したコンポーネント]
    A --> C[Element<br/>Blockを構成する要素]
    A --> D[Modifier<br/>状態やバリエーション]
    
    B --> E["例: .card, .button, .nav"]
    C --> F["例: .card__title, .button__icon"]
    D --> G["例: .card--featured, .button--large"]

Block(ブロック)

Blockは、単独で意味を持つ独立したコンポーネントです。ヘッダー、ナビゲーション、カード、ボタンなど、再利用可能なUI部品がBlockに該当します。

1
2
3
4
5
6
/* Blockの例 */
.header { }
.navigation { }
.card { }
.button { }
.search-form { }

Blockは以下の特徴を持ちます。

特徴 説明
独立性 他のBlockに依存せず、単独で機能する
再利用性 ページ内の任意の場所に配置できる
ネスト可能 Block内に別のBlockを含められる
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<!-- Blockは単独で意味を持つ -->
<nav class="navigation">
  <!-- 中身は後で追加 -->
</nav>

<!-- Blockは他のBlock内にネストできる -->
<header class="header">
  <nav class="navigation">
    <!-- navigationはheaderに依存しない独立したBlock -->
  </nav>
</header>

Element(エレメント)

Elementは、Blockを構成する要素で、Block外では意味を持たない部品です。Elementは必ず特定のBlockに属し、Block名とElement名をダブルアンダースコア(__)で接続して表現します。

1
2
3
4
5
6
/* 構文: block__element */
.card__title { }
.card__image { }
.card__content { }
.navigation__item { }
.navigation__link { }

Elementの特徴は以下のとおりです。

特徴 説明
従属性 必ず特定のBlockに属する
意味の限定 Block外では単独で使用できない
フラット構造 Element同士のネストは命名に反映しない
1
2
3
4
5
6
<!-- Elementは必ずBlock内に配置 -->
<article class="card">
  <img class="card__image" src="thumbnail.jpg" alt="サムネイル">
  <h2 class="card__title">記事タイトル</h2>
  <p class="card__content">記事の概要です。</p>
</article>

Modifier(モディファイア)

Modifierは、BlockやElementの見た目・状態・振る舞いを変更するフラグです。Block名またはElement名とModifier名をダブルハイフン(--)で接続して表現します。

1
2
3
4
5
6
7
8
/* Block Modifier: block--modifier */
.button--primary { }
.button--large { }
.card--featured { }

/* Element Modifier: block__element--modifier */
.card__title--highlighted { }
.navigation__link--active { }

Modifierには2種類のタイプがあります。

タイプ 説明
Boolean 存在の有無で状態を表す --disabled, --active, --hidden
Key-Value 値を持つバリエーション --size-large, --theme-dark, --color-red
1
2
3
4
5
6
7
<!-- Boolean Modifier -->
<button class="button button--disabled">無効なボタン</button>

<!-- Key-Value Modifier -->
<button class="button button--size-large button--theme-primary">
  大きなプライマリボタン
</button>

BEMの命名ルール

基本構文

BEMの命名規則は以下の構文に従います。

block-name__element-name--modifier-name

各パーツの接続ルールをまとめると以下のようになります。

graph LR
    A[block-name] -->|"__"| B[element-name]
    A -->|"--"| C[modifier-name]
    B -->|"--"| D[element-modifier]
    
    style A fill:#e1f5fe
    style B fill:#fff3e0
    style C fill:#f3e5f5
    style D fill:#f3e5f5

詳細な命名ルール

BEMの命名において守るべきルールは以下のとおりです。

ルール 説明
小文字のみ使用 大文字は使用しない searchFormsearch-form
単語はハイフンで接続 複合語はハイフンで区切る mainnavigationmain-navigation
Elementは__で接続 ダブルアンダースコアを使用 card__title
Modifierは--で接続 ダブルハイフンを使用 button--primary

命名スタイルのバリエーション

BEMにはいくつかの命名スタイルが存在します。本記事では最も一般的な「Two Dashes style」を採用していますが、プロジェクトによっては他のスタイルを採用することもあります。

1
2
3
4
5
/* Two Dashes style(本記事で採用) */
.block-name__element-name--modifier-name { }

/* 例 */
.search-form__input--disabled { }
1
2
3
4
5
/* Classic style(元祖BEM) */
.block-name__element-name_modifier-name { }

/* 例 */
.search-form__input_disabled { }
1
2
3
4
5
/* CamelCase style */
.blockName-elemName_modName { }

/* 例 */
.searchForm-input_disabled { }

プロジェクト内では一貫したスタイルを使用することが重要です。チームで開発する場合は、どのスタイルを採用するか事前に合意しておきましょう。

実践的なコンポーネント設計

カードコンポーネントの設計

実際のUIコンポーネントをBEMで設計してみましょう。以下は、ブログ記事のカードコンポーネントの例です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<article class="article-card article-card--featured">
  <div class="article-card__thumbnail">
    <img 
      class="article-card__image" 
      src="/images/thumbnail.jpg" 
      alt="記事のサムネイル"
    >
    <span class="article-card__category">技術記事</span>
  </div>
  <div class="article-card__body">
    <h2 class="article-card__title">BEM記法入門ガイド</h2>
    <p class="article-card__excerpt">
      BEMの命名規則を使って保守性の高いCSSを書く方法を解説します。
    </p>
    <div class="article-card__meta">
      <time class="article-card__date">2026-01-05</time>
      <span class="article-card__author">山田太郎</span>
    </div>
  </div>
  <a class="article-card__link" href="/posts/bem-guide/">続きを読む</a>
</article>

対応するCSSは以下のようになります。

 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/* Block */
.article-card {
  display: flex;
  flex-direction: column;
  background-color: #ffffff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

/* Block Modifier */
.article-card--featured {
  border: 2px solid #3b82f6;
}

/* Elements */
.article-card__thumbnail {
  position: relative;
  aspect-ratio: 16 / 9;
}

.article-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.article-card__category {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 4px 8px;
  background-color: #3b82f6;
  color: #ffffff;
  font-size: 12px;
  border-radius: 4px;
}

.article-card__body {
  padding: 16px;
  flex: 1;
}

.article-card__title {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 700;
  line-height: 1.4;
}

.article-card__excerpt {
  margin: 0 0 12px;
  color: #6b7280;
  font-size: 14px;
  line-height: 1.6;
}

.article-card__meta {
  display: flex;
  gap: 16px;
  font-size: 12px;
  color: #9ca3af;
}

.article-card__date { }

.article-card__author { }

.article-card__link {
  display: block;
  padding: 12px 16px;
  background-color: #f3f4f6;
  color: #3b82f6;
  text-align: center;
  text-decoration: none;
  font-weight: 500;
  transition: background-color 0.2s;
}

.article-card__link:hover {
  background-color: #e5e7eb;
}

ナビゲーションコンポーネントの設計

複数の状態を持つナビゲーションコンポーネントの例です。

 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
30
31
<nav class="main-nav">
  <ul class="main-nav__list">
    <li class="main-nav__item">
      <a class="main-nav__link main-nav__link--active" href="/">
        ホーム
      </a>
    </li>
    <li class="main-nav__item">
      <a class="main-nav__link" href="/about/">
        このサイトについて
      </a>
    </li>
    <li class="main-nav__item main-nav__item--has-dropdown">
      <a class="main-nav__link" href="/categories/">
        カテゴリ
      </a>
      <ul class="main-nav__dropdown">
        <li class="main-nav__dropdown-item">
          <a class="main-nav__dropdown-link" href="/categories/frontend/">
            フロントエンド
          </a>
        </li>
        <li class="main-nav__dropdown-item">
          <a class="main-nav__dropdown-link" href="/categories/backend/">
            バックエンド
          </a>
        </li>
      </ul>
    </li>
  </ul>
</nav>
 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/* Block */
.main-nav {
  background-color: #1f2937;
}

/* Elements */
.main-nav__list {
  display: flex;
  gap: 4px;
  margin: 0;
  padding: 0 16px;
  list-style: none;
}

.main-nav__item {
  position: relative;
}

.main-nav__item--has-dropdown:hover .main-nav__dropdown {
  display: block;
}

.main-nav__link {
  display: block;
  padding: 16px 12px;
  color: #d1d5db;
  text-decoration: none;
  transition: color 0.2s;
}

.main-nav__link:hover {
  color: #ffffff;
}

/* Element Modifier */
.main-nav__link--active {
  color: #ffffff;
  border-bottom: 2px solid #3b82f6;
}

.main-nav__dropdown {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 180px;
  margin: 0;
  padding: 8px 0;
  background-color: #374151;
  border-radius: 0 0 4px 4px;
  list-style: none;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.main-nav__dropdown-item { }

.main-nav__dropdown-link {
  display: block;
  padding: 8px 16px;
  color: #d1d5db;
  text-decoration: none;
}

.main-nav__dropdown-link:hover {
  background-color: #4b5563;
  color: #ffffff;
}

フォームコンポーネントの設計

入力フォームのバリデーション状態を含むコンポーネントの例です。

 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<form class="contact-form">
  <div class="contact-form__group">
    <label class="contact-form__label" for="name">
      お名前
      <span class="contact-form__required">必須</span>
    </label>
    <input 
      class="contact-form__input" 
      type="text" 
      id="name" 
      name="name"
      placeholder="山田太郎"
    >
  </div>
  
  <div class="contact-form__group contact-form__group--error">
    <label class="contact-form__label" for="email">
      メールアドレス
      <span class="contact-form__required">必須</span>
    </label>
    <input 
      class="contact-form__input contact-form__input--error" 
      type="email" 
      id="email" 
      name="email"
      placeholder="example@example.com"
    >
    <span class="contact-form__error-message">
      有効なメールアドレスを入力してください
    </span>
  </div>
  
  <div class="contact-form__group">
    <label class="contact-form__label" for="message">
      お問い合わせ内容
    </label>
    <textarea 
      class="contact-form__textarea" 
      id="message" 
      name="message"
      rows="5"
    ></textarea>
  </div>
  
  <div class="contact-form__actions">
    <button class="contact-form__button contact-form__button--primary" type="submit">
      送信する
    </button>
    <button class="contact-form__button contact-form__button--secondary" type="reset">
      クリア
    </button>
  </div>
</form>
  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
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
/* Block */
.contact-form {
  max-width: 600px;
  padding: 24px;
  background-color: #ffffff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* Elements */
.contact-form__group {
  margin-bottom: 20px;
}

.contact-form__group--error .contact-form__input,
.contact-form__group--error .contact-form__textarea {
  border-color: #ef4444;
}

.contact-form__label {
  display: block;
  margin-bottom: 6px;
  font-weight: 500;
  color: #374151;
}

.contact-form__required {
  margin-left: 4px;
  padding: 2px 6px;
  background-color: #ef4444;
  color: #ffffff;
  font-size: 11px;
  border-radius: 2px;
}

.contact-form__input,
.contact-form__textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid #d1d5db;
  border-radius: 4px;
  font-size: 16px;
  transition: border-color 0.2s, box-shadow 0.2s;
}

.contact-form__input:focus,
.contact-form__textarea:focus {
  outline: none;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
}

.contact-form__input--error {
  border-color: #ef4444;
}

.contact-form__input--error:focus {
  border-color: #ef4444;
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2);
}

.contact-form__error-message {
  display: block;
  margin-top: 4px;
  color: #ef4444;
  font-size: 13px;
}

.contact-form__textarea {
  resize: vertical;
  min-height: 120px;
}

.contact-form__actions {
  display: flex;
  gap: 12px;
  margin-top: 24px;
}

.contact-form__button {
  padding: 12px 24px;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.2s;
}

.contact-form__button--primary {
  background-color: #3b82f6;
  color: #ffffff;
}

.contact-form__button--primary:hover {
  background-color: #2563eb;
}

.contact-form__button--secondary {
  background-color: #e5e7eb;
  color: #374151;
}

.contact-form__button--secondary:hover {
  background-color: #d1d5db;
}

BEMのメリット

予測可能性の向上

BEMを使用することで、クラス名から以下の情報を即座に読み取れます。

graph LR
    A[".article-card__title--highlighted"] --> B["Block: article-card"]
    A --> C["Element: title"]
    A --> D["Modifier: highlighted"]
    
    B --> E["独立したカードコンポーネント"]
    C --> F["カードのタイトル部分"]
    D --> G["強調表示状態"]

この予測可能性により、以下のメリットが得られます。

メリット 説明
コードの理解が容易 クラス名を見ただけで役割がわかる
検索性の向上 Block名で関連するスタイルを検索できる
影響範囲の把握 変更がどこに影響するか予測できる

詳細度の統一

BEMでは、すべてのセレクタがクラスセレクタ1つで構成されるため、詳細度が均一になります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* BEMを使用した場合: すべて詳細度 0-1-0 */
.button { }
.button--primary { }
.button__icon { }
.navigation__link--active { }

/* BEMを使用しない場合: 詳細度がバラバラ */
#header .nav a { }           /* 1-1-1 */
.container .button { }        /* 0-2-0 */
nav ul li a.active { }        /* 0-1-4 */

詳細度が統一されることで、以下の問題を回避できます。

  • !importantの多用
  • 詳細度を上げるためのセレクタの複雑化
  • スタイルの上書きが困難になる「詳細度戦争」

再利用性とモジュール性

Blockは独立したコンポーネントとして設計されるため、他のページやプロジェクトへの移植が容易です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/* このBlockは他のプロジェクトにそのままコピーできる */
.tag {
  display: inline-block;
  padding: 4px 8px;
  background-color: #e5e7eb;
  border-radius: 4px;
  font-size: 12px;
}

.tag--primary {
  background-color: #3b82f6;
  color: #ffffff;
}

.tag--danger {
  background-color: #ef4444;
  color: #ffffff;
}

自己文書化されたコード

BEMのクラス名は、それ自体がドキュメントの役割を果たします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<!-- クラス名から構造と状態がわかる -->
<div class="modal modal--open">
  <div class="modal__overlay"></div>
  <div class="modal__content">
    <h2 class="modal__title">確認</h2>
    <p class="modal__body">この操作を実行しますか?</p>
    <div class="modal__actions">
      <button class="modal__button modal__button--confirm">はい</button>
      <button class="modal__button modal__button--cancel">いいえ</button>
    </div>
  </div>
</div>

BEMの注意点とアンチパターン

クラス名が長くなる問題

BEMの最大の懸念点は、クラス名が長くなりがちなことです。

1
2
/* 長すぎるクラス名の例 */
.user-profile-card__social-media-links__twitter-icon--highlighted { }

この問題への対処法は以下のとおりです。

  1. Block名を簡潔にする: user-profile-cardprofile-card または user-card
  2. 深いネストは新しいBlockに切り出す: 後述の「Elementのネスト問題」を参照

Elementのネスト問題

BEMでは、Element内のElementを__で連結しません。これはBEMの重要なルールです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* 悪い例: Element内のElementを連結 */
.card__header__title { }
.card__body__content__paragraph { }

/* 良い例: フラットな構造を維持 */
.card__header { }
.card__title { }
.card__body { }
.card__content { }
.card__paragraph { }

HTMLのDOM構造がネストしていても、BEMのクラス名はフラットに保ちます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!-- DOM構造はネストしているが、クラス名はフラット -->
<article class="card">
  <header class="card__header">
    <h2 class="card__title">タイトル</h2>
    <span class="card__category">カテゴリ</span>
  </header>
  <div class="card__body">
    <p class="card__content">本文です。</p>
  </div>
</article>

Blockへの切り出し判断

コンポーネントが複雑になった場合、一部を新しいBlockとして切り出すことを検討します。

graph TD
    A[Blockが複雑になったら] --> B{再利用の可能性は?}
    B -->|高い| C[新しいBlockとして切り出す]
    B -->|低い| D{Elementが多すぎる?}
    D -->|はい| C
    D -->|いいえ| E[現状維持]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<!-- 切り出し前: cardに多くのElementがある -->
<article class="card">
  <div class="card__author-info">
    <img class="card__author-avatar" src="avatar.jpg">
    <span class="card__author-name">山田太郎</span>
    <span class="card__author-role">エンジニア</span>
  </div>
</article>

<!-- 切り出し後: authorを独立したBlockに -->
<article class="card">
  <div class="card__author">
    <div class="author">
      <img class="author__avatar" src="avatar.jpg">
      <span class="author__name">山田太郎</span>
      <span class="author__role">エンジニア</span>
    </div>
  </div>
</article>

Modifierの単独使用

Modifierは必ず元のBlockまたはElementクラスと併用します。Modifier単独での使用は禁止です。

1
2
3
4
5
<!-- 悪い例: Modifierのみ -->
<button class="button--primary">ボタン</button>

<!-- 良い例: 元のクラスと併用 -->
<button class="button button--primary">ボタン</button>

これは、Modifierが元のスタイルを「修正」するものであり、ベースとなるスタイルが必要だからです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/* ベーススタイル */
.button {
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

/* Modifierはベーススタイルを上書き・拡張 */
.button--primary {
  background-color: #3b82f6;
  color: #ffffff;
}

SCSSでBEMを効率的に書く

SCSSのネスト機能を使うと、BEMをより効率的に記述できます。

親セレクタ参照(&)の活用

 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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
.card {
  background-color: #ffffff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  
  // Element: &__element
  &__header {
    padding: 16px;
    border-bottom: 1px solid #e5e7eb;
  }
  
  &__title {
    margin: 0;
    font-size: 18px;
    font-weight: 700;
    
    // Element Modifier
    &--large {
      font-size: 24px;
    }
  }
  
  &__body {
    padding: 16px;
  }
  
  &__footer {
    padding: 16px;
    background-color: #f9fafb;
  }
  
  // Block Modifier
  &--featured {
    border: 2px solid #3b82f6;
  }
  
  &--compact {
    .card__header,
    .card__body,
    .card__footer {
      padding: 8px;
    }
  }
}

コンパイル後のCSSは以下のようになります。

 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
30
31
32
.card {
  background-color: #ffffff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card__header {
  padding: 16px;
  border-bottom: 1px solid #e5e7eb;
}
.card__title {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
}
.card__title--large {
  font-size: 24px;
}
.card__body {
  padding: 16px;
}
.card__footer {
  padding: 16px;
  background-color: #f9fafb;
}
.card--featured {
  border: 2px solid #3b82f6;
}
.card--compact .card__header,
.card--compact .card__body,
.card--compact .card__footer {
  padding: 8px;
}

ファイル構成の例

BEMを採用したプロジェクトでは、Block単位でファイルを分割することが一般的です。

scss/
├── base/
│   ├── _reset.scss
│   └── _typography.scss
├── components/
│   ├── _button.scss
│   ├── _card.scss
│   ├── _form.scss
│   ├── _modal.scss
│   └── _navigation.scss
├── layouts/
│   ├── _header.scss
│   ├── _footer.scss
│   └── _sidebar.scss
└── main.scss

BEMと他の設計手法の組み合わせ

BEMとITCSSの併用

ITCSS(Inverted Triangle CSS)の階層構造とBEMの命名規則を組み合わせることで、より堅牢なCSS設計が可能になります。

graph TD
    A[Settings<br/>変数定義] --> B[Tools<br/>ミックスイン・関数]
    B --> C[Generic<br/>リセット・ノーマライズ]
    C --> D[Elements<br/>素のHTML要素]
    D --> E[Objects<br/>レイアウトパターン]
    E --> F[Components<br/>BEMで設計したUI部品]
    F --> G[Utilities<br/>ヘルパークラス]

BEMとユーティリティクラスの併用

Tailwind CSSのようなユーティリティファーストアプローチと、BEMによるコンポーネント設計を組み合わせる手法もあります。

1
2
3
4
5
<!-- BEMコンポーネント + ユーティリティクラス -->
<article class="card mt-4 mb-8">
  <h2 class="card__title text-center">タイトル</h2>
  <p class="card__content line-clamp-3">本文...</p>
</article>

この場合、BEMでコンポーネント固有のスタイルを定義し、ユーティリティクラスでスペーシングや配置などの汎用的なスタイルを適用します。

まとめ

BEM記法は、CSSクラスの命名規則を統一することで、予測可能で保守性の高いスタイル設計を実現する手法です。本記事で解説した内容を振り返ります。

概念 役割 命名規則
Block 独立したコンポーネント .block-name
Element Blockを構成する要素 .block-name__element-name
Modifier 状態やバリエーション .block-name--modifier

BEMを採用することで得られる主なメリットは以下のとおりです。

  • クラス名から役割と関係性が読み取れる(予測可能性)
  • 詳細度が統一され、スタイルの上書きが容易(詳細度の管理)
  • コンポーネント単位での再利用が可能(モジュール性)
  • コード自体がドキュメントになる(自己文書化)

一方、クラス名が長くなりがちという注意点もありますが、適切なBlock分割とSCSSの活用で軽減できます。

BEMは学習コストが低く、チームへの導入も容易な設計手法です。まずは小さなコンポーネントからBEMを適用し、徐々にプロジェクト全体に広げていくことをおすすめします。

参考リンク