CSS 変数 - メリット

CSS 変数(正確には CSS カスタム プロパティ)が Chrome 49 でリリースされます。これらは、CSS の繰り返しを減らすために役立ちます。また、テーマの切り替えや、将来の CSS 機能の拡張やポリフィル化などの強力なランタイム エフェクトにも使用できます。

CSS の混乱

アプリをデザインする際は、アプリの見た目を統一するために、再利用されるブランドカラーのセットを確保するのが一般的です。残念ながら、CSS でこれらの色の値を何度も繰り返すのは、面倒なだけでなく、エラーが発生しやすくなります。いずれかの色を変更する必要がある場合は、慎重に考えずにすべてを「検索して置換」することもできますが、プロジェクトが十分に大きい場合は危険につながる可能性があります。

最近では、多くのデベロッパーが SASS や LESS などの CSS プリプロセッサを利用して、プリプロセッサ変数を使用してこの問題を解決しています。これらのツールはデベロッパーの生産性を大幅に向上させましたが、使用する変数には大きな欠点があります。それは、変数が静的で実行時に変更できないことです。実行時に変数を変更する機能を追加すると、動的アプリケーション テーマ設定などの機能が利用できるようになるだけでなく、レスポンシブ デザインに大きな影響を与え、将来の CSS 機能をポリフィル化する可能性があります。Chrome 49 のリリースにより、これらの機能は CSS カスタム プロパティの形式で使用できるようになりました。

カスタム プロパティの概要

カスタム プロパティは、CSS ツールボックスに 2 つの新機能を追加します。

  • 作成者が任意の値を、作成者が選択した名前のプロパティに割り当てることができる機能。
  • var() 関数。作成者はこれらの値を他のプロパティで使用できます。

簡単な例を次に示します。

:root {
    --main-color: #06c;
}

#foo h1 {
    color: var(--main-color);
}

--main-color は作成者が定義したカスタム プロパティであり、値は #06c です。すべてのカスタム プロパティは 2 つのダッシュで始まります。

var() 関数は、自身を取得してカスタム プロパティ値に置き換えます。結果は color: #06c; になります。ただし、カスタム プロパティがスタイルシート内のどこかで定義されている限り、var 関数で使用できます。

最初の構文は奇妙に見えるかもしれません。多くのデベロッパーから、「変数名に $foo を使用しないのはなぜですか?」という質問が寄せられます。このアプローチは、可能な限り柔軟で、将来的に $foo マクロを許可できるようにするために選択されました。背景については、仕様作成者の 1 人である Tab Atkins のこちらの投稿をご覧ください。

カスタム プロパティの構文

カスタム プロパティの構文は単純です。

--header-color: #06c;

カスタム プロパティでは大文字と小文字が区別されるため、--header-color--Header-Color は異なるカスタム プロパティです。カスタム プロパティでは、額面はシンプルに見えるかもしれませんが、カスタム プロパティで使用できる構文は実際には制約が緩やかです。たとえば、有効なカスタム プロパティは次のとおりです。

--foo: if(x > 5) this.width = 10;

これは変数としては使用できませんが、通常のプロパティでは無効であるため、実行時に JavaScript で読み取って処理できます。つまり、カスタム プロパティを使用すると、現在の CSS プリプロセッサでは不可能なさまざまな興味深い手法を利用できる可能性があります。「SASS があるからどうでもいい」と思っている方は、もう一度よく見てください。これらは、これまで扱ってきた変数とは異なります。

カスタム プロパティは標準のカスケード ルールに従うため、同じプロパティを異なる限定度で定義できます。

:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
    While I got red set directly on me!
    <p>I’m red too, because of inheritance!</p>
</div>

つまり、メディアクエリ内でカスタム プロパティを活用して、レスポンシブ デザインに役立てることができます。たとえば、画面サイズが大きくなるにつれて、主要なセクション要素の周囲の余白を広げることができます。

:root {
    --gutter: 4px;
}

section {
    margin: var(--gutter);
}

@media (min-width: 600px) {
    :root {
    --gutter: 16px;
    }
}

ただし、上記のコード スニペットは、メディアクエリ内で変数を定義できない現在の CSS プリプロセッサでは使用できません。この機能により、さまざまな可能性が広がります。

