テクニック

CSS変数(カスタムプロパティ)の実践的な使い方【コード付き】

この記事の対象: CSS変数を実務で活用したいフロントエンドエンジニア
読了時間: 約7分

CSS変数(カスタムプロパティ)は、CSSの中で値を変数として定義し再利用できる機能です。色やフォントサイズ、余白などを一元管理でき、テーマ切り替えやレスポンシブ対応が格段に楽になります。2026年時点ではモダンブラウザで枯れた機能となり、@propertyによるアニメーション制御やコンテナクエリとの組み合わせなど、実務での使い方も一段階進んでいます。この記事では基本構文から実践パターン、Soreiine!!ギャラリー掲載サイトでの活用例までをコード付きで解説します。


CSS変数(カスタムプロパティ)とは

CSS変数は--で始まる名前を持つプロパティで、var()関数で参照します。Chrome・Safari・Firefox・Edgeの現行バージョンはすべて問題なく対応しており、実務での採用に迷う段階はすでに終わっています。IE11のサポートが必須の案件でのみ、フォールバック用にSass変数や固定値との併用を検討してください。

Sass変数と混同されがちですが、決定的な違いは「ブラウザ上で動的に変更できる」点です。コンパイル時に固定されるSass変数と違い、CSS変数はメディアクエリの内側で値を切り替えたり、JavaScriptから書き換えたりできます。この特性が、ダークモードやテーマ切り替えの実装を大きく簡略化します。


基本構文

/* 変数の定義(:rootで全体に適用) */
:root {
  --color-primary: #3b82f6;
  --color-text: #1a1a2e;
  --font-size-base: 16px;
  --spacing-md: 24px;
}

/* 変数の使用 */
.button {
  background-color: var(--color-primary);
  color: #fff;
  padding: var(--spacing-md);
  font-size: var(--font-size-base);
}

