始めに
CSSは簡単に壊れやすいので、保守性をあげるには色々ルールを考えないといけないと思います。今までに数々のアイデアが出ていて、それぞれ利点と欠点があると思います。これらを踏まえた上でいいとこ取りをしたルールを考えました。
BEM
BEMはBlock, Element, Modifierで構成されていて、__
と--
で区切ることで、クラス名を見るだけでどこのブロックなのかわかるようになっています。
//- block
.navigation
//- element
.navigation__link リンク1
//- element + modifier
.navigation__link.navigation__link--active リンク2(アクティブ)
.navigation__link リンク3
利点
クラス名を見るだけでどの要素かが分かりやすい
.navigation__link
みたいに書かれるため、「navigation
というBlockのlink
というElementなんだ」ということが一目瞭然です。これはHTMLが長くなるほど効果が発揮されます。
.todo-list
.todo-list__title TODOリスト
.todo-list__list
.todo-list__list__item
.todo-item
.todo-item__date 2019/05/01
.todo-item__check
.todo-item__text TODO1
.todo-list__list__item
.todo-item
.todo-item__date 2019/05/01
.todo-item__check
.todo-item__text TODO2
//- todo-listブロックに所属してtodo-list__list配下のitemエレメントであることがひと目で分かる
.todo-list__list__item
.todo-item
.todo-item__date 2019/05/01
.todo-item__check
.todo-item__text TODO3
名前の重複を心配する必要がほぼない
BEMは冗長さが売りで、クラス名がとにかく長いので被ってしまうことはほぼないでしょう。なのでグローバルにクラス名をガンガン定義していけて開発しやすいと思います。
エレメントごとのスタイル当てがやりやすい
BEMはマルチクラスや階層関係などでスタイルを当てないため、追加の設定がやりやすいです。例えばコンポーネントにmodifierが当たった時にエレメントもスタイルを当てたい場合は以下のようにして、エレメントの設定に追加で書くことができます。エレメントの場所に設定を書くことで変更が見やすくなります。
.todo-item {
$root: &;
&--selected {
...
}
// textエレメントの設定
&__text {
...
// todo-itemにselectedが付いた時のスタイル
#{$root}--selected & {
...
}
}
}
.block {
$root: &;
&__title {
...
}
&__text {
...
// titleエレメントがある時だけmarginを入れる
#{$root}__title + & {
margin-top: 10px;
}
}
}
欠点
クラス名が冗長すぎる
冗長さが特徴なので仕方ないのですが、あまりにも長いとクラス名だけで文字が埋まってしまうことがあります。特にmodifierがついてしまうと、ただでさえ冗長な文字にsuffixをつけてマルチクラスにするためクラス名が倍以上に増えます。
.header-navigation
.header-navigation__image-link.header-navigation__image-link--active
まとめ
BEMはベタープラクティスと言われるだけあってよく知られた方法で、割となんでも対応できます。ただmodifierをつけるとあまりにも冗長になってしまったり、まだベストとは呼ばれていない手法です。
RSCSS
BEMと似たような構成を持ちつつ、記述量を圧倒的に減らしたのがRSCSSというルールです。Component, Element, Variantで構成されています。
- Component: 2つ以上の単語で
-
でつなぐ - Element:
-
は使わずに1単語で表す。CSSでは.navigation-block > .link
のように親子セレクタ(>
)を使ってスタイルを当てる - Variant: prefixに
-
をつけて追加のスタイルを設定する
//- component
.navigation-block
//- element
.link リンク1
//- element + variant
.link.-active リンク2(アクティブ)
.link リンク3
利点
圧倒的な記述量の簡略化
上の例を見て分かる通り、BEMと比較して圧倒的に少ないです。少ないながらも、キチンとスタイルの競合を防いだ設計がされています。
欠点
ルールが少し難しい
Componentは必ず2単語以上にして-
でつながないといけなくて、逆にElementは-
でつないではいけないというルールがあるため、クラス名の命名で少し悩んでしまう可能性があります。単純すぎるのに2単語を考える必要があったり、2単語以上のElementの方が分かりやすいけど、-
を取ってしまうと読みづらくなってしまうなど。このルールを守らないとどれがComponentでどれがElementなのかの判定が難しくなってしまう可能性があります。
どこのComponentにいるかは上の階層を遡らないと分からない
基本的には親はすぐに見えるので問題ないのですが、HTMLが長くなってくると親が遠くてどこのComponentかがパッと見では分からなくなる時があります。
.todo-list
.title TODOリスト
.list
.item
.todo-item
.date 2019/05/01
.check
.text TODO1
.item
.todo-item
.date 2019/05/01
.check
.text TODO1
//- .itemがどのComponentに入っているのかが分かりづらい(2階層になっているためなおさら)
.item
.todo-item
.date 2019/05/01
.check
.text TODO1
複雑なCSSの設定は少しやりづらい
BEMの利点に書いたようなコンポーネントにmodifierが付いた時のエレメントのスタイル当ては分けて書くしかなくて、少し読みづらくなってしまいます。
.todo-item {
&.-selected {
...
}
// textエレメントの設定
> .text {
...
}
// todo-itemにselectedが付いた時のスタイル
&.-selected > .text {
...
}
}
.block {
> .title {
...
}
> .text {
...
}
// titleエレメントがある時だけmarginを入れる
> .title + .text {
margin-top: 10px;
}
}
まとめ
クラス名を簡略化しているため、どうしても複雑な構成になると実装が難しくなってしまいます。ただVue.jsのscoped cssみたいに影響範囲を制限している場合はそもそもBEMのように長く書く必要ないため、RSCSSで書いた方が早くかけるかもしれません。
BEMにRSCSSのVariantだけを取り入れる
2つのルールは一長一短ですが、基本的には僕はBEMの方を好みます。あまり考えなくても書けて、どんな問題でも割と対応できて柔軟性が強いためです。皆がよく知っているというのもあります。
ただそれでもmodifierをつけた時はかなり冗長でなんとかしたいと思ってました。そこでRSCSSのVariantのルールをBEMに採用したらどうなるのかなと思いました。
modifierだと同じBlock, Element名をつけて、その後ろにsuffixでmodifierをつけていましたが、この名前自体はユニークにしなくていいと思っているので、RSCSSのVariantと同じようにここだけマルチクラスにしたらスッキリするのかなと思いました。
.todo-item.-selected
.todo-item__date 2019/05/01
.todo-item__check.-checked
.todo-item__text TODO
.todo-item {
$root: &;
...
// todo-itemブロックにselectedオプションが付いた時のスタイル
&.-selected {
...
}
&__check {
...
// checkエレメントにcheckedが付いた時のスタイル
&.-checked {
...
}
}
&__text {
...
// ブロックにselectedが付いた時のスタイル
#{$root}.-selected & {
...
}
}
}
終わりに
BEMは柔軟性が高くて便利ですが、modifierを使うと一気に記述量が増えて大変でした。modifier部分はRSCSSでいうVariantの書き方にすると記述量が抑えられてもっと書きやすくなるかなと思いました。
CSSのルールはなかなかベストプラクティスにはたどり着けておらず皆さん試行錯誤していると思いますので、その人たちの何かキッカケになれれば幸いです。