読者です 読者をやめる 読者になる 読者になる

新しい日記

新しい日記

sass(scss)の&と変数を利用して親の親であるセレクタを参照する

sass の &(アンパサンド) はとっても便利。
特に BEM やるときは、いちいち block や element を書かずに & で書き足していけばいいのでやりやすい。
例えば以下のようなコードをコンパイルすると

.block{
  display: block;
  &__element{
    display: inline-block;
    &--modifier{
      color: #f00;
    }
  }
}

こうなる。

.block{display:block}
.block__element{display:inline-block}
.block__element--modifier{color:red}

んだけど、BEM かつシングルクラス設計にすると、例えば modifier に block や element 要素のスタイルを @extend したい。
例えばさっきのコードだったら、

.block{display:block}
.block__element{display:inline-block}
.block__element--modifier{display:inline-block,color:red}

となってほしかったりする。
そういうとき、以下みたいにセレクタの名前をいちいち調べて @extend するのはちょっとスマートじゃない。

.block{
  display: block;
  &__element{
    display: inline-block;
    &--modifier{
      @extend .block__element;
      color: #f00;
    }
  }
}

&でうまいことやれないかなと思うけど、&は親の名前なので、以下のようなコードだと意味不明になってしまう。

.block{
  display: block;
  &__element{
    display: inline-block;
    &--modifier{
      @extend #{&}; //@extend .block__element--modifer; になってしまう
      color: #f00;
    }
  }
}

そこで親の親の部分で、 &を変数に格納しておけば、そのあと引き継ぐことができる。

.block{
  display: block;
  &__element{
    display: inline-block;
    $element: #{&};
    &--modifier{
      @extend #{$element};
      color: #f00;
    }
  }
}

これをコンパイルすると以下のようになる。

.block{display:block}
.block__element,.block__element--modifier{display:inline-block}
.block__element--modifier{color:red}

これを応用する場面ですが、例えば @for で回してグリッドを作るとしたら、 コード量が少なく済む。
以下はdisplay: table; 前提のグリッドを任意の block の中で作る mixin のサンプルです。
($parent という命名はいかがなものかと思うが…)

@mixin grids($cols: 12){
  $width: 100/$cols;
  @for $i from 1 through $cols {
    &__#{$i}{
      $parent: #{&};
      box-sizing: border-box;
      display: table-cell;
      padding: 0 5px;
      width: $width*$i+0%;
      &:first-child{
        padding-left: 0;
      }
      &:last-child{
        padding-right: 0;
      }
      &--top{
        @extend #{$parent};
        vertical-align: top;
      }
      &--middle{
        @extend #{$parent};
        vertical-align: middle;
      }
      &--bottom{
        @extend #{$parent};
        vertical-align: bottom;
      }
    }
  }
}

これを .grid という block の中で使うとして、コンパイル

