始めに
皆さんはCSSはBEMで書いていますでしょうか?僕は基本的にBEMを使っていて、Elementは1つのみに徹底して書いてきました。ただこの運用にするとあんまりに辛いなと思ってきてElementにElementを書いてもいいんじゃないかと思ってきました。
理想のBEM構成にした時の問題
例えばTODOリストをコーディングするときに、Blockとしてはリストとアイテムは分けておくと柔軟性が良くなるので以下のようにしておくのがベストです。リスト側でアイテム間のマージンを設定しておくと、アイテムだけのパーツは他の場所でも使いまわしやすくなります。
オンラインエディタで書いたものはこちらになります。
See the Pen Element2階層のBEMサンプル by wintyo (@wintyo) on CodePen.
//- リストのBEM
ul.todo-list
//- アイテムごとのマージンをここで書く)
li.todo-list__item
//- アイテムのBEM(ここではマージンをかかない)
.todo-item
input.todo-item__check(type="checkbox")
span.todo-item__text TODO
button.todo-item__button 削除
li.todo-list__item
.todo-item
input.todo-item__check(type="checkbox")
span.todo-item__text TODO2
button.todo-item__button 削除
li.todo-list__item
.todo-item
input.todo-item__check(type="checkbox")
span.todo-item__text TODO3
button.todo-item__button 削除
// TODOリストのリスト部分のみ
.todo-list {
padding: 0;
&__item {
& + & {
margin-top: 10px;
}
}
}
// TODOリストの中身のみ
.todo-item {
display: flex;
align-items: center;
width: 100%;
padding: 10px;
border: solid 1px #ddd;
border-radius: 5px;
&__text {
flex: 1 1 0;
padding: 0 5px;
}
}
ただこの運用は明らかに冗長で、まとめてひとつのBlockにしたいときもあります。その場合、以下のように書いてしまうことがあります。
ul.todo-list
li.todo-list__item
//- アイテムElementの後ろに名前を足して配下感を出す
input.todo-list__item-check(type="checkbox")
span.todo-list__item-text TODO
button.todo-list__item-button 削除
li.todo-list__item
input.todo-list__item-check(type="checkbox")
span.todo-list__item-text TODO2
button.todo-list__item-button 削除
li.todo-list__item
input.todo-list__item-check(type="checkbox")
span.todo-list__item-text TODO3
button.todo-list__item-button 削除
.todo-list {
padding: 0;
&__item {
display: flex;
align-items: center;
width: 100%;
padding: 10px;
border: solid 1px #ddd;
border-radius: 5px;
& + & {
margin-top: 10px;
}
// itemエレメント以下で使っている感じを出す
&-text {
flex: 1 1 0;
padding: 0 5px;
}
}
}
一応SCSSの階層関係を見るとElementの下に更に書かれそうだなという雰囲気は出てますが、単純に単語を連結したいのかの判断が難しくなります。
Elementの中にElementを書くのを許容して明記させる
これを書くくらいだったらもう__
をもう一つ増やしてElementの下に更にElementをはやしていることが分かるようにした方がいいかなと思いました。3つは流石にキツいのでブロックを分けましょう。
ul.todo-list
li.todo-list__item
//- アイテムElementの下で使うクラス名だと一目瞭然(もし違った書き方をしていたら指摘しやすい)
input.todo-list__item__check(type="checkbox")
span.todo-list__item__text TODO
button.todo-list__item__button 削除
li.todo-list__item
input.todo-list__item__check(type="checkbox")
span.todo-list__item__text TODO2
button.todo-list__item__button 削除
li.todo-list__item
input.todo-list__item__check(type="checkbox")
span.todo-list__item__text TODO3
button.todo-list__item__button 削除
.todo-list {
padding: 0;
&__item {
display: flex;
align-items: center;
width: 100%;
padding: 10px;
border: solid 1px #ddd;
border-radius: 5px;
& + & {
margin-top: 10px;
}
// itemエレメント以下で使う設定
&__text {
flex: 1 1 0;
padding: 0 5px;
}
}
}
終わりに
真面目にBEMで書いていくと、すぐにブロックを分ける必要がありました。Vue.jsとかだと同一ファイルに何個もブロックを書いても問題ありませんが、単純な静的サイトでscssファイルに書く場合はクラス名とファイル名は一緒になっていないと探しづらかったりするのでブロックの安易な分割は結構辛いなと思っていました。なるべくブロックを分割せずに上手くまとめようとすると謎のHTML構成になってしまい、修正が難しくなってしまうことも多々ありました。
そこで2階層まではBlock__Element__Element
で書けるようにして1つのブロックにまとめれるようになるともう少し保守がしやすくなるんじゃないかなと思いました。
ただこのようにかくと更に長くなるので、modifierが凄いことになるので、ここはマルチクラスに変えたりするといいのかなと思いました。
BEM + RSCSSでVariant BEMを検討する