スタイルを整理するとき、**Sass の変数($name)**と **CSS カスタムプロパティ(--name)**のどちらに値を置くかで挙動が変わります。名前が似ていても、役割はかなり違います。
いつ・どこで値が決まるか
Sass 変数は コンパイル時に解決されます。ビルドが終わった CSS には $primary という名前は残らず、展開された色や長さだけが出力されます。
カスタムプロパティは ブラウザが CSS を解釈するときに評価されます。生成物には --heading-color: #111; のように 名前付きのプロパティがそのまま残ります。
この差が、以降の「上書き」「JS からの変更」「メディアクエリとの組み合わせ」に効いてきます。
スコープと上書き
Sass 変数のスコープは Sass のモジュール・関数・ミックスイン・ネストのルールに従います。コンパイル結果としては、あるセレクタに color: #111 のように 確定した宣言が並ぶだけです。DOM の親子関係や、後から付いたクラスで「変数そのもの」を差し替えることはできません(別のクラス用に別の CSS が出力される、という形になります)。
カスタムプロパティは カスケードの対象です。親で --block-color を変えれば、子の color: var(--block-color) は その時点の継承値を読みます。メディアクエリ、:hover、[data-theme="dark"]、インラインの style、JavaScript による element.style.setProperty('--x', …) など、実行時に値を変える設計に向きます。
計算と型の扱い
Sass 変数は Sass の世界で 色を暗くする・rem() に通す・map から引くといった処理をしやすいです。結果だけを CSS に出せばよいので、設計トークンをビルド段階で一括変換する用途に強いです。
カスタムプロパティの値は、多くの場合 文字列として保持され、calc() や color-mix() など CSS 側の関数と組み合わせます。Sass で作った色をカスタムプロパティに載せるときは、--c: #{$sassColor}; のように 一度 CSS の文法に落とすイメージになります。
使い分けの目安
-
テーマ切り替え、バリアント、親ブロックから子へ見た目だけ差し替えたい
→ カスタムプロパティで「差し替え可能な軸」を--に寄せ、var()で参照する。 -
ブレークポイント、間隔の基準、ファイル分割のための定数など、ランタイムで変えない設計用の値
→ Sass 変数や map でよいことが多い。 -
JavaScript やインラインスタイルで動的に変えたい値
→ カスタムプロパティが現実的。
一言でまとめると、Sass 変数はビルド時の設計図、カスタムプロパティはブラウザ上でまだ差し替えられる配線です。見た目の差し替えをカスケードで表現したいなら --、コンパイル時に決め切るなら $、という整理が衝突が少ないです。