他のカスタム プロパティから値を取得するカスタム プロパティを設定することもできます。これは、テーマ設定に非常に役立ちます。

:root {
    --primary-color: red;
    --logo-text: var(--primary-color);
}

var() 関数

カスタム プロパティの値を取得して使用するには、var() 関数を使用する必要があります。var() 関数の構文は次のようになります。

var(<custom-property-name> [, <declaration-value> ]? )

ここで、<custom-property-name> は作成者定義のカスタム プロパティの名前(--foo など)で、<declaration-value> は、参照されたカスタム プロパティが無効な場合に使用されるフォールバック値です。フォールバック値はカンマ区切りのリストにできます。このリストは 1 つの値に結合されます。たとえば、var(--font-stack, "Roboto", "Helvetica");"Roboto", "Helvetica" のフォールバックを定義します。ただし、マージンやパディングに使用されるような省略形の値はカンマ区切りではないため、パディングの適切な代替手段は次のようになります。

p {
    padding: var(--pad, 10px 15px 20px);
}

コンポーネント作成者はこれらのフォールバック値を使用して、要素の防御スタイルを作成できます。

/* In the component’s style: */
.component .header {
    color: var(--header-color, blue);
}
.component .text {
    color: var(--text-color, black);
}

/* In the larger application’s style: */
.component {
    --text-color: #080;
    /* header-color isn’t set,
        and so remains blue,
        the fallback value */
}

カスタム プロパティは Shadow 境界を走査できるため、この手法は Shadow DOM を使用するウェブ コンポーネントのテーマを設定する場合に特に便利です。ウェブ コンポーネントの作成者は、フォールバック値を使用して初期デザインを作成し、カスタム プロパティの形式でテーマ設定の「フック」を公開できます。

<!-- In the web component's definition: -->
<x-foo>
    #shadow
    <style>
        p {
        background-color: var(--text-background, blue);
        }
    </style>
    <p>
        This text has a yellow background because the document styled me! Otherwise it
        would be blue.
    </p>
</x-foo>
/* In the larger application's style: */
x-foo {
    --text-background: yellow;
}

var() を使用する場合は、注意すべき点がいくつかあります。変数はプロパティ名にできません。次に例を示します。

.foo {
    --side: margin-top;
    var(--side): 20px;
}

ただし、これは margin-top: 20px; を設定することと同等ではありません。代わりに、2 番目の宣言は無効になり、エラーとして破棄されます。

同様に、その一部が変数で与えられている場合、値を作成することはできません。

.foo {
    --gap: 20;
    margin-top: var(--gap)px;
}

繰り返しになりますが、これは margin-top: 20px; の設定と同等ではありません。値を作成するには、calc() 関数以外の関数が必要です。

calc() を使用して値を作成する

calc() 関数は、CSS 値の計算を行える便利なツールです。すべての最新ブラウザでサポートされており、カスタム プロパティと組み合わせて新しい値を構築できます。例:

.foo {
    --gap: 20;
    margin-top: calc(var(--gap) * 1px); /* niiiiice */
}

JavaScript でカスタム プロパティを操作する

実行時にカスタム プロパティの値を取得するには、計算された CSSStyleDeclaration オブジェクトの getPropertyValue() メソッドを使用します。

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'

同様に、実行時にカスタム プロパティの値を設定するには、CSSStyleDeclaration オブジェクトの setProperty() メソッドを使用します。

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');

また、setProperty() の呼び出しで var() 関数を使用することで、実行時に別のカスタム プロパティを参照するようにカスタム プロパティの値を設定することもできます。

/* CSS */
:root {
    --primary-color: red;
    --secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');

カスタム プロパティは、スタイルシート内の他のカスタム プロパティを参照できるため、さまざまな興味深いランタイム効果につながる可能性があります。

ブラウザ サポート

現在、カスタム プロパティは Chrome 49、Firefox 42、Safari 9.1、iOS Safari 9.3 でサポートされています。

デモ

サンプルをお試しください。カスタム プロパティによって活用できる興味深い手法のすべてを確認できます。

関連情報

カスタム プロパティについて詳しくは、Google アナリティクス チームの Philip Walton が執筆したカスタム プロパティの導入に期待する理由をご覧ください。また、他のブラウザでの進捗状況については、chromestatus.com で確認できます。