BEMという命名規則とSass 3.3の新しい記法

BEMを使った命名がとても明快で、このところHTMLやCSSを書くのによく使っている。CSSのクラス名として書く場合は、BEMをCSS用に使いやすくしたMindBEMdingという書き方を採用している。最初にこれを知ったときは「こんな汚い記述の仕方は使いたくない」と思ってたんだけど、すっかり慣れて、今ではその明快さにちょっと心酔しかけているほど。上記の2つの文書はどちらも@junyaさんが日本語に訳してくれている。

BEM-Methodology Definitionsの日本語訳 Summary of MindBEMding - getting your head ‘round BEM syntax

BEMの方法論とMindBEMdingのルールについてはそれぞれの文書を読んでもらうとして、それらをひっくるめて大雑把に説明すると、BEMとはBlockElementModifierの頭文字を取ったもので、構成する要素をそのどれかに当てはめて命名していく方法。どの場合でも必ずBlockもしくはそのModifierがルートにあり、その中に、所属するElementもしくはそのModifierが含まれる構成になる。

  • Block - 構成のルートとなる要素。すべてはここから始まると言っても過言ではない。
  • Element - Blockに所属する子要素。必ずBlockの中にいて単体では生きられない。
  • Modifier - 元となるBlockまたはElementから変化した状態を表す要素。

さらに誤解を恐れずに書くと、BEMはオブジェクト指向に少し似ていてBlockは継承元のクラスもしくはインターフェイス、Modifierはその派生クラス、Elementはそれらのクラスに所属するメソッドもしくはプロパティを連想するとイメージしやすいかも。

MindBEMding

MindBEMdingは、そのBEMをCSSのクラス名に適用するために作られた規則で、CSS界隈でBEMと言った場合はこのMindBEMdingを指すことが多い。Elementをアンダースコア2つ(__)、Modifierをハイフン2つ(--)で連結することでBEMの各要素を表現する。

block
block__element
block__element--modifier
block--modifier
block--modifier__element

この記号の使い方は初めて見ると強烈で人によっては拒絶反応が起きるタイプのもので、前述の元記事でもUuuugly!とディオ並みに叫んでいる。ただ、醜さを我慢して使ってみると、この命名規則のわかりやすさ・使いやすさが実感できると思うのでぜひ試してほしい。BEM(MindBEMding)を使ってHTMLとCSS(SCSS)を書いてみると、例えばこんな感じ。

<div class="block">
    <div class="block__element"></div>
    <div class="block__element--modifier"></div>
</div>
<div class="block--modifier">
    <div class="block--modifier__element"></div>
</div>
.block {
  width: 100px;
}

.block__element {
  width: 20px;
  margin-left: 10px;
  color: blue;
}

.block__element--modifier {
  @extend .block__element;
  color: red;
}

.block--modifier {
  @extend .block;
  margin-top: 20px;
}

.block--modifier__element {
  @extend .block__element;
  background-color: green;
}

自分はマルチクラス方式があまり好みではなく、できるだけCSS側でコントロールしたいというのもあって、上記のようにModifierを書くときはSassの@extendを使ってシングルクラス方式で書いている。けど、CSSプリプロセッサを使ってなかったりマルチクラス方式で書く方が好みであれば、HTML側に寄せて以下のような書き方になる。BEMに関係なく、今現在はこちらの方が主流な書き方な感じはする。ただ、BEMだとかなり冗長になる。

<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>

シングルクラスとマルチクラス

ところで、もしかしたらHTML/CSSにおけるシングルクラスやマルチクラスという呼び方は聞き慣れないかもしれないけど、そのあたりの設計方法についてはこの記事が参考になる。

HTMLのセマンティックとフロントエンド構造について

上の記事の中で、Nicolas Gallagher氏は「CSSプリプロセッサの手助けがあったとしても私はマルチクラスを利用する方がよいと考えている」と、クラスの組み合わせによる柔軟性を理由にマルチクラス設計を推奨している。けれど、これは使う場面によると思っていて、自分の場合はシングルクラスの方が適していることが多い気がしている。理由は後述。

上記以外にも、CSSにおける設計の仕方の話としては以下の記事なども参考になる。

