@extendで作るBEM系セレクター

2 min read読了の目安(約2400字

@extendとは

@extend される側として一連のスタイルを定義したセレクタがあり、そのセレクタを @extend で継承しつつプロパティを追加したりして、新しいセレクタを作ります

.button {
    display: inline-block;
    border: 1px solid gray;
    background-color: silver;
    &:hover {
        border-color: black;
    }
}

// .button セレクタを継承・拡張
.button-download {
    @extend .button;         // .button を継承
    background-color: green; // プロパティを上書き
    border-radius: 4px;      // 新たなプロパティの追加
    .icon {                  // ネストしたセレクタの追加
        background: url(/img/download.png) no-repeat 0 50%;
    }
}

この SCSS をコンパイルすると、こういう CSS が生成されます。

/* CSS */

.button,
.button-download {
    display: inline-block;
    border: 1px solid gray;
    background-color: silver;
}

.button:hover,
.button-download:hover {
    border-color: black;
}

.button-download {
    background-color: green;
    border-radius: 4px;
}

.button-download .icon {
    background: url(/img/download.png) no-repeat 0 50%;
}

この機能を使ってBEM系のセレクタを作成しようと思います。

実装 - 基本編

// 継承元のクラスを作成します。
.c-link {
  text-decoration: none;
  &--black {
    @extend .c-link; // 継承する
    color: black; // 追加プロパティ
  }
}

これをコンパイルすると

.c-link, .c-link--black {
  text-decoration: none;
}

.c-link--black {
  color: black;
}

の様にコンパイルされてModifierの宣言がきれいに追加されるcssがコンパイルされます。

実装 - 応用編

少し複雑なやつです。
解説は疲れるので気が向いたらやります。

.support-list {
  ...

  &__item {
    ...

    &__title {
      $base: #{&}; // この時点のセレクタを$baseの変数に格納
      font-size: $font-size__card-title;
      font-family: ShinMGoB;
      height: 6.5em;

      &::before {
        content: "";
        display: block;
        height: $font-size__contact;
        background-size: contain;
        margin-bottom: .2em
      }

      &--open-copywriting {
        @extend #{$base}; // 変数に格納しているセレクタを継承
        &::before {
          background-image: url("../img/Icon-open-copywriting.svg");
        }
      }
      &--pencil {
        @extend #{$base}; // 変数に格納しているセレクタを継承
        &::before {
          background-image: url("../img/Icon-pencil.svg");
        }
      }
      &--network-wired {
        @extend #{$base}; // 変数に格納しているセレクタを継承
        &::before {
          background-image: url("../img/Icon-network-wired.svg");
        }
      }
      &--microphone {
        @extend #{$base}; // 変数に格納しているセレクタを継承
        &::before {
          background-image: url("../img/Icon-microphone.svg");
        }
      }
    }
  }
}