CSS カスタムプロパティ (変数) の使用

CSS 変数は、 CSS の作者によって作成され、文書全体で再利用可能な特定の値を含むエンティティです。それらは、カスタムプロパティ記法 (たとえば、--main-color: black;) によって設定し、 var() 関数 (たとえば、 color: var(--main-color);) を使ってアクセスします。

複雑なウェブサイトには、膨大な量の CSS があり、しばしば同じ値が使われています。たとえば、同じ色が異なる場所で数百使われており、色を変更する場合、グローバルに検索し、置き換えをしなくてはいけません。 CSS 変数を使えば、一ヶ所に値を保存しておき、複数の場所から参照できます。更なるメリットとして、意味的な識別をしやすくなります。たとえば、 --main-text-color#00ff00 より理解しやすいでしょう。とりわけ、同じ色がさまざまな文脈で使われる場合はそうです。

CSS 変数はカスケードの対象であり、親からの値を継承します。

基本的な使用方法

変数の宣言:

element {
  --main-bg-color: brown;
}

変数の使用:

element {
  background-color: var(--main-bg-color);
}

CSS 変数の最初のステップ

それぞれ異なるクラスの要素に同じ色を適用するシンプルな CSS から始めましょう。

.one {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 50px;
  height: 50px;
  display: inline-block;
}

.two {
  color: white;
  background-color: black;
  margin: 10px;
  width: 150px;
  height: 70px;
  display: inline-block;
}
.three {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 75px;
}
.four {
  color: white;
  background-color: brown;
  margin: 10px;
  width: 100px;
}

.five {
  background-color: brown;
}

これを下の HTML に適用します。

<div>
  <div class="one">1:</div>
  <div class="two">2: Text <span class="five">5 - more text</span></div>
  <input class="three">
  <textarea class="four">4: Lorem Ipsum</textarea>
</div>

このようになるはずです。

CSS 中に同じ宣言が繰り返し出てくることがわかるでしょうか。いろいろな場所で background colorbrown を設定しています。カスケードの上流で変数を宣言し、継承を利用することでこの問題を自然に解決することもできます。大きなプロジェクトでは、常にこの手法が取れるわけではありません。 :root 擬似クラスで変数を宣言することにより、変数を利用して同じ値を繰り返し書く必要性を減らすことができるのです。

:root {
  --main-bg-color: brown;
}

.one {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 50px;
  height: 50px;
  display: inline-block;
}

.two {
  color: white;
  background-color: black;
  margin: 10px;
  width: 150px;
  height: 70px;
  display: inline-block;
}
.three {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 75px;
}
.four {
  color: white;
  background-color: var(--main-bg-color);
  margin: 10px;
  width: 100px;
}

.five {
  background-color: var(--main-bg-color);
}
<div>
    <div class="one"></div>
    <div class="two">Text <span class="five">- more text</span></div>
    <input class="three">
    <textarea class="four">Lorem Ipsum</textarea>
</div>

この結果は前の例と同じになるはずであり、望んだプロパティを一つの標準的な宣言で実現することができます。

CSS 変数の継承

カスタムプロパティは継承されます。これはつまり、もし与えられた要素にカスタムプロパティの値がない場合、その値は親の値を使用するということです。 HTML を見てみましょう。

<div class="one">
  <div class="two">
    <div class="three"></div>
    <div class="four"></div>
  </div>
</div>

下記の CSS を適用します。

.two {
  --test: 10px;
}

.three {
  --test: 2em;
}

この場合、 var(--test) の結果は以下の通りです。

  • class="two" の要素: 10px
  • class="three" の要素: 2em
  • class="four" の要素: 10px (親から継承)
  • class="one" の要素: 無効な値、これはすべてのカスタムプロパティの既定値です。

