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 を使えるなら、こんなグリッド今時作ることないと思いますけどね!!!!!!
例はともかく、親の親を参照するのに変数に格納しておけば、万が一セレクタ名をタイポしてたとか変更しなきゃいけないときもエラーがでなくてラクチンなのでいいことです。