BEM方法論の紹介
公開: 2022-03-11BEM方法論とは何ですか?
小さなWebサイトを構築する場合、通常、スタイルをどのように整理するかは大きな問題ではありません。 通常のファイルを作成し、必要なCSSをすべて作成すれば、それだけです。 ただし、より大規模で複雑なプロジェクトになると、コードをどのように編成するかが重要になります。 複数のフロントエンド開発者とバックエンド開発者で構成されるチームで作業している場合は、コードの構造がさらに重要になります。
今日、CSSコードを削減し、CSSコードをより保守しやすくすることを目的とした方法論はたくさんあります。 この記事では、そのうちの1つであるBEMについて説明し、いくつか例を示します。 BEMは、 B lock E lementModifierの略です。 その背後にある主なアイデアは、開発プロセスをスピードアップし、CSSクラスを独立したモジュールに配置することで開発者のチームワークを容易にすることです。 header__form--search
のようなクラス名を見たことがあれば、それがBEMの動作です。 はい、クラスには非常に長い名前を付けることができますが、すべて読みやすく、理解しやすいものです。
ベストプラクティスは、IDではなくクラスでのみBEMを使用することです。これは、クラスを使用すると、必要に応じて名前を繰り返し、より一貫性のあるコーディング構造を作成できるためです。 また、Webサイトを整理されたモジュールに分割する場合は、ブロック、要素、修飾子という同じ構造で構成する必要があります。 各ブロックが複数の要素を持つことができ、ブロックと要素の両方が複数の修飾子を持つことができる場合。 ただし、最初に基本的なBEM構造から始めて、例を挙げて説明しましょう。
ブロック
ブロックは、Webサイト内のオブジェクトを表します。 これは、コードのより大きな構造チャンクと考えてください。 今日のすべてのWebサイトで最も一般的なブロックは、ヘッダー、コンテンツ、サイドバー、フッター、および検索です。 BEMのブロックは、常にCSSクラスをチェーンするための開始点です。 いくつかのブロックの例を見てください。
- コンテンツ
- メニュー
- 検索フォーム
.content {/* Styles */} .menu {/* Styles */} .search {/* Styles */}
エレメント
要素は、特定の機能を実行するブロック内のコンポーネントです。 それはそのブロックの文脈でのみ意味をなすはずです:
- コンテンツ記事
- メニュー項目
- 検索入力フィールド
.content__article {/* Styles */} .menu__item {/* Styles */} .search__input {/* Styles */}
修飾子
モディファイアは、ブロックのバリエーションを表す方法です。 Bootstrapを使用したことがある場合、最良の例はボタンのサイズです。 ボタンのサイズは、ボタン自体のサイズのバリエーションであり、修飾子になります。
- コンテンツ特集記事
- メニューリンク
- アイコンの有無にかかわらず検索フィールド
.content__article--featured {/* Styles */} .menu__item--link {/* Styles */} .search__input--icon {/* Styles */}
命名規則
BEM方法論の主な目的は、CSSセレクターの名前をできるだけ有益で透過的にすることです。 元のBEMスタイルは次のように定義されます。
ブロック名は通常、 .header
のような単一の単語ですが、ブロック定義が長い場合は、単一のハイフンで分割されます-
:
.lang-switcher {/* Styles */}
要素名は二重下線で始まります__
:
.lang-switcher__flag {/* Styles */}
修飾子名は単一の下線で始まります_
:
.lang-switcher__flag_basic {/* Styles */}
BEM方法論には、非常に重要なルールが1つだけあります。修飾子は、その所有者のコンテキスト外では使用できません。
例:
.btn_big {/* Styles */}
btn_big
は、ヘッダーも定義されている場合にのみ使用できます。
悪い例:
<div class=”btn_big”>...</div>
良い手本:
<div class=”btn btn_big”>...</div>
これらの元のBEMスタイルに加えて、ハリーロバーツやキャメルケーススタイルのような代替の命名スキームがあります。
ハリーロバーツスタイルの例:
.block-name__element-name--modifier-name {/* Styles */}
キャメルケーススタイルの例:
.BlockName__ElementName_ModifierName {/* Styles */}
他にもいくつかありますが、これら2つが最も一般的なものです。 個人的に、私はハリス・ロバーツによって提案された命名規則のファンです。これには次の規則があります。
- 名前は小文字で書かれています
- BEMエンティティの名前内の単語はハイフンで区切られます
-
- 要素名とブロック名は二重下線で区切られます
__
- ブール修飾子はダブルハイフンで区切られます
--
- Key-Value型修飾子は使用されません
この命名規則が他の命名規則よりもはるかによく形成されている理由は、修飾子要素を他の要素と簡単に区別できるためです。 元の命名規則では、修飾子は次のように定義されます。
.block__element_modifier {/* Styles */}
ただし、ご覧のとおり、シングルアンダースコアとダブルアンダースコアの間に大きな違いはありません。 一方、ダブルハイフンは明確な分離を提供し、修飾子をすぐに確認できます。
.block__element--modifier {/* Styles */}
さまざまな形式のBEMの例
CSSの他に、BEMは、JSON、XML、ツリーファイル、またはネストをサポートする任意の形式の整理にも非常に役立ちます。 BEM方法論は、UIを構築するための優れた方法と考えてください。
BEM形式で構造化された次のHTMLについて考えてみましょう。
<header class=”header”> <img class=”header__logo”> <form class=”header__search-from”> <input class=”header__search-from__input” type=”input”> <button class=”header__search-from__button” type=”button”> </form> <div class=”header__lang-switcher”></div> </header>
同じことは、JSONおよびXML形式を使用して実現できます。
XML:
<block:header> <block:logo/> <block:search-from> <block:input/> <block:button/> </block> <block:lang-switcher/> </block>
JSON:
{ block: 'header', content: [ { block: 'logo' }, { block: 'search-form', content: [ { block: 'input' }, { block: 'button' } ] }, { block: 'lang-switcher' } ] }
BEMプロジェクトのファイルシステム編成
BEMでは、ファイルを正しい方法で整理することが重要です。 BEMは、CSSクラスの優れた編成を提供し、それらを完全に理解できるようにするだけでなく、非常に保守しやすいファイル構造も提供します。 SASSファイルでBEMファイル編成手法を使用したプロジェクトの例を見てみましょう。
blocks/ input/ __box/ --big/ input__box--big.scss input__box.scss button/ --big/ button--big.scss
上記のように、メインフォルダー内のサブフォルダー構造を確認するだけで、すべてが明確で整理されています。 このように、同じパターンに従うのは非常に簡単なので、誰があなたの後に働いているのか、あなたが誰かの後に働いているのかは関係ありません。
BEMプロジェクトをプラットフォームに分割
BEM方法論の手法を使用してファイルを整理するだけでなく、より具体的なことにも取り組むことができます。 たとえば、完全にレスポンシブになるWebプロジェクトを構築していて、クライアントがモバイルの一部のブロックがデスクトップデバイスとはまったく異なることを指定した場合、BEMフォルダー構造をプラットフォームに分割するのが最適です。 さまざまなプラットフォームでボタンを整理する例:
common.blocks/ button/ button.scss desktop.blocks/ button/ buttons.scss mobile.blocks/ button/ button.scss
これは、BEM方法論を使用してプロジェクト全体を整理する場合の単なる例であることに注意してください。 BEMを正しく使用するには、BEM構造のファイルツリーは必須ではありません。プロジェクトの一部のセグメントでのみBEMを使用できます。 これまでのところ、すべての要素と修飾子にファイルが作成される、この厳密なBEMファイル構造構成を使用していません。 代わりに、要素と修飾子の宣言があるブロックのファイル構造を作成しているだけです。
実際のBEM
これで命名規則に精通しているので、実際にBEM方法論を示します。 このHTMLコードが動作しているとしましょう。
<a class=”btn btn--big btn--primary-color” href=”#” title=”Title”> <span class=”btn__price”>$3.99</span> <span class=”btn__text”>Product</span> </a>
次のCSSマークアップを適用した場合:
.btn__price {/* Styles */} .btn__text {/* Styles */} .btn--big {/* Styles */} .btn--primary-color {/* Styles */}
さて、誤解しないでください。 これまでの例では、ほとんどの場合、ブロック、要素、および修飾子がありましたが、必ずしもそうである必要はありません。
たとえば、 personという名前のブロックがあるとします。 人には足と手があり、女性でも男性でもかまいません。 右手で男性を定義する場合は、次のようになります。
.person--male__hand--right {/* Styles */}
これで、BEMの本当の意味を確認できます。 修飾子が性別である人を定義しました。 男性でも女性でも構いませんので、手があり、手が要素です。 また、各人は右手または左手を持つことができます。これも修飾子です。
別のケースでは、片手で一般人を定義したい場合は、次のようにします。
.person__hand {/* Styles */}
お気づきのように、BEMに慣れれば、CSSとHTMLの構造を簡単に構築できます。
CSSプリプロセッサでのBEMの使用
個人的には、CSSプリプロセッサの1つを使用せずに新しいプロジェクトを開始することは想像できません。 ご存知のように、プリプロセッサは素晴らしいものであり、多くの利点を提供してくれます。そして最も重要なことは、プリプロセッサがBEM方法論と完全に一致していることです。
次の例では、SASSと組み合わせたBEMの最も一般的な例を見ることができます。
.person { &__hand {/* Styles */} &__leg {/* Styles */} &--male { /* Styles */ &__hand { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } &__leg { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } } &--female { /* Styles */ &__hand { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } &__leg { /* Styles */ &--left {/* Styles */} &--right {/* Styles */} } } }
SASSコードは次のCSSにコンパイルされます。