これらはカスタムプロパティであり、実際には他のプログラミング言語で見られるような変数ではないことに留意してください。値は必要に応じて計算され、他の規則で使用するために格納されるわけではありません。例えば、要素にプロパティを設定して、兄弟の子孫の規則で受け取ることを期待することはできません。通常の CSS と同様、プロパティは一致するセレクター及びその子孫に対してのみ設定されます。

カスタムプロパティ代替値

var() 関数を使用して、指定された変数が定義されていない場合の代替値を複数定義することができます。カスタム要素およびシャドウ DOM で作業するときに便利なことがあります。

代替値はブラウザーの互換性を修正するためには使用されません。ブラウザーが CSS 変数に対応していない場合、代替値は助けになりません。これは CSS 変数に対応しているブラウザーのための単なるバックアップであり、与えられた変数が定義されていなかったり、無効な値であったりした場合に別な値を選択させるためのものです。

関数の最初の引数は、代替されるカスタムプロパティの名前です。関数の二番目の引数は、もしあれば、参照されたカスタムプロパティが無効であった場合に代わりに使用される代替値です。この関数は引数を2つだけ受け付けるので、最初のコンマの後のものは、すべて二番目の引数として割り当てます。二番目の引数が無効な場合、例えばコンマで区切られたリストが提供された場合、次のように代替処理は失敗します。

.two {
  color: var(--my-var, red); /* --my-var が定義されていなければ red */
}

.three {
  background-color: var(--my-var, var(--my-background, pink)); /* my-var 及び --my-background が定義されていなければ pink */
}

.three {
  background-color: var(--my-var, --my-background, pink); /* 無効: "--my-background, pink" */
}

代替としてのカスタムプロパティを含めるには、上記の二番目の例のようにすることが、複数の代替値を提供するための正しい方法です。この技法は変数全体を解釈するのにより時間が掛かるので、性能上の問題が見られます。

メモ: 代替値の構文は、カスタムプロパティの場合のように、コンマを使用することができます。例えば、 var(--foo, red, blue)red, blue という代替値を定義します。 — 最初のコンマから関数の終わりまでが代替値とみなされます。

値と妥当性

それぞれのプロパティに結び付けられるという CSS の妥当性の伝統的な概念は、カスタムプロパティに関してはあまり使いやすものではありません。カスタムプロパティの値が解析されるとき、ブラウザーはそれがどこで使用されるのか知りません。そのため、ほぼすべての値を妥当なものとみなす必要があります。

残念なことに、これらの値は妥当であっても、意味のない可能性がある場所で var() 関数表記で使用することができてしまいます。プロパティとカスタム変数が無効な CSS 文を生成する可能性があることから、計算時に妥当という新しい概念が導かれます。

無効な変数では何が起こるか

ブラウザーが無効な var() による置き換えに遭遇した場合、プロパティの初期値または継承値が使用されます。

以下のコードスニペットを考えてみてください。

HTML

<p>この段落は初期値で黒です。</p> 

CSS

:root { --text-color: 16px; } 
p { color: blue; } 
p { color: var(--text-color); }

期待通りに、ブラウザーは var(--text-color) の場所を --text-color の値で置き換えようとしますが、 16pxcolor に妥当なプロパティ値ではありません。置き換え後、プロパティは意味をなさなくなります。ブラウザーはこの状況を二段階で扱います。

  1. color プロパティが継承可能であるかを確認します。可能ですが、 <p> には color プロパティを持つ親がありません。よって次の段階に進みます。
  2. 値を既定の初期値、つまり、黒に設定します。

結果

置き換えが無効な場合は代替値ではなく、初期値に置き換えられるため、段落の色は青にはなりません。変数による置き換えなしで color: 16px と書いた場合は、構文エラーとなります。その場合はそれ以前の宣言が使用されます。

メモ: CSS プロパティと値の組に構文エラーがあるとその行が無視されるので、無効な代替値を使用した継承値 -- 無効なカスタムプロパティの値を使用すること -- は無視されず、継承される値になります。

JavaScript での値

