+ ここで紹介している方法は、一部Sassの使用を前提としています。
+ ここでいうBEMは命名規則や概念としてのBEMであり、Yandex社が開発しているBEMツールについては言及しません。
BEMは素晴らしいアイデアであり、SMACSSもまた素晴らしいガイドラインです。
これらの特徴を組み合わせて最高のCSS設計を構築したい、と思った私はさまざまな方法でこの2つの融合を試みましたが、失敗の連続でした。
しかしながら、ようやくいくつかの結論を導けるようになってきました。
今回はそんないくつかの方法論の内、 BEMの命名ルールをそのまま生かしつつ、最もシンプルにSMACSSと融合させる方法 を紹介したいと思います。
実は、SMACSSとBEMをそのまま組み合わせることはできません。
お互いのルール同士が衝突するからです。
とくに注意したい部分は、CSSのカテゴライズだといえるでしょう。
SMACSSではCSSを主要な6つのカテゴリに分類します。
ベース、レイアウト、モジュール、サブモジュール、ステート、テーマです。(※サブモジュールに関しては他のカテゴリと比べるとあまり言及されていませんが、これはOOCSSのスキンやBEMのModifierにも近い概念であり、私は他のカテゴリと同様重要視すべき要素だと考えています。)
対して、BEMではこれをBlock,Element,Modifierの3つの定義だけで説明しようとしています。
これらをそのまま組み合わせてしまうと、当然衝突が起こるのです。
だからこれらが衝突しないよう、アレンジを加える必要があります。
それはどうすればいいのか?
その方法はいたってシンプルで、 BEMに足りない要素のみをSMACSSから引っ張ってきて、足すだけ です。
BEMを前提に考えると、Webページ上における要素は大抵Block,Element,Modifierのいずれかで説明がつきます。
ではBEMに足りない要素とは何かというと、もっと抽象的なもの、つまりSMACSSでいうところの「ベース」です。これに相当するものがBEMにはありません。
そこで、このアイデアをSMACSSから引っ張ってきます。
また、SMACSSを隅々まで読むと、ディレクトリ構成の説明でこのようなファイルの存在に気が付きます。
- site-settings.scss
- mixins.scss
SMACSSはこれらについてはあまり言及していませんが、site-settingsはCSS全体で使うカラーコードなどの変数、mixinsは@mixin関数をまとめたものだと思われます。
これらもBEMには足りない要素なので追加します。
その他のレイアウトやモジュールに関しては、BEMの概念で事足りる(というか、残しておくと衝突する)ので排除します。
すると、最終的なCSS(SASS)の分類は以下の6つになります。
- Setting
- Mixin
- Base
- Block
- Element
- Modifier
##ディレクトリ構造
先ほど分類したCSSのカテゴライズを元に考えると、ディレクトリ構造は以下のようになります。
- _site-settings.scss
- _mixins.scss
- _base.scss
- blocks/
__icon.scss
_button.scss
_heading.scss
_media.scss
_form.scss
_article_list.scss
_panel.scss
_site-header.scss
_site-footer.scss
... - main.scss
そして、SMACSSのやり方に則って、これらのファイルはmain.scssに@importさせて1つに統合します。
ちなみに、BEMではBlock,Element,Modifierごとにファイルを分けたり、cssやjsファイルを同じディレクトリに収納するやり方もあります。
しかしながら、今回はSMACSSに寄せつつ、ファイルはBlock単位で分け、ElementとModifierも同じファイルに記述する方法を採用します。
これだけでも十分機能しますが、もしヘルパークラスを使いたい場合はここに_helper.scssを足しても問題ありません。
##bodyにクラスを付与して何らかの操作を行いたい場合
bodyにクラスを振りたいシーンがあるかもしれません。
たとえば通常のSMACSSなら、bodyにレイアウトやテーマのクラスを振ってサイト全体の見た目を変えるというテクニックもあります。
しかし今回のアプローチではレイアウトの概念もテーマの概念も排除しています。
その状態でこれらにどう対処するかというと、ページ全体を1つのBlockと考えることで対応することができます。
<body class="page">
...
</body>
bodyに.page
というクラスを振り、1つのBlockと捉えれば、この問題は解決できます。
サイト全体のレイアウトやテーマを操作したい場合は、ここにModifierクラスを付与します。
レイアウトやテーマをModifierと考える事で、BEMだけで解決することができます。
<body class="page page_layout_column2">
...
</body>
<body class="page page_theme_summer">
...
</body>
##ステートのクラス
この方法ではSMACSSのステートの概念を排除しているため、これもModifierで表します。
ボタン要素を例にマークアップすると、以下のようになります。
<a class="button button_state_disable" href=""></a>
これはあくまで一例であり、クラス名は例えば.button_is_disable
などであってもかまいません。
##JSのフック
JSのフックにはSMACSSのアイデアを採用します。
基本的にはidを使用するものとし、クラスの場合はプレフィックス.js-
をつけます。
##命名のルールの変更について
一部の開発者は、BEMの命名ルールをMindBEMdingのようにアレンジしたいと思うかもしれません。
その点に関しては自由にして頂いて構いませんが、注意が必要です。
なぜならそれらのアレンジには、SMACSSのルールが混在している場合があるからです。
例えばSUIT CSSが採用している命名ルールでは、BEMを主体にはしているものの.is
から始まるステートクラスが採用されています。
ルールを足したり引くことは比較的容易ですが、 異なるルール同士の帳尻を合わせることは難易度が高いです。
もしアレンジするとすれば、私なら以下の様な変更程度に留めます。
.Block-name__Element-name--Modifier-name {...}
##この方法のメリット
BEMとSMACSSを融合させる方法は他にもいろいろありますが、 この方法の最大のメリットはBEMとSMACSSの知識だけで事足りる という学習コストの低さにあります。
もっともこの2つに関しては熟知している必要がありますが、どのような方法を用いるにしてもBEMやSMACSSの知識は必要になりますし、他の厳格なガイドラインなどに頼るよりは楽に導入できるはずです。
また、やっていることはBEMとSMACSS内にある既存のルールを足したり引いたりしているだけなので、容易に理解できるでしょう。