bem-structure について
bem-structure は、BEM の命名規則と構造に沿って CSS を作成・レビューするエージェントスキルです。重複するブロックを作らず、適合する Optics コンポーネントの再利用も促します。
主な機能
- 01BEM 命名規則の適用
- 02ブロック、エレメント、モディファイアの構成
- 03明示的なクラスセレクター
- 04既存 Optics コンポーネントの考慮
- 05明確で影響の小さい CSS 変更の優先
活用シーン
- 01CSS の BEM 整合性レビュー
- 02スタイルの BEM 構造へのリファクタリング
- 03曖昧または不統一なクラス名の修正
- 04Optics コンポーネントと新規ブロックの選択
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rolemodel/ rolemodel-skills --skill bem-structureインストール後、Claude Code で/bem-structureを入力して読み込まれたか確認します。
詳細
概要
このスキルは、明確な命名規則とコンポーネント構造を用いて、保守性、拡張性、再利用性に優れたスタイルシートを作成するため、BEM(Block Element Modifier)手法に基づくCSSの記述をAIにガイドします。また、スコープ、リスク、アーキテクチャへの影響を判断しながら、Optics(当社のRoleModelデザインシステム)と組み合わせてBEMを使用し、すでに存在するものを再作成しないようにします。ニーズに合うOpticsコンポーネントがすでにある場合は、新しいBEMブロックを作成するのではなく、必要に応じてそのコンポーネントを使用、またはオーバーライドしてください。
エージェントは、明確さ、予測可能性、意図しない副作用の最小化を優先する必要があります。
キーワード:CSSレビュー、BEM構造、BEM手法、CSSのベストプラクティス、CSSのリファクタリング、CSSのレビュー、CSSを修正、BEMを修正、CSSをBEM化
BEMとは?
BEMはBlock Element Modifierの略です。フロントエンド開発で、再利用可能なコンポーネントとコード共有を実現するための手法です。
| パターン | 構文 | 例 |
|---|---|---|
| ブロック | .block | .card |
| エレメント | .block__element | .card__title |
| ブロック修飾子 | .block--modifier | .card--elevated |
| エレメント修飾子 | .block__element--modifier | .card__title--large |
| 複数単語の名前 | .block-name | .user-profile |
命名規則
- ほかの開発と同様に、意図が伝わる名前が重要です。
- BEMでは、名前で伝える意図は適用されるスタイルや見た目ではなく、インターフェース上の目的に基づきます。
- 修飾子(small、large、paddedなど)を除き、特定のスタイルを表す名前は通常、適切ではありません。
- 特定のワークフローに基づく命名は、場合によっては許容されます(曜日を含むカレンダーなど)。
- 共通するワークフローの種類に基づく命名が適切です(form、table、card、buttonなど)。
- より広いUIの抽象概念に基づく命名は必ずしも必要ではありませんが、コンテキストが不要な抽象的なケース(primary、largeなど)では使用できます。
- 目的が明確に伝わるほど具体的でありながら、該当する場合には再利用できるほど汎用的な名前にしてください。再利用が常に可能、または望ましいとは限らないため、無理に汎用化しないでください。
- 解釈の余地がなく、明示的な名前を使うようにしてください。特に修飾子では、この点を考慮する必要があります。
- 修飾子には明示的な
&の使用を組み合わせ、フラットなBEMクラスを使用してください。 - DOM構造はCSSクラス構造に従う必要はありません。
プロジェクトの制約やその他の理由により、これらのガイドラインに従えない場合は、チャットの出力で逸脱の理由を記載してください。
基本構文
✅ GOOD(このようにしてください)
.block {
.block__element {
&.block__element--modifier { }
}
&.block--modifier { }
}
<div class="block">
<div class="block__element">...</div>
<div class="block__element block__element--modifier">...</div>
</div>
<div class="block block--modifier">
<div class="block__element">...</div>
<div class="block__element">...</div>
</div>
🚫 BAD(このようにはしないでください)
.block {
.block--modifier { } /* Use `&` before all Modifier class names */
}
.block_element { /* Use `__` between Blocks and Elements and nest Element within the Block */
&.block__element-modifier { } /* Use `--` between the Modifier and its Element */
}
<div class="block">...</div>
<div class="block__element">...</div>
<div class="block__element--modifier">...</div>
</div>
<div class="block__element">
<div class="block__element">...</div>
</div>
ルールの概要
- すべてのクラス名は、完全かつ明示的なBEM形式でなければなりません。整理のためのネストは許可されますが、セレクターでタグ名やIDに依存してはいけません。
&は、完全なセレクターへのテキスト上の参照としてのみ使用できます。&を使ってクラス名を構成してはいけません(&--、&__)。- ネストは整理のためだけに使用します。明示的なBEMクラス名が必要です。必要に応じて、ブロック内のエレメントにスコープを限定するために、ネストしたセレクターを使用できます。
- セレクターを明示的なままにしつつ、ブロックまたはエレメントと修飾子を近くに記述するために、
&を使用できます。
✅ GOOD(このようにしてください)
.card {
&.card--featured {}
&.card--compact {}
&.card--featured {
&.card--compact {}
}
}
🚫 BAD(このようにはしないでください)
.card {
&--featured {}
&__title {}
&__title--large {}
}
ブロック
それ自体で意味を持つ独立したエンティティをカプセル化します。ブロックはネストしたり相互に作用したりできますが、意味的には対等であり、優先順位や階層はありません。コントローラーやモデルなど、DOM表現を持たない全体的なエンティティもブロックにできます。
命名:
ブロック名には、小文字のラテン文字、数字、ハイフンを使用できます。CSSクラスを作成するには、名前空間を指定する短いプレフィックスを追加します:.block。長いブロック名に含まれるスペースはハイフンに置き換えます。
HTML:
クラス名を受け入れるDOMノードであれば、どれもブロックにできます。
✅ GOOD(このようにしてください)
<div class="card">...</div>
<div class="button">...</div>
<div class="menu">...</div>
<div class="header">...</div>
<div class="search-form">...</div>
<div class="user-profile">...</div>
<div class="modal">...</div>
<div class="navigation">...</div>
<div class="dropdown-menu">...</div>
🚫 BAD(このようにはしないでください)
<div class="searchForm">...</div>
<div class="button_primary">...</div>
<div class="userProfile">...</div>
<div class="dropdown__menu">...</div>
CSS:
クラス名セレクターのみを使用してください。タグ名や ID は使用しないでください。ページ上の他のブロックや要素に依存させないでください。
✅ GOOD(このようにしてください)
.card { }
.button { }
.menu { }
.header { }
.search-form { }
.user-profile { }
.modal { }
.navigation { }
.dropdown-menu { }
🚫 BAD(このようにはしないでください)
.searchForm {}
.button_primary {}
.userProfile {}
.dropdown__menu {} /* Don't use element syntax for blocks */
}
Element
ブロックの一部であり、単独では意味を持ちません。各要素は意味的にそのブロックと結び付いています。
命名:
要素名には、小文字のラテン文字、数字、ハイフン、アンダースコアを使用できます。CSS クラスは、ブロック名の後にアンダースコアを 2 つ付け、さらに要素名を続けて作成します:.block__elem。長い要素名のスペースはハイフンに置き換えます。
HTML:
ブロック内の DOM ノードはどれも要素にできます。同じブロック内では、すべての要素は意味的に等しいものとして扱います。CSS では、その要素を含むブロックの外で使用しないでください。
✅ GOOD(このようにしてください)
<div class='block'>
<div class='block__element'>
<div class='block2'>
<div class='block2__element'>...</div>
</div>
</div>
</div>
🚫 BAD(このようにはしないでください)
<div class='block'>
<div class='block__element'>
<div class='element__element'>...</div>
</div>
</div>
CSS:
CSS では、要素を所属するブロックの内側にネストしてください。構造を DOM の構造と一致させる必要はありません。
✅ GOOD(このようにしてください)
/* Card block with elements */
.card { /* This is the block; elements are inside */
.card__header { }
.card__title { }
.card__body { }
.card__footer { }
.card__image { }
}
/* Menu block with elements */
.menu {
.menu__item { }
.menu__link { }
.menu__icon { }
}
/* Search form block with elements */
.search-form {
.search-form__input { }
.search-form__button { }
.search-form__label { }
}
🚫 BAD(このようにはしないでください)
/* Don't create deeply nested element names */
.menu {
.menu__item { }
.menu__item__link { } /* Improper naming structure */
.menu__item__link__icon { } /* Improper naming structure */
}
Modifier
ブロックまたは要素に付けるフラグです。外観、動作、状態を変更するために使用します。
命名:
修飾子名には、小文字のラテン文字、数字、ハイフン、アンダースコアを使用できます。CSS クラスは、ブロック名または要素名の後にハイフンを 2 つ付けて作成します:.block--modifier、.block__elem--modifier、および .block--color-black(.block--color-red も同様)です。複雑な修飾子名のスペースはハイフンに置き換えます。
次の場合は、独立した要素を作成する代わりに修飾子を使用してください:
- 変更が単純な状態の変更である(例:アクティブ、無効、強調表示)
- 変更が単純な外観の変更である(例:サイズ、色、レイアウト)
- 変更によって、新たな要素を必要とするコンテンツや機能が追加されない
要素にデフォルトの状態と修飾子で表す別の状態がある場合は、基本要素にデフォルトのスタイルを設定し、修飾子が適用されたときにそのスタイルを上書きしてください。デフォルト状態専用の要素を作成したり、このケースに 2 つの修飾子を作成したりしないでください。
🚫 BAD(このようにはしないでください)
.product-card__image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.product-card__placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--op-color-neutral-plus-six) 0%, var(--op-color-neutral-plus-seven) 100%);
}
✅ GOOD(このようにしてください)
.product-card__image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
&.product-card__image--placeholder {
object-fit: unset;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--op-color-neutral-plus-six) 0%, var(--op-color-neutral-plus-seven) 100%);
}
}
HTML:
修飾子は、ブロックまたは要素の DOM ノードに追加する追加のクラス名です。修飾子クラスは、変更対象のブロックまたは要素にのみ追加し、元のクラスも残してください。つまり、修飾子クラスは常に、ベースとなるブロックまたは要素のクラスと併用する必要があります。
✅ GOOD(このようにしてください)
<div class="block block--modifier">...</div>
<div class="block block--size-big block--shadow-yes">...</div>
🚫 BAD(このようにはしないでください)
<div class="block--modifier utility">...</div>
CSS:
✅ GOOD(このようにしてください)
.menu {
.menu__item {
&.menu__item--active { }
}
.menu__link { }
.menu__icon { }
&.menu--padded { }
}
🚫 BAD(このようにはしないでください)
.menu {
.menu__item {
.menu__item--active { } /* No ampersand */
}
.menu__link { }
.menu-link-active { } /* Bad name structure */
.menu__icon { }
.menu__padded { } /* Improper modifier structure; should be using `&` and `--`, not `__` */
}
その他のルール
- クラスのみを使用します(ID は使用しません)
- フラットなクラスとセレクターのみを使用します
- タグに基づくスタイル設定はしません
- DOM の階層に基づくスタイル設定はしません
- 1 つのブロックにつき、概念上の責務は 1 つにします
- 必要に応じて、ブロックの中にブロックを含められます
- 要素は、それが属するブロックの外には存在しません
- 複数の単語からなる名前には kebab-case を使用します:
.user-profile、.dropdown-menu - 要素名では、ブロックと要素の区切りにアンダースコア 2 つ(
__)を使用します - 修飾子名では、ブロックまたは要素と修飾子の区切りにハイフン 2 つ(
--)を使用します - 名前は意味が明確で、説明的かつ意図が伝わるものにします(外観に基づく名前は避けます)
- 広く理解されていない略語は避けます
構文の例
theme: "xmas" および simple: true の修飾子を持ち、input と submit の要素を持つフォームブロックがあるとします。また、フォームが未入力のときに送信を防ぐため、submit 要素には disabled: true の修飾子があります。
✅ GOOD(このようにしてください)
<form class="form form--theme-xmas form--simple">
<input class="form__input" type="text" />
<input
class="form__submit form__submit--disabled"
type="submit" />
</form>
.form {
.form__input { }
.form__submit {
&.form__submit--disabled { }
}
&.form--simple { }
&.form--theme-xmas { }
}
🚫 BAD(このようにはしないでください)
<form class="form form-simple form--theme-xmas ">
<input class="form_input" type="text" />
<input
class="form__submit--disabled"
type="submit" />
</form>
.form {
.form__input { }
.form_submit { /* Use `__` between Block and Element */
.form__submit--disabled { } /* Use `&` before all Modifier class names */
}
&.form-simple { } /* Use `--` between Element and Modifier */
}
&.form--theme-xmas { } /* Must nest Elements and Modifiers within Block */