ぼくのかんがえたさいきょうのしーえしゅえしゅ | MOL 大規模サイトにおける本当は怖いCSSの話 Thinking about CSS Architecture 今必要なCSSアーキテクチャ

これは個人的な考えだけど、どちらかと言えばBEMはシングルクラスに適した構造・命名だと思っていて、モジュール組み(さらに詳細な有料記事)などもこの系統に近い。逆に、マルチクラスにはOOCSSSMACSS書籍)などが向いているという印象を持っている。

自分がマルチクラスよりシングルクラスでの設計の方が好みなのは、

  • 序盤の設計時のシンプルさ・容易さ
  • HTML側を見た時の明快さ・編集する時の容易さ
  • HTML側での簡潔なクラス指定によるデザインの崩れにくさ

などが挙げられる。HTML側をシンプルに保つ代わりに、CSS(Sass)側の複雑さが増える。一方、マルチクラスでの設計になると、HTML側が複雑になりやすい代わりに柔軟性が高くなり、その柔軟性の代償としてクラスの組み換えによるデザインの崩れも起きやすくなる。自分がHTML側を明快にしたい理由は、HTMLはCSSに比べて編集する人の数が多いから

また、マルチクラスは最初の設計の段階でコストが掛かりやすく、シングルクラスに比べて設計力を問われる。シングルクラスは初動時のコストは少なくシンプルに保てるが、継続的にうまくコントロールしていかないとのちのちカオスになりやすい。一長一短ある感じではあるけれど、マルチクラス設計はフレームワークや大規模なサイトに、シングルクラス設計はスタートアップや小規模なサイトに向いているかなと思っている。自分は、後者の環境で設計することがほとんどなので、シングルクラスの方が適していると思うことが多い。

BEMの明快さ

それで、シングルクラス設計でCSSを書いていく上で問題になりやすいポイントとしては、その付けられた名前から意味を読み取りづらくなりがちというのがある。BEMのメリットの中でも大きな特長だと思うのは、特にシングルクラス設計での構造・命名に秩序をもたらしてくれることで、BEMを適用するだけでその問題をある程度は解決できるのがうれしい。

例えば、以下のようなCSSのクラス名があったとしたら、ここからどのような構造や状態を想像するだろうか。この名前だけでどこまで読み取れるだろう?

character-avatar-and-name-notice

シングルクラス設計の命名では、1つの名前の中に単語数が多くなりがちで、CSSクラス名として主流のハイフン連結だけでは、名前をつけた本人以外には正確に意味を読み取れないことが多々ある。さらにキャメルケースを使ったり、アンダースコアを使ってわかりやすくしようとする気があるなら、最初からBEMのルールを使ったほうがよりわかりやすくなると思う。BEMには記号の違いだけでなく、ElementModifierという概念があるから。

character__avatar-and-name--notice

BEMを前提にこう書かれてあれば、この名前を見ただけで「characterというブロックに含まれるavatar-and-nameという要素を元とするnoticeというバリエーションの要素」ということが読み取れるようになる。仮にここに変更を加える際にも、「場合によっては元になっている要素のcharacter__avatar-and-nameの方にも影響するかも」ということまで、この名前を初めて見た人にも伝わる。ところが最初の名前では、まず読み取り方からして「character-avatarname-notice」など、人によって複数の読み方ができてしまう。

記事をここまで読んでいるならもう既に、例えば以下の名前からも単語の羅列以上に多くの情報を読み取れるようになっているのではないだろうか。

setting-list__item--active
setting--admin__title-img

少なくとも、この2つがそれぞれ別のグループ(ブロック)に所属している要素ということが読み取れれば、この命名規則の趣旨がつかめていると思う。

BEMは見た目の奇妙さと引き換えに、とても強力な明快さをもたらしてくれる。

このBEMの名前の明快さは、HTMLの構造やCSSの設計を把握してない人が触る場合に特に威力を発揮する。例えばサーバーサイドやJavaScriptのエンジニアが仮にCSSの設計を把握していなくても、とりあえずBEMの命名規則を覚えてもらえればブロック単位で維持すべきだと理解してもらえるので、それだけでデザインを壊してしまうリスクを結構回避できる。また命名した本人であっても、半年経ってから見たらBEMの名前はわかりやすく見えそう。

