Hail2u

Sassの変数スコープと!global

Sassの変数スコープの仕様では、ローカル・コンテキストからグローバル変数を上書きできていた。LESSでは多くのプログラミング言語と一緒で上書きはできないという素直な仕様になっている。Sass 3.3では上書きしようとすると警告が出るようになり、!globalフラグを使い明示的に上書きしていることを教える必要があるようになった。将来的には仕様が変更され、警告なしでLESSと同じ挙動になるようだ。

Sassではローカル・コンテキストでグローバル変数を上書きでき、そのスコープを抜けてもそのままになる。

$color: #f00;

.test-local {
  $color: #0f0;
  color: $color; // #0f0
}

.test-global {
  color: $color; // #0f0
}

対してLESSでは上書きされない。

@color: #f00;

.test-local {
  @color: #0f0;
  color: @var; // #0f0
}

.test-global {
  color: @color; // #f00 yay!
}

Sass 3.3ではグローバル変数をローカル・コンテキストで変更しようとした時に警告(Backwards Incompatibilitiesの12個目の項目を参照)が出るようになった。具体的には以下のような警告メッセージをSassコンパイラが吐く。

$ scss test.scss test.css
DEPRECATION WARNING on line 4 of test.scss:
Assigning to global variable "$color" by default is deprecated.
In future versions of Sass, this will create a new local variable.
If you want to assign to the global variable, use "$color: #0f0 !global" instead.
Note that this will be incompatible with Sass 3.2.

この警告を出さないようにするには!globalフラグを使う。

$color: #f00;

.test-local {
  $color: #0f0 !global;
  color: $color; // #0f0
}

.test-global {
  color: $color; // #0f0
}

警告が出るのみで、そのメッセージの通り実際にはまだ挙動は変わらない。しかし、将来的にはローカル変数を新しく作成する(this wil create a new local variable)と書かれているので、挙動はLESSと同じになるのだろう。

$color: #f00;

.test-local {
  $color: #0f0;
  color: $color; // #0f0
}

.test-global {
  color: $color; // #f00 gotcha!
}

つまり!globalフラグを使うことにより今までの挙動を維持したまま警告は出なくなるが、それは一時しのぎに過ぎないということだ。そこそこ大きな互換性のない変更なので、その「一時」はかなり長い間ではありそうだが。元々ローカル・コンテキストでグローバル変数を上書きするのは、そのルールセットの順番を変えるだけで破綻するようなあまり行儀の良い書き方ではないので、なるべくなら仕様の変更を見据えて書き直した方が良いだろう。


現状の仕様だとグローバル変数で全てやった方が効率的なので、世のSassコードはだいたいそうなっている。しかしグローバル変数を多用する場合、変数へ厳しい命名規則を適用しないと、保守性があからさまに落ちる。例えばBEMを応用するのはひとつの手で、そのようなことを行っている人もちらほら聞くし、僕も使ったりしている。ただ、そういった厳しい命名規則は、長い変数名や特殊な言い回しとセットと言って良いので、書きやすさや導入しやすさに大きく欠ける。

LESSのようにローカル変数が新しく作成されるようになれば、ローカル・スコープでの衝突のみを考慮すれば良くなる。そうすれば命名規則が随分とゆるやかになるか、ほとんどいらなくなるだろう。特殊な言い回しに至っては害悪ということにすらなるかもしれない。ただCSS Variablesとの兼ね合いから考えると、SassにしろLESSにしろ、カスケーディングを考慮しない変数システムは将来性に欠けるところもある。少なくとも!globalが不要なように書き直す必要はあるが、それ以上にSassべったりな形での変数の取り扱いへ移行するのは、まだ自重するべき段階だと言えるだろう。