.grid__1,.grid__1--bottom,.grid__1--middle,.grid__1--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:8.33333%}
.grid__1--bottom:first-child,.grid__1--middle:first-child,.grid__1--top:first-child,.grid__1:first-child{padding-left:0}
.grid__1--bottom:last-child,.grid__1--middle:last-child,.grid__1--top:last-child,.grid__1:last-child{padding-right:0}
.grid__1--top{vertic.align:top}
.grid__1--middle{vertic.align:middle}
.grid__1--bottom{vertic.align:bottom}
.grid__2,.grid__2--bottom,.grid__2--middle,.grid__2--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:16.66667%}
.grid__2--bottom:first-child,.grid__2--middle:first-child,.grid__2--top:first-child,.grid__2:first-child{padding-left:0}
.grid__2--bottom:last-child,.grid__2--middle:last-child,.grid__2--top:last-child,.grid__2:last-child{padding-right:0}
.grid__2--top{vertic.align:top}
.grid__2--middle{vertic.align:middle}
.grid__2--bottom{vertic.align:bottom}
.grid__3,.grid__3--bottom,.grid__3--middle,.grid__3--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:25%}
.grid__3--bottom:first-child,.grid__3--middle:first-child,.grid__3--top:first-child,.grid__3:first-child{padding-left:0}
.grid__3--bottom:last-child,.grid__3--middle:last-child,.grid__3--top:last-child,.grid__3:last-child{padding-right:0}
.grid__3--top{vertic.align:top}
.grid__3--middle{vertic.align:middle}
.grid__3--bottom{vertic.align:bottom}
.grid__4,.grid__4--bottom,.grid__4--middle,.grid__4--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:33.33333%}
.grid__4--bottom:first-child,.grid__4--middle:first-child,.grid__4--top:first-child,.grid__4:first-child{padding-left:0}
.grid__4--bottom:last-child,.grid__4--middle:last-child,.grid__4--top:last-child,.grid__4:last-child{padding-right:0}
.grid__4--top{vertic.align:top}
.grid__4--middle{vertic.align:middle}
.grid__4--bottom{vertic.align:bottom}
.grid__5,.grid__5--bottom,.grid__5--middle,.grid__5--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:41.66667%}
.grid__5--bottom:first-child,.grid__5--middle:first-child,.grid__5--top:first-child,.grid__5:first-child{padding-left:0}
.grid__5--bottom:last-child,.grid__5--middle:last-child,.grid__5--top:last-child,.grid__5:last-child{padding-right:0}
.grid__5--top{vertic.align:top}
.grid__5--middle{vertic.align:middle}
.grid__5--bottom{vertic.align:bottom}
.grid__6,.grid__6--bottom,.grid__6--middle,.grid__6--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:50%}
.grid__6--bottom:first-child,.grid__6--middle:first-child,.grid__6--top:first-child,.grid__6:first-child{padding-left:0}
.grid__6--bottom:last-child,.grid__6--middle:last-child,.grid__6--top:last-child,.grid__6:last-child{padding-right:0}
.grid__6--top{vertic.align:top}
.grid__6--middle{vertic.align:middle}
.grid__6--bottom{vertic.align:bottom}
.grid__7,.grid__7--bottom,.grid__7--middle,.grid__7--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:58.33333%}
.grid__7--bottom:first-child,.grid__7--middle:first-child,.grid__7--top:first-child,.grid__7:first-child{padding-left:0}
.grid__7--bottom:last-child,.grid__7--middle:last-child,.grid__7--top:last-child,.grid__7:last-child{padding-right:0}
.grid__7--top{vertic.align:top}
.grid__7--middle{vertic.align:middle}
.grid__7--bottom{vertic.align:bottom}
.grid__8,.grid__8--bottom,.grid__8--middle,.grid__8--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:66.66667%}
.grid__8--bottom:first-child,.grid__8--middle:first-child,.grid__8--top:first-child,.grid__8:first-child{padding-left:0}
.grid__8--bottom:last-child,.grid__8--middle:last-child,.grid__8--top:last-child,.grid__8:last-child{padding-right:0}
.grid__8--top{vertic.align:top}
.grid__8--middle{vertic.align:middle}
.grid__8--bottom{vertic.align:bottom}
.grid__9,.grid__9--bottom,.grid__9--middle,.grid__9--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:75%}
.grid__9--bottom:first-child,.grid__9--middle:first-child,.grid__9--top:first-child,.grid__9:first-child{padding-left:0}
.grid__9--bottom:last-child,.grid__9--middle:last-child,.grid__9--top:last-child,.grid__9:last-child{padding-right:0}
.grid__9--top{vertic.align:top}
.grid__9--middle{vertic.align:middle}
.grid__9--bottom{vertic.align:bottom}
.grid__10,.grid__10--bottom,.grid__10--middle,.grid__10--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:83.33333%}
.grid__10--bottom:first-child,.grid__10--middle:first-child,.grid__10--top:first-child,.grid__10:first-child{padding-left:0}
.grid__10--bottom:last-child,.grid__10--middle:last-child,.grid__10--top:last-child,.grid__10:last-child{padding-right:0}
.grid__10--top{vertic.align:top}
.grid__10--middle{vertic.align:middle}
.grid__10--bottom{vertic.align:bottom}
.grid__11,.grid__11--bottom,.grid__11--middle,.grid__11--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:91.66667%}
.grid__11--bottom:first-child,.grid__11--middle:first-child,.grid__11--top:first-child,.grid__11:first-child{padding-left:0}
.grid__11--bottom:last-child,.grid__11--middle:last-child,.grid__11--top:last-child,.grid__11:last-child{padding-right:0}
.grid__11--top{vertic.align:top}
.grid__11--middle{vertic.align:middle}
.grid__11--bottom{vertic.align:bottom}
.grid__12,.grid__12--bottom,.grid__12--middle,.grid__12--top{box-sizing:border-box;display:table-cell;padding:0 5px;width:100%}
.grid__12--bottom:first-child,.grid__12--middle:first-child,.grid__12--top:first-child,.grid__12:first-child{padding-left:0}
.grid__12--bottom:last-child,.grid__12--middle:last-child,.grid__12--top:last-child,.grid__12:last-child{padding-right:0}
.grid__12--top{vertic.align:top}
.grid__12--middle{vertic.align:middle}
.grid__12--bottom{vertic.align:bottom}

まあ flexbox を使えるなら、こんなグリッド今時作ることないと思いますけどね!!!!!!

例はともかく、親の親を参照するのに変数に格納しておけば、万が一セレクタ名をタイポしてたとか変更しなきゃいけないときもエラーがでなくてラクチンなのでいいことです。