.person__hand {/* Styles */} .person__leg {/* Styles */} .person--male {/* Styles */} .person--male__hand {/* Styles */} .person--male__hand--left {/* Styles */} .person--male__hand--right {/* Styles */} .person--male__leg {/* Styles */} .person--male__leg--left {/* Styles */} .person--male__leg--right {/* Styles */} .person--female {/* Styles */} .person--female__hand {/* Styles */} .person--female__hand--left {/* Styles */} .person--female__hand--right {/* Styles */} .person--female__leg {/* Styles */} .person--female__leg--left {/* Styles */} .person--female__leg--right {/* Styles */}
さらに詳しく知りたい場合は、BEM用の便利なSASSミックスインを使用できます。
/// Block Element /// @param {String} $element - Element's name @mixin element($element) { &__#{$element} { @content; } } /// Block Modifier /// @param {String} $modifier - Modifier's name @mixin modifier($modifier) { &--#{$modifier} { @content; } }
そして、あなたはそれをこのように使うことができます:
.person { @include element('hand') {/* Person hand */} @include element('leg') {/* Person leg */} @include modifier('male') { /* Person male */ @include element('hand') { /* Person male hand */ @include modifier('left') { /* Person male left hand */ } @include modifier('right') { /* Person male right hand */ } } } }
これにより、次のCSS出力が生成されます。
.person__hand { /* Person hand */ } .person__leg { /* Person leg */ } .person--male { /* Person male */ } .person--male__hand { /* Person male hand */ } .person--male__hand--left { /* Person male left hand */ } .person--male__hand--right { /* Person male right hand */ }
おそらくこれほど長いユースケースはないでしょうが、これはBEMがどのように使用されているか、そして小規模プロジェクトと大規模プロジェクトの両方でBEMが非常に強力である理由の良い例です。
BEMプロジェクトの開始
公式のBEMドキュメントで説明されているように、新しいBEMプロジェクトを開始する最も簡単な方法は、既存のGITリポジトリを使用することです。 Gitcloneコマンドを使用するだけです。
$ git clone https://github.com/bem/project-stub.git
次に、新しく作成されたディレクトリに移動し、すべての依存関係をインストールします。
$ npm install
必要なすべての依存関係がインストールされます。
ENBを使用してプロジェクトをビルドします。
$ node_modules/.bin/enb make
開発用のサーバーモードを実行します。
$ node_modules/.bin/enb server
その結果、次のメッセージが表示されます。
Server started at 0.0.0.0:8080
これは、サーバーが稼働していることを意味します。 これで、このアドレスで結果を確認できます。
http://localhost:8080/desktop.bundles/index/index.html
ご覧のとおり、ここにあるbemjson
ファイル内に定義されている要素がすでに作成されています。
project-stub/desktop.bundles/index/index.bemjson.js
localhost index.html
ファイルに表示される、すべてのHTMLを生成しているファイルの現在の構造を確認および調査できます。 このファイルを変更して、前の章で説明した「Person」BEMプロジェクトを取得します。 index.bemjson.js
ファイルからコード全体を削除(またはコメント)して、次のコードに置き換えることができます。
module.exports = { block: 'page', title: 'Person BEM', favicon : '/favicon.ico', head : [ { elem : 'meta', attrs : { name : 'description', content : '' } }, { elem : 'meta', attrs : { name : 'viewport', content : 'width=device-width, initial-scale=1' } }, { elem : 'css', url : 'index.min.css' } ], scripts: [{ elem : 'js', url : 'index.min.js' }], content: [ { block: 'person', content: [ { elem: 'male', content: [ { elem: 'leg', mods: {side: 'left'}, content: 'Male person leg -- left' }, { elem: 'leg', mods: {side: 'right'}, content: 'Male person leg -- right' }, { elem: 'hand', mods: {side: 'left'}, content: 'Male person hand -- left' }, { elem: 'hand', mods: {side: 'right'}, content: 'Male person hand -- right' } ] }, { elem: 'female', content: [ { elem: 'leg', mods: {side: 'left'}, content: 'Female person leg -- left' }, { elem: 'leg', mods: {side: 'right'}, content: 'Female person leg -- right' }, { elem: 'hand', mods: {side: 'left'}, content: 'Female person hand -- left' }, { elem: 'hand', mods: {side: 'right'}, content: 'Female person hand -- right' } ] }, ] } ] };
これで、次のHTMLが生成されます。
<div class="person"> <div class="person__male"> <div class="person__leg person__leg_side_left"> Male person leg -- left </div> <div class="person__leg person__leg_side_right"> Male person leg -- right </div> <div class="person__hand person__hand_side_left"> Male person hand -- left </div> <div class="person__hand person__hand_side_right"> Male person hand -- right </div> </div> <div class="person__female"> <div class="person__leg person__leg_side_left"> Female person leg -- left </div> <div class="person__leg person__leg_side_right"> Female person leg -- right </div> <div class="person__hand person__hand_side_left"> Female person hand -- left </div> <div class="person__hand person__hand_side_right"> Female person hand -- right </div> </div> </div>
上記のコードからわかるように、このシナリオでは、BEMから提供されたデフォルト設定を使用しているため、デフォルトのBEMコーディングスキームが使用されました。 新しいページやブロックの作成、BEM HTMLの変更など、探索して使用できるコマンドやオプションは他にもたくさんあります。 これについてはあまり深く掘り下げません。すべて、公式のBEMドキュメントに記載されています。
利点と懸念
利点
- BEMはメンテナンスに最適です。 大規模なプロジェクトで誰かを追いかけなければならなかったことが何回ありますか?そして、何か未知のものが崩壊することなく何かを変えることを恐れすぎていますか? BEMを使用する場合、要素の正確な目的と、要素が表示される可能性のあるブロックを知っています。
- クラス名は論理的で直感的であり、チームのすべてのメンバーはその要素がWebサイトで何をするかを知っています。 BEMは、プロジェクトの全員に共有できる宣言型構文を提供するため、同じページに表示されます。
- BEMは、ネストされたCSSセレクターを排除します。 すべてのHTML要素には独自のCSSクラスがあり、その名前から、その目的がわかります。 それらすべてを支配する1つのセレクター。
懸念事項とよくある間違い
- 入れ子に深く入りすぎないでください。 主なルールは、親と子の2つ以上のレベルを使用しないことです。
- ブロックスコープを開始する場所に注意してください。 ここでよくある間違いは、開発者がブロックを使用している場合ですが、開発の後半の時点で、同じブロックにメインの親ブロックがあり、ネストによってルールが破られる可能性があることに気づいていません。
- SASS@extendは避けてください。 これについてハリー・ロバーツを引用するには:
Sassでクラスを「結び付け」ないことで、ビューでより多くの組み合わせを作成できます。 HTMLには、すべてのクラスがDOMの一部に作用しているのを見ることができるという点ではるかに優れた紙の証跡があります。 新しいUIを作成するたびに、新しいプレースホルダークラス(またはそれらを組み合わせたマニフェストクラス)を作成する必要がないという点で、CSSははるかにスリムなままです。
結論
BEMコーディングスキームを初めて見たとき、最初に考えたのは次のとおりです。
これらのクラスは長すぎて読み書きできません。
でも、やってみたら、使わずに新しいプロジェクトを始めるなんて想像もできません。 私にとって、BEMはコードの保守性を大幅に向上させました。そして、BEMベースのプロジェクトに「投げ込まれる」すべての開発者は、コード構造全体に非常に迅速に追いつくと確信しています。
それにもかかわらず、BEMについてはソーシャルネットワークで多くの議論があります。 BEMは良くないと言う人もいますが、デフォルトのHTMLネスト要素を使用するのではなく、なぜこのような長い名前のクラスを作成する必要があるのか疑問に思っています。 そうですね、BEMが好きだと言う人は誰もいませんが、実際には、フロントエンド開発者の大多数がBEMを採用しており、非常に便利だと感じています。