Help us understand the problem. What is going on with this article?

Element Modifierと同じノリでElementの見た目を変えれるBlock ModifierのSassの書き方

More than 1 year has passed since last update.
block-modifier.sass
=block--($modifier)
  $current: &
  $block: str_slice("#{&}", 0, str-index("#{&}", "__") - 1)

  @at-root #{$block}
    &--#{$modifier}
      #{$current}
        @content

使い方

親のBlockにModifierが指定されている場合のElementの見た目を、Element以下にネストして書ける。

user-icon.sass
.user-icon
  &__image
    width: 100px
    height: 100px

    +block--(round)
      border-radius: 50px
user-icon.css
.user-icon__image {
  width: 100px;
  height: 100px;
}
.user-icon--round .user-icon__image {
  border-radius: 50px;
}

動機: BlockにModifierを付けたい 

HTMLマークアップするときElementにModifierつけると書くのがダルいし横長になる。

.list
  %li.list__item.list__item--icebox 海に行く🏊
  %li.list__item.list__item--icebox スイカ割る🍉

BlockにModifierつけると横幅減って読みやすい

.list.list--icebox
  %li.list__item 海に行く🏊
  %li.list__item スイカ割る🍉

BlockのModifierによってElementの見た目を変えるのはしんどい

Sassが書きづらい

参考: BEMでmodifierを作る時に便利な&の変数化パターン

.list
  $self: &
  &__item
    // デフォルトの項目の見た目
  &--icebox
    #{$self}__item
      // iceboxに入っている項目の見た目

一方Elementにmodifierをつけるとこんな感じ。

.list
  &__item
    // デフォルトの項目の見た目
    &--icebox
      // iceboxに入っている項目の見た目

Blockのmodifierによって見た目を変えたいElementが他にもある場合、BlockのModifierでまとめようとするとこんな感じになってElementの定義と離れてしまう

.list
  $self: &
  &__item
    // デフォルトの項目の見た目
  &__foo
    // デフォルトのfooの見た目
  &__bar
    // デフォルトのbarの見た目
  &__fizzbuzz
    // デフォルトのfizz buzzの見た目
  &--icebox
    #{$self}__item
      // iceboxに入っている項目の見た目
    #{$self}__foo
      // iceboxに入っているfooの見た目
    #{$self}__bar
      // iceboxに入っているbarの見た目
    #{$self}__fizzbuzz
      // iceboxに入っているfizz buzzの見た目

それぞれのElementの下に書くと縦に伸びるし凸凹感がすごい

.list
  $self: &

  &__item
    // デフォルトの項目の見た目
  &--icebox
    #{$self}__item
      // iceboxに入っている項目の見た目
  &__foo
    // デフォルトのfooの見た目
  &--icebox
    #{$self}__foo
      // iceboxに入っているfooの見た目
  &__bar
    // デフォルトのbarの見た目
  &--icebox
    #{$self}__bar
      // iceboxに入っているbarの見た目
  &__fizzbuzz
    // デフォルトのfizz buzzの見た目
  &--icebox
    #{$self}__fizzbuzz
      // iceboxに入っているfizz buzzの見た目

mixinを使うと便利

block-modifier.sass
=block--($modifier)
  $current: &
  $block: str_slice("#{&}", 0, str-index("#{&}", "__") - 1)

  @at-root #{$block}
    &--#{$modifier}
      #{$current}
        @content

このmixinを使うとこのSassが

.list
  $self: &;
  &__item
    // デフォルトの項目の見た目
  &--icebox
    #{$self}__item
      // iceboxに入っている項目の見た目

こうなる

.list
  &__item
    // デフォルトの項目の見た目
    +block--(icebox)
      // iceboxに入っている項目の見た目

このSassが

.list
  $self: &
  &__item
    // デフォルトの項目の見た目
  &__foo
    // デフォルトのfooの見た目
  &__bar
    // デフォルトのbarの見た目
  &__fizzbuzz
    // デフォルトのfizz buzzの見た目
  &--icebox
    #{$self}__item
      // iceboxに入っている項目の見た目
    #{$self}__foo
      // iceboxに入っているfooの見た目
    #{$self}__bar
      // iceboxに入っているbarの見た目
    #{$self}__fizzbuzz
      // iceboxに入っているfizz buzzの見た目

こう

.list
  &__item
    // デフォルトの項目の見た目
    +block--(icebox)
      // iceboxに入っている項目の見た目
  &__foo
    // デフォルトのfooの見た目
    +block--(icebox)
      // iceboxに入っているfooの見た目
  &__bar
    // デフォルトのbarの見た目
    +block--(icebox)
      // iceboxに入っているbarの見た目
  &__fizzbuzz
    // デフォルトのfizzbuzzの見た目
    +block--(icebox)
      // iceboxに入っているfizz buzzの見た目

まとめ

SassとBEMべんり

もう少し汎用的にするとこういう感じです。

within-block.sass
=within-block($s)
  $current: &
  $block: str_slice("#{&}", 0, str-index("#{&}", "__") - 1)

  @at-root #{$block}#{$s} &
    @content

.user-icon
  &__image
    width: 100px
    height: 100px

    +within-block(--round)
      border-radius: 50px

    +within-block(".is-round")
      border-radius: 50px
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away