/* フォールバック値(変数が未定義の場合の初期値) */
.card {
  border-color: var(--color-border, #e5e7eb);
}

実装のポイント: :rootはドキュメント全体のルート要素を指すセレクタで、ここに変数を定義するとサイト全体から参照できます。フォールバック値(第2引数)は、変数名のタイプミスや、コンポーネント単位で変数が未定義のケースに備えて付けておくと事故が減ります。

つまずきやすい点: CSS変数名は大文字・小文字を区別します。--Color-Primaryと--color-primaryは別物として扱われるため、命名規則をチーム内で統一しておくことが重要です。

基本構文を押さえたところで、次は実務でよく効く典型パターンを見ていきます。スクロール追従など、似た文脈でCSSの挙動につまずきやすい実装として「position:stickyが効かない原因と直し方|スティッキー 追従 CSS position sticky 実装ガイド」もあわせて押さえておくと、レイアウト系の詰まりに強くなります。


実践パターン6選

①テーマカラーの一括管理

:root {
  --color-primary: #3b82f6;
  --color-primary-dark: #2563eb;
  --color-secondary: #10b981;
  --color-bg: #ffffff;
  --color-text: #1a1a2e;
  --color-text-muted: #6b7280;
  --color-border: #e5e7eb;
}

.btn-primary {
  background: var(--color-primary);
}
.btn-primary:hover {
  background: var(--color-primary-dark);
}

ブランドカラーを変更する場合、:rootの値を変えるだけでサイト全体に反映されます。リニューアル時の配色差し替えや、複数ブランドを1つのコードベースで運用するマルチテナント構成でも威力を発揮します。

②ダークモード切り替え

:root {
  --color-bg: #ffffff;
  --color-text: #1a1a2e;
  --color-surface: #f9fafb;
}

[data-theme="dark"] {
  --color-bg: #0f172a;
  --color-text: #e2e8f0;
  --color-surface: #1e293b;
}

body {
  background: var(--color-bg);
  color: var(--color-text);
}

HTML要素にdata-theme="dark"を付与するだけで、CSS変数の値が切り替わりダークモードになります。OSの設定に連動させたい場合はprefers-color-schemeメディアクエリと組み合わせるのが定番です。ダークモードの設計思想については「ダークモード対応のUIデザイン設計」で詳しく解説しています。

③レスポンシブのフォントサイズ管理

:root {
  --font-size-h1: 2rem;
  --font-size-h2: 1.5rem;
  --font-size-body: 1rem;
  --spacing-section: 48px;
}

@media (min-width: 768px) {
  :root {
    --font-size-h1: 3rem;
    --font-size-h2: 2rem;
    --spacing-section: 80px;
  }
}

h1 { font-size: var(--font-size-h1); }
h2 { font-size: var(--font-size-h2); }
section { padding: var(--spacing-section) 0; }

メディアクエリでCSS変数の値だけを変更すれば、使用しているすべての場所に反映されます。h1やsectionのセレクタを個別にメディアクエリで書き直す必要がなくなるため、ブレークポイントが増えるほど恩恵が大きくなります。

変数の変更が波及する範囲

:root(変数定義)

  • h1, h2 のfont-size
  • sectionのpadding
  • buttonのbackground

メディアクエリ内で上書き

  • 768px以上で値だけ変更
  • 参照側のCSSは無変更

個々のセレクタを書き換えず、変数の定義元だけを触れば全体に波及する。

④コンポーネントのバリエーション管理

.card {
  --card-padding: 24px;
  --card-radius: 12px;
  --card-bg: var(--color-surface);

  padding: var(--card-padding);
  border-radius: var(--card-radius);
  background: var(--card-bg);
}

.card--compact {
  --card-padding: 16px;
  --card-radius: 8px;
}

.card--featured {
  --card-bg: var(--color-primary);
  color: #fff;
}

バリエーションごとに変数の値だけをオーバーライドすることで、コンポーネントの見た目を柔軟に変更できます。修飾クラスを増やすたびにプロパティを丸ごと書き直す必要がなく、差分だけを記述できるのが利点です。カードのホバー演出まで含めて整理したい場合は「ホバーアニメーションのCSS実装|カードでやりすぎない基準」もあわせて参考にしてください。

⑤JavaScriptとの連携

// CSS変数の値をJSから取得
const primary = getComputedStyle(document.documentElement)
  .getPropertyValue('--color-primary');

// CSS変数の値をJSから変更
document.documentElement.style.setProperty('--color-primary', '#ef4444');

JavaScriptからCSS変数を読み書きできるため、ユーザー操作に応じたテーマ変更やアニメーション制御が可能です。カラーピッカーでリアルタイムにテーマ色をプレビューする機能や、スクロール位置に応じて変数を書き換える演出などに使われます。

つまずきやすい点: getPropertyValueで取得した値には前後の空白が含まれることがあります。数値として計算に使う場合は.trim()してからparseFloat()する処理を挟んでください。

⑥@propertyによるアニメーション対応(追加)

従来のCSS変数は「ただの文字列置換」に近い挙動のため、グラデーションの角度や数値をアニメーションさせようとしてもtransitionが効かないという制約がありました。@propertyを使うと型を明示でき、この問題を解消できます。

@property --gradient-angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}

