CSS カスタムプロパティ(変数)の使用
カスタムプロパティ(CSS 変数やカスケード変数と呼ばれることもあります)は、CSS の作者によって作成され、文書全体で再利用可能な特定の値を表すエンティティです。これらは、@property
アットルールまたはカスタムプロパティ構文(例: --primary-color: blue;
)を使用して設定します。 カスタムプロパティは、CSS の var()
関数(例: color: var(--primary-color);
)を使用してアクセスします。
複雑なウェブサイトには膨大な量の CSS が含まれており、その結果、CSS の値が重複することがよくあります。例えば、スタイルシートの異なる場所で同じ色が使用されていることはよくあります。多くの場所で重複している色を変更するには、すべてのルールと CSS ファイルを検索して置換する必要があります。カスタムプロパティを使用すると、値を 1 か所で定義し、他の複数の場所で参照できるため、作業が容易になります。また、可読性と意味づけも利点のひとつです。例えば、--main-text-color
は 16 進数表記のカラーコード #00ff00
よりも理解しやすく、特にその色が様々なコンテキストで使用される場合にはその傾向が顕著です。
ダッシュ 2 本 (--
) を使用して定義されたカスタムプロパティは、カスケードの対象となり、親から値を継承します。
@property
アットルールを使用すると、カスタムプロパティをより詳細に制御でき、親から値を継承するかどうか、初期値をどうするか、適用すべき型制約をどうするかを指定できます。
カスタムプロパティの宣言
CSS では、プロパティ名の接頭辞として ダッシュ 2 本を使用するか、@property
アットルールを使用してカスタムプロパティを宣言できます。
以下の項では、これら 2 つの方法について説明します。
ダッシュ 2 本 (--
) の接頭辞の使用
ダッシュ 2 本で始まるカスタムプロパティは、--
で始まってプロパティ名(例: --my-property
)が続くもので、有効な CSS 値であればどのような値でも指定できます。
他のプロパティと同様に、これはルールのセット内に記述します。次の例では、カスタムプロパティ --main-bg-color
を作成し、<named-color>
値として brown
を使用する方法を示しています。
section {
--main-bg-color: brown;
}
ルールセットに指定されたセレクター(例えば、上記の例では <section>
要素)は、カスタムプロパティを使用できるスコープを定義します。
このため、カスタムプロパティを :root
擬似クラスで定義し、グローバルに参照できるようにすることが一般的です。
:root {
--main-bg-color: brown;
}
常にこうしなければならないわけではありません。カスタムプロパティのスコープを制限する正当な理由があるかもしれません。
メモ:
カスタムプロパティの名前は大文字小文字を区別します。 — --my-color
は --My-color
とは別なカスタムプロパティとして扱われます。
@property
アットルールの使用
@property
アットルールを使用すると、カスタムプロパティの定義をより詳細に表現できるようになり、プロパティに関連付けられた型、既定値の設定、および継承の制御が可能になります。
次の例では、--logo-color
というカスタムプロパティが <color>
を期待するものとして作成されます。
@property --logo-color {
syntax: "<color>";
inherits: false;
initial-value: #c0ffee;
}
直接 CSS でなく JavaScript でカスタムプロパティを定義したり作業したりしたい場合は、そのために対応する API があります。 どのように動作するかについては、 CSS プロパティと値 API ページを参照してください。
var()
によるカスタムプロパティの参照
どの方法でカスタムプロパティを定義しても、標準プロパティ値の代わりに var()
関数の中でそのプロパティを参照することができます。
details {
background-color: var(--main-bg-color);
}
カスタムプロパティの第一歩
スタイルを設定する HTML から始めましょう。
コンテナーとして機能する <div>
があり、その中に子要素を記載します。その中には、入れ子になった要素もあります。
<div class="container">
<div class="one">
<p>One</p>
</div>
<div class="two">
<p>Two</p>
<div class="three">
<p>Three</p>
</div>
</div>
<input class="four" placeholder="Four" />
<textarea class="five">Five</textarea>
</div>
次の CSS を使用すると、クラスに基づいていくつかの異なる要素をスタイル設定することができます(下記では、色に焦点を当てるため、一部のレイアウトルールは表示されていません)。
クラスに応じて、cornflowerblue
または aquamarine
の要素に背景色を設定しています。
/* それぞれのクラスに、いくつかの色を設定 */
.one {
background-color: cornflowerblue;
}
.two {
color: black;
background-color: aquamarine;
}
.three {
background-color: cornflowerblue;
}
.four {
background-color: cornflowerblue;
}
.five {
background-color: cornflowerblue;
}
このようになるはずです。
これらのルール全体で繰り返される値をカスタムプロパティで置き換える機会があります。
.container
スコープで --main-bg-color
を定義し、その値を複数の場所で参照した後、更新されたスタイルは次のようになります。
/* ここで --main-bg-color を定義 */
.container {
--main-bg-color: cornflowerblue;
}
/* それぞれのクラスに、いくつかの色を設定 */
.one {
background-color: var(--main-bg-color);
}
.two {
color: black;
background-color: aquamarine;
}
.three {
background-color: var(--main-bg-color);
}
.four {
background-color: var(--main-bg-color);
}
.five {
background-color: var(--main-bg-color);
}
:root 擬似クラスの使用
CSS 宣言の中には、カスケードのより上位で宣言し、CSS 継承でこの問題を解決することが可能なものもあります。複雑なプロジェクトでは、常に可能であるとは限りません。CSS 作者は、:root
擬似クラスにカスタムプロパティを宣言し、文書内の必要な箇所でそれを使用することで、繰り返し記述の必要性を減らすことができます。
/* ここで --main-bg-color を定義 */
:root {
--main-bg-color: cornflowerblue;
}
/* それぞれのクラスに、いくつかの色を設定 */
.one {
background-color: var(--main-bg-color);
}
.two {
color: black;
background-color: aquamarine;
}
.three {
background-color: var(--main-bg-color);
}
.four {
background-color: var(--main-bg-color);
}
.five {
background-color: var(--main-bg-color);
}
これは前回と同じ結果になりますが、望ましいプロパティ値の標準的な宣言(--main-bg-color: cornflowerblue;
)が可能になり、これは後で自分のプロジェクト全体で値を変更したい場合にとても有益なものです。
カスタムプロパティの継承
カスタムプロパティは継承されます。これはつまり、もし与えられた要素にカスタムプロパティの値がない場合、その値は親の値を使用するということです。 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>
div {
background-color: var(--box-color);
}
.two {
--box-color: cornflowerblue;
}
.three {
--box-color: aquamarine;
}
var(--box-color)
の結果は次のように、継承状況によって変わります。
class="one"
: 無効値、これはすべてのカスタムプロパティの既定値です。class="two"
:cornflowerblue
class="three"
:aquamarine
class="four"
:cornflowerblue
(親から継承)
上記の例が示すカスタムプロパティの 1 つの側面は、他のプログラミング言語の変数とまったく同じには動作しないということです。 この値は、必要とされる場所で計算され、このスタイルシートの他の場所に保存されて再利用されることはありません。 例えば、プロパティの値を設定しても、兄弟の子孫のルールでその値を取得することはできません。 プロパティは、一致するセレクターとその子孫に対してのみ設定されます。
@property
を使用して継承を制御
@property
アットルールでは、プロパティを継承するかどうかを明示的に指定できます。
次の例では、@property
アットルールを使用してカスタムプロパティを作成しています。
継承は無効になっており、<color>
データ型が定義され、cornflowerblue
が初期値として設定されています。
親要素は、--box-color
の値を緑に設定し、--box-color
を背景色の値として使用します。
子要素も background-color: var(--box-color)
を使用しており、継承が有効になっている場合(または、ダッシュ 2 本の構文を使用して定義されている場合)には、green
色が設定されていることが期待されます。
<div class="parent">
<p>親要素</p>
<div class="child">
<p>子要素で、--box-color の継承が無効になっています。</p>
</div>
</div>
@property --box-color {
syntax: "<color>";
inherits: false;
initial-value: cornflowerblue;
}
.parent {
--box-color: green;
background-color: var(--box-color);
}
.child {
width: 80%;
height: 40%;
background-color: var(--box-color);
}
アットルールで inherits: false;
が設定されており、.child
スコープ内で --box-color
プロパティの値が宣言されていないため、親から継承されるはずの green
の代わりに cornflowerblue
の初期値が使用されます。
カスタムプロパティ代替値
カスタムプロパティの代替値は、var()
関数と @property
アットルールの initial-value
を使用して定義できます。
メモ: 代替値はブラウザーの互換性を修正するためには使用されません。ブラウザーが CSS カスタムプロパティに対応していない場合、代替値は助けになりません。 これは CSS カスタムプロパティに対応しているブラウザーのための単なるバックアップであり、与えられた変数が定義されていなかったり、無効な値であったりした場合に別な値を選択させるためのものです。
var()
関数の代替値の定義
var()
関数を使用して、指定された変数が定義されていない場合の代替値を複数定義することができます。カスタム要素およびシャドウ DOM で作業するときに便利なことがあります。
関数の最初の引数は、カスタムプロパティの名前です。関数の 2 番目の引数は、省略可能で、参照されたカスタムプロパティが無効であった場合に代わりに使用される代替値です。 この関数は引数を 2 つだけ受け付けるので、最初のカンマの後のものは、すべて 2 番目の引数として割り当てます。2 番目の引数が無効な場合、次のように代替処理は失敗します。
.one {
/* --my-var が定義されていなければ red */
color: var(--my-var, red);
}
.two {
/* my-var 及び --my-background が定義されていなければ pink */
color: var(--my-var, var(--my-background, pink));
}
.three {
/* 無効: "--my-background, pink" */
color: var(--my-var, --my-background, pink);
}
代替値としてのカスタムプロパティを含めるには、上記の 2 番目の例 (var(--my-var, var(--my-background, pink))
) のようにすることが、var()
で複数の代替値を提供するための正しい方法です。
ただし、階層化された変数の解析に時間がかかるため、この方法によるパフォーマンスへの影響を認識しておく必要があります。
メモ:
代替値の構文は、カスタムプロパティの場合のように、カンマを使用することができます。例えば、 var(--foo, red, blue)
は red, blue
という代替値を定義します。最初のカンマから関数の終わりまでが代替値とみなされます。
@property
の初期値を使用した代替値
var()
を使用する以外に、@property
アットルールで定義された initial-value
を代替メカニズムとして使用することができます。実際、これはすでに @property
の継承の節で見てきました。
次の例では、@property
アットルールを使用して、--box-color
の初期値を cornflowerblue
に設定しています。
アットルールに続くルールセットでは、--box-color
を aquamarine
に設定したいのですが、値の名前にタイプミスがあります。
3 番目の <div>
でも同じことが言有効な <color>
値を期待するカスタムプロパティに 2rem
を使用しています。
2rem
と aqumarine
はどちらもカラー値として無効であるため、cornflowerblue
の初期値が適用されます。
@property --box-color {
syntax: "<color>";
initial-value: cornflowerblue;
inherits: false;
}
.one {
--box-color: aquamarine;
background-color: var(--box-color);
}
.two {
--box-color: aqumarine;
background-color: var(--box-color);
}
.three {
--box-color: 2rem;
background-color: var(--box-color);
}
無効なカスタムプロパティ
CSS の各プロパティには、定義された値のセットを割り当てることができます。 プロパティに有効な値の集合から外れた値を割り当てた場合、そのプロパティは「無効」とみなされます。
ブラウザーが通常の CSS プロパティの無効な値(例えば、color
プロパティにおける 16px
という値)に遭遇すると、その宣言は破棄され、要素には宣言が存在しなかった場合の値が割り当てられます。
次の例では、通常のCSS宣言が無効である場合の挙動を示しています。 color: 16px;
は無視され、代わりに以前の color: blue
ルールが適用されます。
<p>この段落は初期状態で黒です。</p>
p {
color: blue;
}
p {
/* おっと、有効な色ではない */
color: 16px;
}
しかし、カスタムプロパティの値が解釈される際には、ブラウザーはまだそれらがどこで使用されるのかを知りません。そのため、ほぼすべての値を 有効 とみなさなければなりません。
残念ながら、これらの有効な値は、var()
関数記法によって、意味をなさない可能性のあるコンテキストで使用されてしまうことがあります。
プロパティとカスタム変数は、無効な CSS 文につながる可能性があり、「計算時に有効」という概念につながります。
ブラウザが無効な var()
置換に遭遇した場合は、プロパティの初期値または継承値が使用されます。
この例は、カスタムプロパティを使用している点を除いて、最後の例と同じです。
期待通りに、ブラウザーは --text-color
の値で var(--text-color)
の場所を置き換えようとしますが、 16px
は color
に妥当なプロパティ値ではありません。
置き換え後、プロパティは意味をなさなくなります。ブラウザーはこの状況を 2 段階で扱います。
color
プロパティが継承可能であるかを確認します。可能ですが、<p>
にはcolor
プロパティを持つ親がありません。よって次の段階に進みます。- 値を既定の初期値、つまり、黒に設定します。
<p>この段落は初期状態で黒です。</p>
:root {
--text-color: 16px;
}
p {
color: blue;
}
p {
color: var(--text-color);
}
このような場合、@property
アットルールを使用してプロパティの初期値を定義することで、予期せぬ結果を防ぐことができます。
<p>この段落は初期状態で黒です。</p>
@property --text-color {
syntax: "<color>";
inherits: false;
initial-value: cornflowerblue;
}
:root {
--text-color: 16px;
}
p {
color: blue;
}
p {
color: var(--text-color);
}
JavaScript での値
カスタムプロパティを JavaScript で使用するには、標準のプロパティのようにします。
// インラインスタイルから値を取得
element.style.getPropertyValue("--my-var");
// あらゆる場所の変数を取得
getComputedStyle(element).getPropertyValue("--my-var");
// インラインスタイルに値を設定
element.style.setProperty("--my-var", jsVar + 4);