上の例ではそもそもの名前の付け方が下手だという指摘もありそうだけど、誰にでも伝わる良い名前を付けるというのはとても大変なことで、できるだけその労力を減らしたいと常々思っていて、今回のBEMの命名規則はその部分を大きく軽減・改善してくれるものだった。BEMの利点はこれだけではないけれど、一番気に入っているところを挙げるならこの部分。

Sass 3.3の新しい記法

現在RC1で正式版のリリースが近いSass 3.3では、BEMで記述するのに適した新しい記法が導入される予定。前述のSCSSでの記述例を、新しい記法で書くとこういう感じになる。

Sass 3.3正式版では、RC1の記法から変更されたので詳しくはドキュメント等を確認してください。以下で紹介している記法は最新版のSassでは動きません。

.block {
  width: 100px;

  @at-root {
    #{&}__element {
      width: 20px;
      margin-left: 10px;
      color: blue;
    }

    #{&}__element--modifier {
      @extend .block__element;
      color: red;
    }

    #{&}--modifier {
      @extend .block;
      margin-top: 20px;
    }

    #{&}--modifier__element {
      @extend .block__element;
      background-color: green;
    }
  }
}

親セレクタを&で表すことは今までも出来ていたけど、それとインターポレーション#{}を組み合わせてクラス名の表現(生成)に使えるようになった。

また、ブロック直下で@at-rootディレクティブを使って囲んでおくと、デフォルトではそのブロックでネストしないようになるので、記述上はネストしてグルーピングしたいけど、詳細度を上げないためにブロックのセレクタを追加したくないということが実現できる。BEMではどの名前も一意なのが確実なので、ネストして詳細度を上げる意味はあまりない。

出力結果のCSSは以下のようになる。

.block, .block--modifier {
  width: 100px;
}

.block__element, .block__element--modifier, .block--modifier__element {
  width: 20px;
  margin-left: 10px;
  color: blue;
}

.block__element--modifier {
  color: red;
}

.block--modifier {
  margin-top: 20px;
}

.block--modifier__element {
  background-color: green;
}

前述のSCSSで改善したいのは、@extendでブロック名の部分をインターポレーションで表現できずに直接書いている点。調べた範囲では適切な書き方がわからなかった。

#{&}__element--modifier {
  @at-root { @extend #{&}__element; }
}

と書けばいけるかなと思ったけど無理だった。新記法での@extendの書き方を募集中。

実際に、自分のペライチサイトでこのSass 3.3の新記法を使ってCSSを書いたりもしてみたけど、ベタ書きするのと比べて今のところこの記法にメリットをあまり感じられていない。前述の@extendでうまく使えてなかったり、エディタの補完が使えなかったり、一括置換しづらく感じたりと、むしろデメリットのほうが目立っている感もあるんだけど、わざわざ導入されるからには何かしらの良さがあるはずなので、今後も調査・検証するつもり。


追伸、先程のペライチサイトのCSSは、ブロック数も少ないので1つのSassファイルに全部書いているけど、ページ数の多いWebサービスなどでは、ブロック単位でSassファイルを分けるようにしている。こうしておくと見通しが良くなるし、ファイル名=ブロック名になるので、数が増えた時にうっかりブロック名を重複させてしまうミスを防止できそう。

結局のところ、BEMがどうこうというよりも、より壊れにくいCSSの書き方を求めていて、BEMの書き方は今のところそれに最も合致していたということかもしれない。CSSはとても脆いので恐る恐る触るくらいがちょうどいい。百鬼夜行していいのは妖怪だけ。

そんな感じで、まだ使いながら試行錯誤している部分もありつつではあるけど、現時点では大局的に見て、SassなどのCSSプリプロセッサを使っているならば、BEMという命名規則は使う価値のあるものだと思う。最近だとTogetterでこのようなやり取りがまとめられていたけど、確かに実際に書いてみるとどう命名すれば良いか迷う場面は出てくるし、書き方が冗長だと感じる場面も多々ある。ただ、そういうのもある程度の慣れと割り切り、そしてCSSプリプロセッサの機能で回避できそうな感触はなきにしもあらず。

最後に、本文の中で紹介できなかったBEMに関して参考になるページをまとめてこの記事の終わりとしたい。早くBEM人間になりたい。