.hero {
  background: linear-gradient(var(--gradient-angle), #3b82f6, #10b981);
  transition: --gradient-angle 0.6s ease;
}

.hero:hover {
  --gradient-angle: 180deg;
}

syntaxで型(<angle>や<color>、<number>など)を指定することで、ブラウザが値を補間できるようになり、変数そのものをアニメーションさせられます。対応ブラウザはChrome・Edge・Safariの現行バージョンです。Firefoxは執筆時点で部分対応のため、演出の主役にする場合はフォールバックを用意してください。


Sass変数との使い分け

CSS変数とSass変数、どちらを選ぶか

CSS変数を選ぶ

  • ダークモードなど動的切り替えが要る
  • メディアクエリ内で値を変えたい
  • JavaScriptから読み書きしたい
  • アニメーションさせたい(@property併用)

Sass変数を選ぶ

  • ビルド時に確定していい設定値
  • mixinやループでの計算が中心
  • プリプロセッサ環境がすでにある
CSS変数 Sass変数
動的変更 ブラウザで変更可能 コンパイル時に固定
メディアクエリ 内部で値を変更可能 不可
JSからのアクセス 可能 不可
ブラウザ対応 全モダンブラウザ対応 プリプロセッサ不要
計算 calc()と組み合わせ ネイティブの算術演算
アニメーション @propertyで対応可能 不可(静的値のため)

2026年の実務では、テーマカラーやレスポンシブ値など動的に変更する可能性のあるものはCSS変数、コンパイル時の設定値やmixinの計算はSassという住み分けが定着しています。両者は排他ではなく、Sassでビルドしたファイル内でCSS変数を定義・参照する構成も一般的です。


Soreiine!!ギャラリーに見るCSS変数の使いどころ

CSS変数がどこで効いてくるかは、実際のサイトの実装パターンを見た方がわかりやすくなります。Soreiine!!ギャラリーに掲載されているサイトを横断して見ていくと、テーマ設計にCSS変数が使われていると判断できる実装には共通した型があります。

複数カラーバリエーションを展開するブランドサイトでは、商品カテゴリごとにアクセントカラーが切り替わる作りがよく見られます。こうした実装は、ページ単位やセクション単位のルート要素で--color-accentのような変数を上書きし、ボタンやタグのスタイルはそのまま参照する構成にしておくと、カテゴリが増えるたびにCSSを複製せずに済みます。具体的には、<body data-category="furniture">のようにカテゴリをdata属性で持たせ、[data-category="furniture"] { --color-accent: #b45309; }のようにルート直下で上書きする形が典型です。ページ数の多いコーポレートサイトやECサイトほど、この設計の有無が保守コストの差になって表れます。

もう一つよく見かけるのが、セクションごとに余白のリズムを変えているLPです。見出し直下は詰めて、セクション間は大きく空けるといった強弱を、--spacing-sectionのような変数で一元管理しておくと、後からリズムを調整するときにCSS全体を探し回らずに済みます。ギャラリーで縦に長いLPを見るときは、DevToolsのComputedタブで--spacing-sectionのような変数が定義されているかを確認すると、余白設計が変数化されているかどうかが一目で分かります。


よくある質問

CSS変数はどこまで古いブラウザに対応していますか?

Chrome・Safari・Firefox・Edgeの現行バージョンはすべて問題なく対応しています。IE11のサポートが必須の案件でのみ、フォールバック用にSass変数や固定値との併用を検討してください。

CSS変数とSass変数はどちらを使えばいいですか?

動的に切り替える必要があるならCSS変数、ビルド時に確定していい設定値やmixinの計算が中心ならSass変数を選びます。両者は併用可能で、Sassのビルド出力の中でCSS変数を定義する構成もよく使われます。

CSS変数はどのくらいパフォーマンスに影響しますか?

一般的な使用量(数十〜数百個の変数定義)であれば、レンダリングパフォーマンスへの実務上の影響はほぼありません。ただし大量の要素で頻繁にJavaScriptから書き換えると再計算コストが発生するため、アニメーション用途では@propertyとの組み合わせで最適化する方が安全です。

--で始まる名前以外に制約はありますか?

変数名には大文字・小文字の区別があり、--Colorと--colorは別の変数として扱われます。ハイフンで区切るケバブケース(--color-primaryなど)に統一しておくと、チーム開発でのタイポ事故を防げます。

変数が効かないときの原因は何が多いですか?

多くは定義スコープの問題です。:rootではなく特定のクラス内で定義した変数は、そのクラスの子孫要素からしか参照できません。開発者ツールのComputedタブで変数の実際の値を確認し、定義箇所とスコープを見直してください。


まとめ

CSS変数のポイントをまとめます。

  • :rootでグローバルに定義し、var()で参照する
  • テーマカラーの一括管理で保守性が大幅に向上する
  • ダークモード切り替えがCSS変数で簡潔に実装できる
  • メディアクエリ内で値を変更してレスポンシブ対応できる
  • JavaScriptとの連携でインタラクティブな表現も可能
  • @propertyを使えば変数そのものをアニメーションさせられる

CSS変数を軸にしたコンポーネント設計は、フォームやモーダルなど他のUIパーツにも応用が効きます。実装の幅を広げたい場合は「フォームのCSS実装|入力しやすい設計とエラー表示まで」もあわせてご覧ください。