CSS講座 / CSS変数:var()・スコープ・継承・フォールバック
CSSカスタムプロパティは、再利用する値を保存し、プロパティの値の中でvar()から参照する仕組みです。適用範囲はカスケードと継承に従い、定義済みの値が用途に合わない場合までフォールバックが救うわけではありません。
役割が分かる共通変数を選ぶ
同じ役割の色や余白を複数箇所で使うなら変数へまとめると変更点を減らせます。一か所でしか使わず意味も共有しない値まで変数にすると、名前を追う負担が増えます。
:root {
--accent: #1d5f91;
--space-unit: .5rem;
}
.button { color: white; background: var(--accent); }
.card { border: 2px solid var(--accent); padding: calc(var(--space-unit) * 3); }
変数を宣言するだけでは見た目は変わりません。backgroundやborderなどから参照します。--blueより--accentのように役割で名付けると、色を変えても意味が残ります。--accentと--Accentは別名です。
var()はcolorやpaddingなどの値に使います。セレクターやプロパティ名を置換したり、@mediaやサイズコンテナークエリーの境界値へそのまま使ったりする仕組みではありません。条件と、条件内の要素へ適用する色・余白を分けます。
root・継承・部品内の範囲を確認する
HTML文書の:rootは最上位のHTML要素に一致し、全体の基本値を置くのに便利です。通常の--カスタムプロパティは子孫へ継承されます。カード内の値はその子へ渡せますが、無関係な兄弟カードには渡りません。
.card { --card-accent: var(--accent); }
.card.warning { --card-accent: #a63e32; }
.card { border-color: var(--card-accent); }
.card h2 { color: var(--card-accent); }
.card.warningは同じ要素の両クラスへ一致します。HTMLのclassの並びではなく、カスケードと詳細度で値が決まります。全体のaccentを変えても、独自のcard-accentを持つ警告カードは警告色を維持できます。
--line-color: var(--accent)を親で計算して継承した場合、子でaccentだけを変えてもline-colorが常に再計算されるわけではありません。子の色へ連動させたい派生値は、その要素で宣言するか実際のプロパティから直接参照します。CSSカスタムプロパティ仕様を参照してください。
未定義の代替と計算時の無効を区別する
var(--notice-color, #6a3989)は使える変数値がないとき紫を代替にします。しかしnotice-colorが20pxと定義されていれば、値は代入され、colorに合わないため計算時に無効になります。「紫へ置き換わる」とは限りません。
.sample {
color: #1d5f91;
color: var(--notice-color, #6a3989);
}
.sample.bad { --notice-color: 20px; }
完全例では、未定義は紫、redは赤、20pxはcolorの継承規則により親の緑になります。同じルール内の先行する青へ戻るわけでもありません。選ばれた宣言が計算時に無効になった後、継承するプロパティかどうかなどの規則で処理されます。MDNのカスタムプロパティを参照してください。
代替にはvar(--button-accent, var(--accent, #1d5f91))のように別のvarも書けます。ただし定義値の用途が混ざる問題は同じなので、色・長さ・数値を名前と用途で管理します。
calc()で値と単位を計算する
--space-unit: .5remを三倍すれば、ルートのサイズへ連動する余白を作れます。文字列として単位を連結するのではなく、calc()で計算します。加算・減算の演算子の前後には空白を入れます。
:root {
--space-unit: .5rem;
--space-card: calc(var(--space-unit) * 3);
}
.card { padding: var(--space-card); }
単位込みの長さを保存するか、単位のない数値を保存するかをそろえます。長さのつもりで2だけを代入したり、色の変数を算術へ使ったりすると用途に合いません。MDNのcalc()、色と単位を参照してください。
完全例で範囲と代替を比較する
次をcustom-properties.htmlとして保存します。二つのカードと三つの文章を比較し、色だけに頼らず結果の意味も文章で読める構成です。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS variable scope and substitution values</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; padding: 1rem; color: #183044; font-family: sans-serif; line-height: 1.6; }
main { max-width: 46rem; margin-inline: auto; }
h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; }
button, input { font: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 3px solid #164f73; outline-offset: 3px; }
:root { --space-unit: .5rem; --space-card: calc(var(--space-unit) * 3); --accent: #1d5f91; }
.cards { display: grid; gap: 1rem; }
.card { --card-accent: var(--accent); padding: var(--space-card); border: 2px solid var(--card-accent);
border-radius: .5rem; background: #f6f9fb; }
.card h2 { color: var(--card-accent); margin-block: 0 .5rem; }
.card p { margin: 0; }
.card.warning { --card-accent: #a63e32; }
.fallback-area { margin-block: 2rem; padding: 1rem; border: 1px solid #8a9ba7; color: #28633b; }
.sample { color: #1d5f91; color: var(--notice-color, #6a3989); }
.sample.bad { --notice-color: 20px; }
.sample.good { --notice-color: #a63e32; }
</style>
</head>
<body>
<main>
<h1>Variable scope and fallbacks</h1>
<div class="cards">
<article class="card"><h2>Basic card</h2><p>The heading and border share the same accent color.</p></article>
<article class="card warning"><h2>warning card</h2><p>The accent color changes only inside this card.</p></article>
</div>
<section class="fallback-area">
<h2>The parent's text color is green</h2>
<p class="sample missing">Undefined: purple fallback</p>
<p class="sample bad">20px: Doesn't match the color, so it inherits the green color from the parent.</p>
<p class="sample good">Defined as red: use that color</p>
</section>
</main>
</body>
</html>
標準カードの見出しと枠は青、警告カードは赤です。三つの文は紫・緑・赤になります。rootのaccentだけを#28633bへ変え、標準カードだけが追従するか確認して#1d5f91へ戻します。
space-unitだけを1remへ変えて両カードの余白を比べ、.5remへ戻します。.badのnotice-colorを20pxから#1d5f91へ変えると緑から青へ変わります。20pxへ戻してから宣言だけを削除すると、今度は紫の代替が使われます。比較後は元の宣言を復元します。
値が見つからない・違うときの確認
開発者ツールで、その要素に実際の変数名と値があるかを確認します。綴り、大文字小文字、宣言した範囲、子孫や別ルールの上書きを見ます。参照自体が実際のプロパティにあるか、代入後の型と単位が合うかも調べます。
複数の変数を経由するなら、どの要素で計算された値を継承したかを追います。自分自身や循環する変数への参照も避けます。共通値と部品固有の例外を分け、共有する範囲を明確にすることが保守に役立ちます。




