かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Sass if文 ( @ifディレクティブ ) の中で変数を使う時の罠

Sass で if文中で変数を使う時にスコープのトラップがあったのでメモ。

if文 ( @ifディレクティブ ) の中で作成された変数は、if文外でアクセスできない

次のような書き方だと変数が存在しないというコンパイルエラーになります。

.foo {
  @if $is-error {
    $color: red;
  } @else {
    $color: inherit;
  }
  color: $color;
}

=> Undefined variable: "$color".

Sass の if文 ( @ifディレクティブ ) はスコープを作成するようで、ディレクティブ外の変数にはアクセスできるが、ディレクティブ内のローカル変数はディレクティブ外ではアクセスできないという仕様なようです。

if文で変数の変更したい時は、if文の外で変数定義をする必要がある

上記のような単純なものなら @else 節を使わずに書くのが良さそうです。

.foo {
  $color: inherit;
  @if $is-error {
    $color: red;
  }
  color: $color;
}

或いは三項演算子のような if 関数を使う

.foo {
  color: if($is-error, red, inherit);
}

おまけ global 変数の上書き

Sass v3.3 より前は、ローカルスコープ内で global の変数が変更できてしまっていた。
Sass v3.3 からはローカルスコープで global の変数は上書きされなくなった。

$color: red;
.foo {
  $color: blue;
  color: $color;
}
.bar {
  color: $color;
}

↓ Sass 3.3 より前でのコンパイル結果

.foo { color: blue; }
.bar { color: blue; }

↓ Sass 3.3 以降でのコンパイル結果

.foo { color: blue; }
.bar { color: red; }

global の変数をローカルスコープ内で上書き変更したい時は !global キーワードを使う

$color: red;
.foo {
  $color: blue !global;
  color: $color;
}
.bar {
  color: $color;
}

コンパイル

.foo { color: blue; }
.bar { color: blue; }

こうすると、Sass 3.3 より前と同じ挙動になる。
ローカルスコープで global 変数を上書きしたい場合がチョット思いつかないけど…

ポエム

if文がスコープを作成するのは予想外だった。( Ruby もこうじゃないよね? )
SCSS で言うところの { } で囲われるとスコープを作成する仕様になってるのかも知れない。
Sass v3.3 より前はローカルスコープで global の変数を上書きできてしまってたの、今のファイル分けまくって作成してる感覚だと結構ヤバイ仕様だったんだなーって思った。


[参考]

スラスラわかるHTML&CSSのきほん 第2版

スラスラわかるHTML&CSSのきほん 第2版