CSSのカスタムプロパティ(通称:CSS変数)を使うと、色や余白といった値に名前を付けて、サイト全体で使い回せるようになります。同じ色コードをあちこちに書き散らす必要がなくなり、デザインの変更が一気に楽になります。この記事では、--変数名 での定義と var() での参照という基本から、フォールバック値、スコープ、JavaScriptからの操作、ダークモードへの応用までを、初心者の方にも分かりやすく解説します。
目次
CSS変数(カスタムプロパティ)とは
CSS変数とは、値に名前を付けて保存しておき、好きな場所から呼び出せる仕組みです。正式名称は「カスタムプロパティ(Custom Properties)」で、プログラミングの「変数」とよく似た使い方ができるため、一般的にはCSS変数と呼ばれています。
たとえばサイトのメインカラーを #4f46e5 に決めたとき、ボタン・見出し・リンクなど何十か所にもこの色コードを書くことになります。後から色を変えたくなったら、すべてを手作業で書き換えなければなりません。CSS変数を使えば、色を1か所にまとめて定義し、各所からその名前を参照するだけで済みます。変更時は定義を1行直すだけで全体に反映されます。
基本の使い方|変数の定義と var() での参照
CSS変数は「定義」と「参照」の2ステップで使います。定義はプロパティ名の先頭にハイフン2つ(--)を付けて行い、参照は var() 関数で行います。次の例を見てください。
:root {
/* 先頭に -- を付けて変数を定義する */
--main-color: #4f46e5;
}
.button {
/* var() で定義した変数を参照する */
background-color: var(--main-color);
}
このように --変数名: 値; の形で定義し、使うときは var(--変数名) と書きます。変数名は大文字・小文字を区別するので、--mainColor と --maincolor は別の変数として扱われる点に注意してください。値には色だけでなく、数値・文字列・10px のような単位付きの値など、CSSプロパティに指定できるものなら何でも入れられます。
:root に定義してサイト全体で使う
上の例で出てきた :root は、HTML文書の最上位(<html> 要素)を指す擬似クラスです。ここで定義した変数はページ全体に行き渡るため、サイト共通の色やサイズはまず :root にまとめておくのが定番のパターンです。
:root {
--main-color: #4f46e5; /* メインカラー */
--text-color: #333333; /* 本文の文字色 */
--radius: 8px; /* 角丸の大きさ */
--space: 16px; /* 基本の余白 */
}
.card {
color: var(--text-color);
border-radius: var(--radius);
padding: var(--space);
}
.card__title {
color: var(--main-color);
}
こうしておけば、メインカラーを変えたいときは --main-color の1行を書き換えるだけです。var() で参照しているすべての箇所に自動で反映されます。
動かして確認するデモ
実際の動きを下のデモで確認してみましょう。色・角丸・余白をすべて :root の変数で管理しています。ボタンを押すと、JavaScriptから変数の値を書き換えてカードの配色が切り替わります。CSSタブやJavaScriptタブを開いて、どこで変数を定義・参照しているかを見てみてください。
<div class="card">
<h2 class="card__title">CSS変数でテーマを管理</h2>
<p class="card__text">色や角丸、余白を1か所の変数でまとめて管理しています。下のボタンで配色を切り替えられます。</p>
<button class="card__btn" id="toggle">テーマカラーを切り替える</button>
</div>
/* :root にまとめて変数を定義(サイト全体で使える) */
:root {
--main-color: #4f46e5;
--text-color: #ffffff;
--radius: 12px;
--space: 24px;
}
body {
margin: 0;
padding: var(--space);
font-family: sans-serif;
background: #f5f5f7;
}
/* var() で変数を参照する */
.card {
background: var(--main-color);
color: var(--text-color);
border-radius: var(--radius);
padding: var(--space);
}
.card__title {
margin: 0 0 8px;
}
.card__text {
margin: 0 0 16px;
line-height: 1.7;
}
.card__btn {
/* 第2引数はフォールバック値。--btn-color が未定義なら #111 を使う */
background: var(--btn-color, #111111);
color: var(--text-color);
border: none;
border-radius: var(--radius);
padding: 10px 18px;
font-size: 15px;
cursor: pointer;
}
const btn = document.getElementById("toggle");
let dark = false;
btn.addEventListener("click", () => {
dark = !dark;
// JavaScript から :root の変数を書き換える
const root = document.documentElement;
if (dark) {
root.style.setProperty("--main-color", "#0f172a");
root.style.setProperty("--btn-color", "#38bdf8");
} else {
root.style.setProperty("--main-color", "#4f46e5");
root.style.setProperty("--btn-color", "#111111");
}
});
var() の第2引数(フォールバック値)
var() には2つ目の引数を渡すことができ、これを「フォールバック値」と呼びます。これは「指定した変数が定義されていない(または無効な)ときに代わりに使う値」です。書式は var(--変数名, フォールバック値) です。
.button {
/* --btn-color が未定義なら #111 が使われる */
background-color: var(--btn-color, #111111);
/* フォールバックにも var() を入れ子にできる */
color: var(--btn-text, var(--text-color, #fff));
}
フォールバック値があると、変数が用意されていない環境でも最低限のスタイルが保たれます。コンポーネントを部品として配布する場合など、外部から変数が渡されるかどうか分からないときに役立ちます。なお、フォールバック値の中にカンマを含めることも可能で、その場合は最初のカンマ以降がすべてフォールバック値として扱われます。
スコープ|要素ごとに変数を上書きする
CSS変数には「スコープ」があります。変数は定義した要素と、その子孫要素の中でだけ有効です。これは通常のCSSと同じ「継承(カスケード)」の仕組みに従っているためで、同じ名前の変数を特定の要素で再定義すると、その要素の内側だけ値が上書きされます。
:root {
--label-color: #4f46e5; /* 全体のデフォルト */
}
.badge {
color: var(--label-color);
}
/* .badge--warning の中だけ変数を上書きする */
.badge--warning {
--label-color: #e11d48;
}
この例では、通常の .badge は :root の青系の色を使いますが、.badge--warning が付いた要素では --label-color が赤系に上書きされます。color: var(--label-color) という記述を書き換えずに、変数の値だけを差し替えて見た目を変えられるのがポイントです。このスコープの仕組みは、後で紹介するダークモードの切り替えでも活躍します。
JavaScriptから変数を読み書きする
CSS変数の大きな特徴のひとつが、JavaScriptから動的に読み書きできることです。値の取得には getPropertyValue()、設定には setProperty() を使います。どちらも要素の style オブジェクトのメソッドです。
const root = document.documentElement; // :root(html要素)
// 変数を書き換える(要素のインラインスタイルとして設定される)
root.style.setProperty("--main-color", "#0f172a");
// 設定したインラインスタイルの変数を読み取る
const value = root.style.getPropertyValue("--main-color");
console.log(value); // "#0f172a"
setProperty() で設定した値は、その要素のインラインスタイルとして適用されます。先ほどのデモのボタンも、この setProperty() で :root の変数を書き換えることで配色を切り替えていました。なお、CSSファイルやスタイルシートで定義した変数の「計算後の値」を取得したい場合は、getComputedStyle(要素).getPropertyValue("--変数名") を使います。
実践|ダークモードとテーマ色の一括管理
CSS変数が特に力を発揮するのが、ダークモードのような「配色のまるごと切り替え」です。色を直接書くのではなく変数を経由しておけば、変数の定義をまとめて差し替えるだけでサイト全体の見た目を切り替えられます。
たとえば <html> 要素に data-theme="dark" という属性を付けたときだけ変数を上書きする、という方法がよく使われます。テーマの切り替えはJavaScriptでこの属性を付け外しするだけで済みます。
:root {
--bg: #ffffff;
--text: #1a1a1a;
}
/* ダークテーマのときだけ変数を上書き */
:root[data-theme="dark"] {
--bg: #0f172a;
--text: #e2e8f0;
}
body {
background-color: var(--bg);
color: var(--text);
}
OSやブラウザのダークモード設定に自動で合わせたいときは、prefers-color-scheme メディアクエリの中で変数を定義する方法も便利です。ユーザーの環境設定に応じて、追加のJavaScriptなしに配色を切り替えられます。
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f172a;
--text: #e2e8f0;
}
}
変数が反映されないときに確認すること
「変数を定義したのにスタイルが効かない」というつまずきは、原因がいくつかのパターンに絞られます。デベロッパーツールで対象要素を選び、変数が反映されているかを確認しながら、次の点をチェックしてみてください。
変数名のタイプミス・ハイフンの数
もっとも多いのが綴りの間違いです。定義側が --main-color なのに参照側で --mein-color と書いていたり、先頭のハイフンが1つしかない、といったケースです。CSS変数は大文字・小文字も区別するため、--mainColor と --maincolor も別物として扱われます。定義と参照の文字列が完全に一致しているか確認しましょう。
スコープの外から参照している
変数は定義した要素とその子孫でしか有効ではありません。たとえばある要素の中だけで定義した変数を、その外側の要素から参照しても効きません。サイト全体で使いたい変数は :root に定義するのが基本です。意図せず狭いスコープで定義していないか見直してみてください。
無効な値が入っていてフォールバックも未指定
変数に代入した値が、使う場所のプロパティにとって無効な場合(たとえば色のプロパティに数値だけが入っているなど)、その指定は無効になります。フォールバック値を指定していないと、プロパティの初期値や継承値が使われてしまい、期待した見た目になりません。値の単位や形式が、参照先のプロパティに合っているかを確認しましょう。
var() なしで変数名を直接書いている
CSS変数は必ず var() 関数を通して参照します。color: --main-color; のように var() を付けずに変数名を直接書いても値にはならず、無効な指定として無視されます。参照するときは color: var(--main-color); と書く必要があることを覚えておきましょう。
覚えておきたい書式のまとめ
最後に、この記事で登場した書式とメソッドを一覧で振り返ります。
| 書式・メソッド | 説明 |
|---|---|
--変数名: 値; | カスタムプロパティ(CSS変数)を定義する |
var(--変数名) | 定義した変数を参照する |
var(--変数名, フォールバック値) | 変数が未定義・無効なときに使う値を指定する |
:root { ... } | 文書全体で使える変数を定義する場所 |
element.style.setProperty("--名", 値) | JavaScriptから変数を書き換える |
element.style.getPropertyValue("--名") | JavaScriptから変数の値を読み取る |
CSS変数は、色やサイズを1か所で管理してデザインの変更を楽にし、スコープによる部分的な上書きやJavaScriptとの連携で、ダークモードのような動的な切り替えまで実現できる強力な仕組みです。まずは :root にメインカラーや余白を定義し、var() で参照するところから始めてみてください。