カスタムプロパティを JavaScript で使用するには、標準のプロパティのようにします。

// インラインスタイルから値を取得
element.style.getPropertyValue("--my-var");

// あらゆる場所の変数を取得
getComputedStyle(element).getPropertyValue("--my-var");

// インラインスタイルに値を設定
element.style.setProperty("--my-var", jsVar + 4);

ブラウザーの対応

Update compatibility data on GitHub
デスクトップモバイル
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung Internet
--*Chrome 完全対応 49
完全対応 49
完全対応 48
無効
無効 From version 48: this feature is behind the Enable experimental Web Platform features preference. To change preferences in Chrome, visit chrome://flags.
Edge 完全対応 15Firefox 完全対応 31
完全対応 31
未対応 29 — 55
補足 無効
補足 From Firefox 29 until Firefox 31, this feature was implemented by the var-variablename syntax.
無効 From version 29 until version 55 (exclusive): this feature is behind the layout.css.variables.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
IE 未対応 なしOpera 完全対応 36Safari 完全対応 9.1WebView Android 完全対応 49Chrome Android 完全対応 49
完全対応 49
完全対応 48
無効
無効 From version 48: this feature is behind the Enable experimental Web Platform features preference. To change preferences in Chrome, visit chrome://flags.
Firefox Android 完全対応 31
完全対応 31
未対応 29 — 55
補足 無効
補足 From Firefox 29 until Firefox 31, this feature was implemented by the var-variablename syntax.
無効 From version 29 until version 55 (exclusive): this feature is behind the layout.css.variables.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
Opera Android 完全対応 36Safari iOS 完全対応 9.1Samsung Internet Android 完全対応 5.0
env()
実験的
Chrome 完全対応 69Edge 未対応 なしFirefox 完全対応 65IE 未対応 なしOpera 完全対応 56Safari 完全対応 11.1
完全対応 11.1
未対応 11 — 11.1
代替名
代替名 非標準の名前 constant を使用しています。
WebView Android 完全対応 69Chrome Android 完全対応 69Firefox Android 完全対応 65Opera Android ? Safari iOS 完全対応 11.1
完全対応 11.1
未対応 11 — 11.1
代替名
代替名 非標準の名前 constant を使用しています。
Samsung Internet Android ?
var()Chrome 完全対応 49
完全対応 49
完全対応 48
無効
無効 From version 48: this feature is behind the Enable experimental Web Platform features preference. To change preferences in Chrome, visit chrome://flags.
Edge 完全対応 15Firefox 完全対応 31
完全対応 31
未対応 29 — 55
無効
無効 From version 29 until version 55 (exclusive): this feature is behind the layout.css.variables.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
IE 未対応 なしOpera 完全対応 36Safari 完全対応 9.1WebView Android 完全対応 50Chrome Android 完全対応 49
完全対応 49
完全対応 48
無効
無効 From version 48: this feature is behind the Enable experimental Web Platform features preference. To change preferences in Chrome, visit chrome://flags.
Firefox Android 完全対応 31
完全対応 31
未対応 29 — 55
無効
無効 From version 29 until version 55 (exclusive): this feature is behind the layout.css.variables.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
Opera Android 完全対応 36Safari iOS 完全対応 9.1Samsung Internet Android ?

凡例

完全対応  
完全対応
未対応  
未対応
実装状況不明  
実装状況不明
実験的。動作が変更される可能性があります。
実験的。動作が変更される可能性があります。
実装ノートを参照してください。
実装ノートを参照してください。
ユーザーが明示的にこの機能を有効にしなければなりません。
ユーザーが明示的にこの機能を有効にしなければなりません。
非標準の名前を使用しています。
非標準の名前を使用しています。

メモ: 初期仕様のカスタムプロパティの接頭辞は var- でしたが、最新の仕様では -- に変更されました。 Firefox 31 以上は最新仕様に従っています。 (バグ 985838)

関連情報