この命名規則は、少しBEMに似ていますが、単にBEMの設計をカスタマイズしたものではありません。
一番の特長は、Class名とHTML構造をシンクロさせることで、CSSからHTML構造を予測できるという点で、この特長によってスタイリング(CSSをあてる作業)が非常に快適になっています。
(後述の特長:2で紹介)
※ BEM(特にMindBEMding)との比較を軸に紹介していきたいと思います。
完成形
.Parent {}
.Parent-child {}
.Parent-child-grandChild {}
.Parent-child-grandChild.modifier {}
<ul class="UserList">
<li class="UserList-item">
<div class="UserList-item-name">name</div>
<div class="UserList-item-desc">desc</div>
</li>
<li class="UserList-item modifier">
<!-- ... -->
</li>
</ul>
特長
特長1: 記法
- 登場する記号は一つのみで、**親子関係を表すために
-
(ハイフン)**を使います - 複数語は記号を使わずにキャメルケースで書きます
.ParentName-childName
block-name__element-name--modifier
のようにたくさんの記号が登場するMindBEMdingと比べてかなりシンプルなので、見てすぐに理解できます。
記号はプロジェクト内で統一されていれば、好きなものに置き換えられます。
特長2: 「Block->Element」ではなく「Parent->Child->GrandChild->..」
これが最大の特長となります。
パーツ単位で実装していく考えについてはBEMと同じです。
BEMと大きく異なる点は、「子孫はHTMLの構造通りにネスト」していくということです。
BEM | 本規則 | |
---|---|---|
親 | .block |
.Block |
子 | .block__element |
.Parent-child |
孫 | .block__element |
.Parent-child-grandChild |
BEMはBlock
の直下に全ての子孫(Element
)が属しますが、この規則は子は親の下に、孫は子の下に属すような命名をします。
<div class="Parent">
<div class="Parent-child">
<div class="Parent-child-grandChild"></div>
</div>
</div>
これの何が嬉しいのかというと、まずは下記の2つのCSSを見比べてください。
.block {
&__elementA {}
&__elementB {}
&__elementC {}
}
.Parent {
&-childA {
&-childB {}
&-childC {}
}
}
この規則(後者)では、「B
とC
を横に並べたいなら、A
にdisplay: flex;
をつければよい」ということがすぐに分かります。
他にも、「A
にcolor: #AAA
をつけるとB
とC
の文字色にも影響する」ということがすぐに分かります。
一方BEMでは、実際のHTML構造と照らし合わせなければそれが分かりません。
CSSでのスタイリングの多くは、レイアウト系・装飾系、いずれも親子関係を意識しなければいけないものがほとんどなので、この特長はとても便利に働きます。
上記は、「Class名がHTML構造を再現している」という前提のもと成立していますので、このルールは確実に守られなければいけません。
子孫の世代数
子孫の世代数は3つまでを推奨します。
子孫が増えれば名前が長くなってしまうという問題もありますが、
それ以前に、子孫が多すぎる場合は必要以上のタグでラッピングしているか、パーツ化の粒度が大きすぎる可能性があります。
パーツ化の粒度が大きすぎると、親子関係が硬化し、パーツの移動や再利用の際に不便になります。
この制限の重要度はそれほど高くないため、もし面倒であれば省略してもよいと思います。
特長3: Modifierはマルチクラス
Modifierはマルチクラスを使います。
.SubmitButton {}
.SubmitButton.large {}
.SubmitButton.blue {}
<div class="SubmitButton large blue">Button</div>
BEM(↓)に比べ短く読み取りやすいです。
<!-- BEM -->
<div class="SubmitButton SubmitButton--large SubmitButton--blue">Button</div>
Parent
がパスカルケースである理由は、このModifier
との混同を避けるためです。
Modifier
単体にグローバルなスタイルを当てることは避けてください
.bold
という、それ単独でfont-weight: bold;
を持つ汎用的なModifier
を作ったとします。
目先は便利に働くかもしれませんが、ある箇所では文字の太さではなく、border-width: 1px;
をborder-width: 2px;
にするためにこの名前を使いたいかもしれません。
実装規模が大きくなると、グローバルなスタイルはそのように邪魔な存在となります。
ここまでが特長の紹介です。
デメリット: 有名でない
当たり前ですが、BEMやSMACSSのように多くの人が書いてきたルールではありません。
オレオレ設計やフレームワーク全てに言える問題ですが、複数人のプロジェクトで使いたい場合、これを採用することに納得してもらったり、ルールを覚えてもらったりする必要があります。
おわりに
自分は基本的に、(多少気に入らないものでも)人気なものや流行っているものをプロジェクトに使うのが無難で、一緒に開発する人のためになると思っています。
しかしCSSに関しては、現在主流になっている設計が最善だと思えず、これまで色々と模索してきました。
この規則については、色々な開発に使ってきて、特に破綻したということもなく好調なため紹介してみました。
詳細なルールと具体例
↓これ以降は上で書いたルールの列挙と、間違った使い方の例ですので、実際に導入する人以外は読む必要はありません。
Rules
- 親子関係を
-
を用いて表してください- HTMLの親子関係と矛盾しないでください
- 例:
.Parent-child-grandChild
はHTMLでも.Parent-child
を親に持つ必要があります - 例:
.Parent-childA
と.Parent-childB
はHTMLでも必ず兄弟関係にある必要があります
- 親子関係はn世代までです
- 例:
.Parent-foo-bar-baz
のように子孫が増えた場合、別のパーツにできないか、そもそもHTML要素を減らすことができないか検討してください
- 例:
- 複数語をつなげる場合はlowerCamelCaseを使ってください
- 例:
.Parent_name-child-name
のように複数語の繋ぎに-
や_
を使ってはいけません
- 例:
- 部分的に違うスタイルをあてるためのmodifierはマルチクラスにしてください
- 例:
.SubmitButton.large.blue
のように複数のmodifierをつけることができます - 例:
.large { font-size: 20px; }
のように、modifier単体にスタイルをあてないでください
- 例:
間違った例
この規則が、単なるBEMの記号違いだと認識されてしまうと、以下のような間違いを生みます。
<ul class="UserList">
<li class="UserList-item">
<div class="UserList-name">name</div>
<div class="UserList-desc">desc</div>
</li>
</ul>
.UserList-name
は.UserList-item
の子供なので、.UserList-item-name
としてください。(descも同様)
<ul class="UserList">
<li>
<div class="UserList-item-name">name</div>
<div class="UserList-item-desc">desc</div>
</li>
</ul>
nameとdescは、.UserList-item
を親に持つ必要があります。
もし<li>
に対するスタイルがなくても、必ず.UserList-item
というclass名を付与してください。
<ul class="UserList">
<li class="UserList-item">
<a>
<div class="UserList-item-name">name</div>
<div class="UserList-item-selfIntroduction">self introduction</div>
</a>
</li>
</ul>
.UserList-item-name
の親がaタグになっていますが、.UserList-item-name
の親は.UserList-item
である必要があります。