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 DOM を使用する Web Components のテーマ設定に特に便利です。ウェブ コンポーネントの作成者は、フォールバック値を使用して初期デザインを作成し、カスタム プロパティの形式でテーマ設定の「フック」を公開できます。

<!-- 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 で確認できます。