CSS Variables とは、CSS でカスタムプロパティを定義し、変数として使用できるようにするための新しい CSS 仕様です。定義した変数は他のスタイル宣言内で参照することができることで、より効率的な CSS の記述が可能になります。
以前、この Blog でも書きましたが、CSS Variables は Firefox 29 が実装し、機能としては使用できるようになっていましたが、正式リリース版ではデフォルトでは無効だったのと、カスタムプロパティの接頭辞が var-
という古い仕様での実装でした。
近日正式版がリリースされる予定の Firefox 31 で最新の仕様 (接頭辞が --
に変更) を基に実装、デフォルト有効になる予定とのことですので、ちょうどいい機会と言うことで CSS Variables の使い方について最新の仕様に基づく解説を書いてみようと思います。
CSS calc() 関数が入れ子にできるようになると、カスタムプロパティと組み合わせてもっと便利になるよという記事を書いています。詳しくは 「Firefox 48 は CSS calc() 関数の入れ子に対応、CSS カスタムプロパティとの併用がより便利に」 をご覧ください。
本解説の基となる仕様書は下記です。
カスタムプロパティの基本的な使い方
まず最初に最も基本的な使い方についてですが、
--
から始まるカスタムプロパティを定義する- 変数を使いたい場所で
var(--hoge)
という形で呼び出す
という形になります。具体的なソースコードを示すと、まず下記のようにカスタムプロパティを定義し、
- :root {
- --bg-color: red;
- --border-radius: 4px;
- --box-padding: 10px 20px;
- --txt-color: white;
- }
下記のように、任意の場所で呼び出します。
- .btn {
- display: inline-block;
- background-color: var(--bg-color);
- border-radius: var(--border-radius);
- color: var(--txt-color);
- padding: var(--box-padding);
- }
実際のスタイルとしては下記のように解釈されます。
- .btn {
- display: inline-block;
- background-color: red;
- border-radius: 4px;
- color: white;
- padding: 10px 20px;
- }
上の例だと普通に書いた方が早くね? 的な感じになってしまっていますが、うまく利用すれば効率的なスタイルシートの記述が可能になります。この辺は、Sass など、CSS プリプロセッサをすでに利用している人ならイメージしやすいかと思いますが。
ちなみに、カスタムプロパティの大文字小文字は区別されます。つまり、--foo
と --FOO
はそれぞれ個別に認識されます。
カスタムプロパティ記述の特徴
Sass などで使用する変数とカスタムプロパティが少し異なるのが、その解釈のされ方です。
例えば下記のような HTML があったとして、
- <div class="one">
- <p>one</p>
- <div class="two">
- <p>two</p>
- <div class="three">
- <p>three</p>
- </div>
- <div class="four">
- <p>four</p>
- </div>
- </div>
- </div>
これに対して下記のカスタムプロパティとスタイルを指定したとします。
- /* カスタムプロパティの定義 */
- :root {
- --text-color: red;
- }
- .two {
- --text-color: green;
- }
- .three {
- --text-color: blue;
- }
- /* 変数を呼び出し */
- div {
- color: var(--text-color);
- }
これが実際に反映されると画像のようになります。
ちなみに、.two {--text-color: green;}
などと書いているので、.two
に対してスタイルが宣言されているように思われますが、この記述の段階では .two
に対してカスタムプロパティの定義がされている状態となります。
実際にはそのあとの div {color: var(--text-color);}
の指定によって変数が呼び出されてはじめてスタイルとして宣言されますが、この指定の仕方の場合、もし同一の HTML 文書内に、ul.two
があったとしても、color: green;
は適用されません。
わかりやすいように CSS に直してみると下記のような感じに解釈されるということですね。
- div {
- color: red;
- }
- div.two {
- color: green;
- }
- div.three {
- color: blue;
- }
同じスタイル宣言を Sass で書く場合は下記のような感じになりますので (普通はこんな面倒な書き方しないと思いますが)、同じ変数を使うと言っても、記述の仕方はかなり異なることがわかると思います。
- $color: red;
- div {
- color: $color;
- $color: green;
- &.two {
- color: $color;
- }
- $color: blue;
- &.three {
- color: blue;
- }
- }
Sass の場合はネストすることで変数の参照範囲 (スコープ) が変化しますし、同じ変数に異なる値が定義された場合にどの値が優先されるかが決まりますが、カスタムプロパティの場合は、カスタムプロパティの定義や変数呼び出し時に指定したセレクタと、継承によって値がセットされることになります。
ユニバーサルセレクタによる変数の呼び出し
仕様書内のサンプルソースにもありますが、下記のように、ユニバーサルセレクタで変数を呼び出す指定もできます。
- /* カスタムプロパティの定義 */
- :root {
- --color: blue;
- }
- div {
- --color: green;
- }
- #alert {
- --color: red;
- }
- /* 変数を呼び出し */
- * {
- color: var(--color);
- }
下記のような HTML に上記が適用されると、それぞれ内容に書いてあるとおりのテキストカラーになります。
- <p>blue</p>
- <div>green</div>
- <div id="alert">
- <p>red</p>
- </div>
CSS 的には下記のように解釈されているということになります。
- * {
- color: blue;
- }
- div {
- color: green;
- }
- #alert {
- color: red;
- }
カスタムプロパティ内で変数の使用
下記のように、カスタムプロパティ内で、別のカスタムプロパティで定義された変数を呼び出すということも可能です。
- :root {
- --main-color: #c06;
- --accent-background: linear-gradient(to top, var(--main-color), white);
- }
もちろん、変数は別々に使用することができます。
- .sample {
- color: var(--main-color);
- }
- .box {
- background: var(--accent-background);
- }
変数が定義されていない場合のフォールバック
例えば、下記のような HTML と CSS があったとします。
- <div>
- <h1>header</h1>
- <p>text</p>
- </div>
- :root {
- --text-color: red;
- }
- div {
- color: var(--text-color);
- }
- h1 {
- color: var(--header-color);
- }
この場合、--header-color
というカスタムプロパティは定義されていませんので、h1 要素に対する color
プロパティの指定はされていないことになりますから、div 要素からの継承でテキストカラーは color: red;
が適用されてしまいますね。
そこで、下記のようにカスタムプロパティが定義されていなかった場合に適用される指定を追加しておきます。これによって、h1 要素には color: blue;
が適用されることになります。
- :root {
- --text-color: red;
- }
- div {
- color: var(--text-color);
- }
- h1 {
- color: var(--header-color, blue);
- }
カスタムプロパティが使用できる場所
カスタムプロパティは通常のプロパティと同じ扱いになりますので、プロパティが書ける場所であれば同様に使用できます。例えば、CSS Animations における、@keyframes 内で参照したり、@media 内で使ったりもできます。
- :root {
- --animation-duration: 3s;
- --animation-name: slidein;
- --animation-from: 100%;
- --animation-to: 0%;
- }
- h1 {
- animation-duration: var(--animation-duration);
- animation-name: var(--animation-name);
- }
- @keyframes slidein {
- from {
- margin-left: var(--animation-from);
- width: 300%
- }
- to {
- margin-left: var(--animation-to);
- width: 100%;
- }
- }
正しくないカスタムプロパティの記述例
下記のような記述は不正な記述になり、正常に動作しませんので注意しましょう。
プロパティ名を変数にしてしまう
下記のサンプルでは、margin-top
が変数として定義されていますが、変数として定義できるのは値だけですので、このような記述は不正です。
- /* 間違った記述例 */
- .sample {
- --side: margin-top;
- var(--side): 20px;
- }
単位なしの値を変数にしてしまう
下記のサンプルではカスタムプロパティで単位なしの数値のみ変数として定義し、呼び出す際に単位を指定しています。一見便利そうですが、このような記述は正しく動作しませんので注意が必要です。
- /* 間違った記述例 */
- .sample {
- --gap: 20;
- margin-top: var(--gap)px;
- }
ただし、calc()
を使用することで、単位なしの値を変数として定義して使用することは可能です。下記のような記述なら、正しく動作します。
- /* この記述は正しい記述例 */
- :root {
- --size: 20;
- }
- .sample {
- font-size: calc(var(--gap) * 2px);
- }
CSS としては下記のように解釈されます。
- .sample {
- font-size: 40px;
- }
calc()
を使用した記述例を次にもう少し詳しく説明していきましょう。
もう少し高度なカスタムプロパティの使用方法
さらに高度な使い方を見てみましょう。上で少し触れた、calc()
を使用する方法です。
calc()
との組み合わせ
CSS 内で計算式の記述を可能にする calc()
を使用して、より高度な変数の定義をすることも可能です。ちなみに、calc()
については相当昔 (4年も前だった・・・) ですが、下記の記事で書いていますので詳しくはそちらをご覧ください。
例えば、下記のように変数を定義できます。
- :root {
- --wrap-box-width: 500px;
- --box-margin: 10px;
- --box-padding: 5px;
- --box-column: 4;
- --box-width: calc(var(--wrap-box-width) / var(--box-column) - var(--box-margin) * 2 - var(--box-padding) * 2);
- }
- .sample {
- width: var(--wrap-box-width);
- }
- .sample div {
- float: left;
- margin: var(--box-margin);
- padding: var(--box-padding);
- width: var(--box-width);
- }
これを下記の HTML に適用すれば、4カラム横並びの div 要素が作れます。変数に定義する数値を変えることで、カラム数を簡単に変更することができますね。
- <div class="sample">
- <div>1</div>
- <div>2</div>
- <div>3</div>
- <div>4</div>
- <div>5</div>
- <div>6</div>
- <div>7</div>
- </div>
不正な値が変数として呼び出されたときの挙動
最後に、変数で呼び出された値が、そのプロパティでは使用できない値など、不正な値が呼び出されたときの挙動について見てみます。例えば下記のような CSS があったとしますね。
- :root {
- --not-a-color: 20px;
- }
- p {
- background-color: red;
- }
- p {
- background-color: var(--not-a-color);
- }
この指定だと、background-color
プロパティの値として 20px
がセットされてしまいますので、スタイルの指定としては不正な指定となります。
では、この間違った指定は無視されて、background-color: red;
の方が適用されるのかというと、そうはなりません。
あるプロパティに本来指定できない、不正な値がセットされた場合はそのプロパティの初期値が適用されます。つまり、background-color
プロパティの場合は transparent
が指定されたことになるということですね。
もちろん、下記のような順番で記述されていれば、カスケード処理に則って、p 要素には background-color: red;
が適用されます。これは var(--not-a-color)
が正しい値だったとしてもです。この辺は CSS の基本なのでわざわざ書く必要もないかもしれませんが。
- :root {
- --not-a-color: 20px;
- }
- p {
- background-color: var(--not-a-color);
- }
- p {
- background-color: red;
- }
さて、いかがだったでしょうか。まだ Firefox しか実装例がないので広く使える状態にはなっていない CSS Variables (CSS カスタムプロパティ) ですが、使い方によってはかなり便利な機能だということがおわかりいただけたんではないかと。
ちなみに、最新仕様に則った CSS Variables がデフォルトで有効になる予定の Firefox 31 は、7月22日に正式リリースされる予定です。