Sassの勉強 #09 @at-root (Ver.3.3以降)
@at-root
とりあえず「@at-root」の使い方書きます。
.parent { text-align:left; @at-root .child { text-align:center; } } /* コンパイル後 */ .parent { text-align: left; } .child { text-align: center; }
こんな感じでルールセットの中に「@at-root」をつっこめる。
上のサンプルは何の役にも立たないけれども、記述した場所より上のセレクタのネストを解除する、ということで、.parentのネストを解除して階層が1つ上がってるのが確認できる。上の例ではネストは2階層だけれども、3階層でも4階層でも「@at-root」が使われている箇所はネストが解除される。
@at-root (without: …) と @at-root (with: …)
@mediaなどのルールの中での「@at-root」はその中でのルートに展開される。
@media print{ .parent { text-align:left; @at-root .child { text-align:center; } } } /* コンパイル後 */ @media print { .parent { text-align: left; } .child { text-align: center; } }
これが不便だなという時用に「(without: …)」「(with: …)」というオプションを指定する事が可能。「(without: …)」を使用すれば外側で展開される。「(with: …)」を使用すれば中で展開される。
// withoutを使用した例 @media print{ .test{ width:100%; @at-root(without: media) { color: red; } } } /* コンパイル後 */ @media print { .test { width: 100%; } } .test { color: red; }
// withを使用した例 @media print{ .test{ width:100%; @at-root(with: media) { color:red; } } } /* コンパイル後 */ @media print { .test { width: 100%; } color: red; }
こうすることでメディアクエリの中で展開するものと外で展開させたいものを分ける事が可能に。うん、これは便利そう。
だが、まだだ。まだこの「@at-root」の使いどころがイマイチわからない。
@at-rootの使い道を求めて
「@at-root」の使いどころを求めて彷徨ったところ、下記のようなサンプルを発見。
@keyframesを一緒に書いておきたい時に。
@keyframesの使い方とかは省きますが、これはソースの管理が便利そう。
>>Using Sass 3.3s @at-root for piece of mind | Always Twisted. Front-End Development.
.avatar { background-color: red; height: 120px; margin: 40px; width: 120px; @at-root { @keyframes fade { 0% { transform: scale(1.0); } 25% { transform: scale(1.1); } 50% { transform: scale(1.0); } 75% { transform: scale(1.2); } 100% { transform: scale(1.1); } } } &:hover { animation: fade .8s infinite ease-in alternate; } } /* コンパイル後 */ .avatar { background-color: red; height: 120px; margin: 40px; width: 120px; } @keyframes fade { 0% { transform: scale(1); } 25% { transform: scale(1.1); } 50% { transform: scale(1); } 75% { transform: scale(1.2); } 100% { transform: scale(1.1); } } .avatar:hover { animation: fade .8s infinite ease-in alternate; }
BEMの命名ルールに沿った形を簡単に書く
「@at-root」を使ってBEMのルールに沿ってセレクタ名を書く事が容易に。確かに「@at-root」を使えば適した記述が簡単だとソースを見て納得。(ソースについての補足を後述してますのでご一読くださいませ)
>>Almost Profound — Sass 3.3 @at-root & BEM!
.speech-bubble{ color: purple; @at-root #{&}__header{ color: orange; } @at-root #{&}__text{ color: black; @at-root #{&}--link{ color: green; } } } /* コンパイル後 */ .speech-bubble { color: purple; } .speech-bubble__header { color: orange; } .speech-bubble__text { color: black; } .speech-bubble__text--link { color: green; }
更にミックスインでやろうぜという話も。
//elements get appended with "__" and the $name @mixin e($name) { @at-root #{&}__#{$name} { @content; } } //modifiers get appended with "--" and the $name @mixin m($name) { @at-root #{&}--#{$name} { @content; } } .speech-bubble{ color: purple; @include e(header){ //header element color: orange; } @include e(text){ //text element color: black; @include m(link){ //link modifier color: green; } } } /* コンパイル後 */ .speech-bubble { color: purple; } .speech-bubble__header { color: orange; } .speech-bubble__text { color: black; } .speech-bubble__text--link { color: green; }
BEM派な人にすごく良さげ。更にググって見ると結構BEMと「@at-root」の話を書いてる記事もあったから、その界隈では結構有名なネタなのだろう。(←今までノーマーク)
#{&} についての補足
上のサンプルソースのポイントは「@at-root」と「#{&}」ですね。それは把握。…なのですが、この「#{&}」部分については、sass ver3.3以降は「&」だけでOKです。(厳密には3.3.0.rc.6以降なのかな)
//elements get appended with "__" and the $name @mixin e($name) { @at-root &__#{$name} { @content; } } //modifiers get appended with "--" and the $name @mixin m($name) { @at-root &--#{$name} { @content; } }
こう書いても同じCSSが出力されます。どちらの書き方で書いてもエラーは出ないのだけれども、下記のような問題があって「&」だけで済むようになったとのこと。
試してみると確かに…#{&}の書き方で書いちゃうとセレクタがまずいことになる。
.foo, .bar { @at-root #{&}-suffix { color: blue; } } /* コンパイル後 */ .foo, .bar-suffix { color: blue; }
「&」のみの書き方なら大丈夫。
.foo, .bar { @at-root &-suffix { color: blue; } } /* コンパイル後 */ .foo-suffix, .bar-suffix { color: blue; }
ということで、「#{&}」は使用せずに「&」で書いた方が良いですねという補足。
ネストされたセレクタで、ルートと直近のセレクタの間に別のセレクタを挿入
まだSassの関数の話を書いてないのでアレなんですが、「selector_replace()」というSassの関数がありまして、
selector_replace($selector, $original, $replacement)
$selectorの$originalを$replacementに置換するっていう関数です。
こんな感じ↓
selector-replace(".foo .bar", ".bar", ".baz") => ".foo .baz"
selector-replace(".foo.bar.baz", ".foo.baz", ".qux") => ".bar.qux"
このselector_replace()関数と「@at-root」を利用してこんな事が出来ちゃうというぜっていうお話を下記サイトで見つけました。
>>selector-replace() の利用 · terkel.jp
.outer { color: red; .inner { color: green; @at-root { #{ selector-replace(&, '.outer', '.outer .foo') } { color: blue; } } } } /* コンパイル後 */ .outer { color: red; } .outer .inner { color: green; } .outer .foo .inner { color: blue; }
.outer下からいちいちセレクタを書きなおさなくても別のセレクタを割り込ませる事がこれで簡単に可能に。
また同サイトの使い方では汎用的なセレクタを定義したルールの中で絞り込みをするという話も書かれていました。
.bar { .button { border: 1px solid; @at-root { #{ selector-replace(&, ".button", "a.button") } { text-decoration: none; } } } } /* コンパイル後 */ .bar .button { border: 1px solid; } .bar a.button { text-decoration: none; }
.buttonというクラスを定義して、その中で要素がa要素だったら…っていう絞り込み。とにかく発想がすごいと思いました(*´ω`*)
Sassの勉強 関連記事
- Sassの勉強 #00 もっかい最初からやり直そうSassの巻
- Sassの勉強 #01 Sassとは何か?~環境構築
- Sassの勉強 #02 Sassの基本的な機能「ネスト」
- Sassの勉強 #03 Sassの基本的な機能「変数」
- Sassの勉強 #04 Sassの基本的な機能「演算」
- Sassの勉強 #05 Sassの基本的な機能「@import」
- Sassの勉強 #06 スタイルの継承ができる「@extend」
- Sassの勉強 #07 柔軟なスタイル定義が出来る「@mixin」
- Sassの勉強 #08 制御構文(条件分岐・繰り返し)
- Sassの勉強 #09 @at-root
- Sassの勉強 #10 Sassの勉強 #10 関数一覧(Ver.3.4) と自作関数