HTML
CSS
scss
bem
フロントエンド

BEMのmodifierでスタイルを切り替える時の書き方

はじめに

BEMでこういうよくあるモジュールがあるとする。

<div class="p-hoge">
  <div class="p-hoge__photo">
    <img src="aaa.jpg" alt="">
  </div>
  <div class="p-hoge__text">
    テキストテキスト
  </div>
</div>

modifierをつけて要素のstyleを切り替えたい、みたいなことはよくあると思う。

.p-hoge <----> .p-hoge--reverse

でも、sassはネストしまくると

  • 可読性が悪い
  • 検索しづらい

ので私も基本は、ネストさせないようにしている。
https://qiita.com/tatsuyankmura/items/49ac82183415b7779df1

その辺を踏襲しつつ、より良い書き方を探ってみることにした。

※(注) BlockとElementをネストはさせないけど、modifierは「&」でネストさせます。
Block--Element まで検索出来れば、あとは見つけやすいだろうという考えです。

(A) それぞれスタイルを変化させるBlockとElementにModifierをつける

A.html
<div class="p-hoge p-hoge--reverse">
  <div class="p-hoge__photo p-hoge__photo--reverse">
    <img src="aaa.jpg" alt="">
  </div>
  <div class="p-hoge__text p-hoge__text--reverse">
    テキストテキスト
  </div>
</div>

(※参考)ネストさせて書くバージョン

A.scss
.p-hoge{
  display:flex;
  background-color:#f00;
  &--reverse{
    background-color:#00f;
  }
  &__photo{
    width:100px;
    &--reverse{
      order:1;
    }
  }
  &__text{
    font-size:1.5rem;
    &--reverse{
        order:0;
    }
  }
}

これは、楽!一人でやったり、短期の案件ならこれでいいんじゃないだろうか。

ネストさせないで書くバージョン

A_2.scss
.p-hoge{
  display:flex;
  background-color:#f00;
  &--reverse{
    background-color:#00f;
  }
}
.p-hoge__photo{
  width:100px;
  &--reverse{
    background-color:#00f;
    order:1;
  }
}
.p-hoge__text{
  font-size:1.5rem;
  &--reverse{
    order:0;
  }
}

これは割とスムーズにかける。
「&」が使える分コードを書くのが楽だし ElementをBlockの入れ子にしてないので見やすい。
難点はhtmlの記述量が増えてしまうのと、「jsでclassを切り替えてstyle変更」が3つの要素を変更しなければいけないのが難点。
現実的ではないかも。

(B) Aと似ているが、「Block + Modifier + Element」という点が違う

B.html
<div class="p-hoge p-hoge--reverse">
  <div class="p-hoge__photo p-hoge--reverse__photo">
    <img src="aaa.jpg" alt="">
  </div>
  <div class="p-hoge__text p-hoge--reverse__text">
    テキストテキスト
  </div>
</div>
B.scss
.p-hoge{
  display:flex;
  background-color:#f00;
  &--reverse{
    background-color:#00f;
  }
}
.p-hoge__photo{
  width:100px;
}
.p-hoge--reverse__photo{
  order:1;
}
.p-hoge__text{
  font-size:1.5rem;
}
.p-hoge--reverse__text{
    order:0;
}

なんかうまい書き方が思い浮かばなかった。普通に書くのが無難か。

(C) block要素にのみModifierをつける。 cssの方でネストにして対応

C.html
<div class="p-hoge p-hoge--reverse">
  <div class="p-hoge__inner">
    <div class="p-hoge__photo">
      <img src="aaa.jpg" alt="">
    </div>
    <div class="p-hoge__text">
      テキストテキスト
    </div>
  </div>
</div>
C.scss
.p-hoge{
  $this: & !global;
  display:flex;
  background-color:#f00;
  &--reverse{
    background-color:#00f;
  }
}
.p-hoge__photo{
  width:100px;
  #{$this}--reverse &{
    order:1;
  }
}
.p-hoge__text{
  font-size:1.5rem;
  #{$this}--reverse &{
      order:0;
  }
}

ここでも、推奨されている
http://getbem.com/faq/#block-modifier-affects-elements

While in general BEM recommends avoiding nested selectors, in this case they are reasonable.
一般に、BEMはネストされたセレクタを避けることを推奨しますが、この場合は合理的です。

thisをグローバルにせざるを得ないので、
案件で$thisは、この用途以外で使わない!というルールが必要。

この書き方が一番いい気がする。

  • jsでのclassの切り替えもblockだけで良い。
  • ネストするけど、可読性は高い(Elementの)

最近はCで書いています。

もし、他に良い書き方があれば教えていただけるとありがたいです。

参考記事

https://qiita.com/tatsuyankmura/items/49ac82183415b7779df1
https://qiita.com/usagi-f/items/b4e56e765384c49d5d04
https://qiita.com/y_hokkey/items/70eb2bc1394d74989359