WithCodeMedia-1-pc
previous arrowprevious arrow
next arrownext arrow

WithCodeMedia-1-sp
previous arrowprevious arrow
next arrownext arrow

CSSカスタムプロパティ(変数)の使い方|保守しやすいスタイル設計の実践ガイド

生徒

CSSって色やサイズを何度も同じ値で書いていて、修正するたびに全部探して直すのが大変です…。変数みたいな仕組みってCSSにもあるんですか?

ペン博士

もちろんあります!「CSSカスタムプロパティ」を使えば、色・サイズ・余白などの値を一元管理できて、修正もラクラク。この記事では定義の書き方からスコープ・ダークモード切り替えまで、実例つきで丁寧に解説しますよ。

CSSを書いていると、同じカラーコードやフォントサイズを何十箇所にも繰り返してしまい、「デザインを少し変えるだけで修正が大量に発生する」という経験をしたことはないでしょうか。そんな悩みを解決するのがCSSカスタムプロパティ(CSS変数)です。SassやLessといったプリプロセッサを使わなくても、純粋なCSSだけで値を変数として管理でき、保守性・再利用性が格段に向上します。本記事では、CSSカスタムプロパティの基本的な書き方から、スコープの考え方、テーマ切り替えへの応用まで、実際のコードを交えながら体系的に解説します。


目次

CSSカスタムプロパティとは?基本の仕組みをおさらい

CSSカスタムプロパティとは、開発者が自分で定義できる「CSS専用の変数」です。正式名称は CSS Custom Properties for Cascading Variables といい、主要ブラウザはすべてサポート済みで、現在の実務でも標準的に使われる技術です。プロパティ名の先頭に必ず --(ダブルハイフン)を付けて定義し、var() 関数で参照します。

基本の構文

定義と参照の基本パターンは以下のとおりです。

/* カスタムプロパティの定義 */
:root {
  --color-primary: #3a86ff;
  --font-size-base: 16px;
  --spacing-md: 24px;
}

/* 参照(var()関数を使う) */
.button {
  background-color: var(--color-primary);
  font-size: var(--font-size-base);
  padding: var(--spacing-md);
}

:root はHTML文書全体のルート要素(<html>)を指す疑似クラスです。ここに定義することで、サイト全体からアクセスできるグローバル変数として機能します。

SassなどのプリプロセッサとCSSカスタムプロパティの違い

比較項目 Sass変数($var) CSSカスタムプロパティ(–var)
実行タイミング コンパイル時(静的) ブラウザ実行時(動的)
JavaScriptからの操作 不可 可能
スコープ ファイル・ブロックスコープ DOMツリーに基づくカスケード
メディアクエリ内での再定義 不可 可能
ビルドツール不要 要Sassコンパイラ 不要(純粋CSS)

最大の差は「ブラウザ上でリアルタイムに値が変わる」という点です。JavaScriptと組み合わせることで、ダークモード切り替えやアニメーション制御など、インタラクティブなUIにも活用できます。


スコープを理解する|グローバル変数とローカル変数

CSSカスタムプロパティは、定義したセレクターの子孫要素にのみ有効という「スコープ(有効範囲)」を持つのが特徴です。この仕組みを理解することで、意図しない値の上書きを防ぎ、コンポーネント単位での設計が可能になります。

グローバルスコープ(:rootに定義)

サイト全体で共通して使う値は :root に定義します。ブランドカラー・ベースフォントサイズ・共通スペーシングなどが代表例です。

:root {
  --color-brand: #ff6b6b;
  --color-text: #333333;
  --color-bg: #ffffff;
  --radius-base: 8px;
}

ローカルスコープ(コンポーネント単位で定義)

特定のコンポーネント内だけで使う値は、そのコンポーネントのセレクターに定義します。グローバル変数を上書きして、コンポーネント内だけ見た目を変えることも可能です。

/* カードコンポーネント内だけ背景色を変える */
.card {
  --color-bg: #f8f9fa; /* :rootの値をローカルで上書き */
  background-color: var(--color-bg);
  border-radius: var(--radius-base);
  padding: 24px;
}

この設計パターンにより、グローバルな一貫性を保ちながら、コンポーネントごとの柔軟なカスタマイズが実現できます。


var()関数の応用|フォールバック値と計算式との組み合わせ

CSSカスタムプロパティの参照に使う var() 関数には、変数が未定義の場合に使用する「フォールバック値」を設定できます。また、calc() と組み合わせることで、より柔軟なレイアウト設計が可能です。

フォールバック値の設定

var() の第2引数にフォールバック値を指定します。変数が定義されていない環境でも安全にスタイルが適用されるため、コンポーネントライブラリを作る際には必須のテクニックです。

.button {
  /* --color-accentが未定義の場合は #ffbf00 を使用 */
  background-color: var(--color-accent, #ffbf00);
  color: var(--color-button-text, #ffffff);
}

/* フォールバックに別の変数を指定することも可能 */
.heading {
  color: var(--color-heading, var(--color-text, #333));
}

calc()との組み合わせ

変数で基準値を定義しておき、calc() で計算することで、スケーラブルなタイポグラフィやスペーシングシステムを構築できます。

:root {
  --spacing-unit: 8px;
}

.section {
  padding: calc(var(--spacing-unit) * 4);    /* 32px */
  margin-bottom: calc(var(--spacing-unit) * 6); /* 48px */
}

.icon {
  width: calc(var(--spacing-unit) * 3);      /* 24px */
  height: calc(var(--spacing-unit) * 3);
}

基準となる --spacing-unit を変えるだけで、関連するすべての余白が自動的に更新されます。デザインシステムの構築や、レスポンシブ対応に非常に効果的です。


実践:ダークモード切り替えをCSSカスタムプロパティで実装する

CSSカスタムプロパティの最も代表的な応用例が「ダークモード切り替え」です。クラスの付け替えだけで全体のテーマカラーが一括変更できるのは、カスタムプロパティならではのメリットです。

CSSのみで実装するパターン(メディアクエリ使用)

:root {
  --color-bg: #ffffff;
  --color-text: #333333;
  --color-surface: #f4f4f4;
}

/* OSのダークモード設定に自動対応 */
@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #1a1a2e;
    --color-text: #e0e0e0;
    --color-surface: #16213e;
  }
}

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

.card {
  background-color: var(--color-surface);
}

JavaScriptで手動切り替えするパターン

ボタン操作でテーマを切り替える場合は、data-theme 属性やクラスと組み合わせる方法が一般的です。

/* CSSでテーマを定義 */
:root {
  --color-bg: #ffffff;
  --color-text: #333333;
}

[data-theme="dark"] {
  --color-bg: #1a1a2e;
  --color-text: #e0e0e0;
}
// JavaScriptでdata-theme属性を切り替え
const toggleBtn = document.getElementById('theme-toggle');
toggleBtn.addEventListener('click', () => {
  const current = document.documentElement.getAttribute('data-theme');
  document.documentElement.setAttribute(
    'data-theme',
    current === 'dark' ? 'light' : 'dark'
  );
});

CSS変数の値だけを切り替えるので、コンポーネント側のCSSは一切変更不要。コードの変更箇所が最小限で済み、バグが発生しにくい設計を実現できます。


保守しやすいスタイル設計のための命名規則と管理ルール

カスタムプロパティの強みを最大限に活かすには、命名規則と管理ルールを最初に決めておくことが不可欠です。チーム開発では特に、誰が見ても意味がわかる命名が保守性を左右します。

推奨する命名パターン

  • カテゴリー-役割-状態:--color-primary--color-primary-hover--color-text-muted のようにカテゴリーを先頭に置く
  • コンポーネントスコープ変数はプレフィックスを付ける:--btn-bg--card-padding のようにコンポーネント名を接頭辞にする
  • セマンティックな名前を優先:--color-red より --color-danger--color-blue より --color-link のほうが意図が伝わる
  • スケール系は数値サフィックスを使う:--font-size-sm--font-size-md--font-size-lg--spacing-2--spacing-4 など段階的に定義する

デザイントークンとして管理する

規模の大きいプロジェクトでは、カスタムプロパティを「デザイントークン」として1ファイル(例:tokens.css)に集約するのがベストプラクティスです。

/* tokens.css */
:root {
  /* ===== Color Tokens ===== */
  --color-brand-primary: #3a86ff;
  --color-brand-secondary: #ff6b6b;
  --color-text-default: #333333;
  --color-text-muted: #888888;
  --color-bg-default: #ffffff;
  --color-bg-surface: #f8f9fa;
  --color-border: #dddddd;

  /* ===== Typography Tokens ===== */
  --font-family-base: 'Noto Sans JP', sans-serif;
  --font-size-xs: 12px;
  --font-size-sm: 14px;
  --font-size-md: 16px;
  --font-size-lg: 20px;
  --font-size-xl: 24px;
  --font-size-2xl: 32px;
  --line-height-base: 1.7;

  /* ===== Spacing Tokens ===== */
  --spacing-1: 4px;
  --spacing-2: 8px;
  --spacing-4: 16px;
  --spacing-6: 24px;
  --spacing-8: 32px;
  --spacing-12: 48px;

  /* ===== Border & Radius ===== */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 16px;
  --radius-full: 9999px;

  /* ===== Shadow ===== */
  --shadow-sm: 0 1px 3px rgba(0,0,0,0.1);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.15);
}

このファイルを最初に読み込んでおけば、あとはすべてのコンポーネントからトークンを参照するだけ。デザイン変更の影響範囲が明確になり、修正コストを大幅に削減できます。


よくある落とし穴と注意点

CSSカスタムプロパティを使う上で、初心者がつまずきやすいポイントを整理しておきます。

注意すべき3つのポイント

  • 大文字・小文字は区別される:--Color-Primary--color-primary は別の変数として扱われます。命名は統一ルールで小文字ケバブケース(--color-primary)に揃えることを推奨します。
  • shorthandプロパティで部分的に使う場合は注意:border: var(--border-width) solid var(--color-border) のように分割して記述しないと、意図しない結果になることがあります。
  • 未定義の変数はinheritされない:変数が未定義のまま var() で参照すると、プロパティ全体が無効(unset相当)になります。フォールバック値を設定するか、@property ルールで型定義しておきましょう。

@propertyで型を定義する(モダンな書き方)

Chrome・Edge・Safariなど主要ブラウザが対応済みの @property を使うと、変数の型・初期値・継承の有無を明示できるため、より堅牢な設計が実現します。特にCSSアニメーション(@keyframes)で変数を補間したい場合に有効です。

@property --progress-value {
  syntax: '';
  inherits: false;
  initial-value: 0;
}

.progress-bar {
  --progress-value: 75;
  width: calc(var(--progress-value) * 1%);
  transition: --progress-value 0.5s ease;
}

まとめ

CSSカスタムプロパティは、Sassなどのビルドツールに頼らずに「値の一元管理」「動的な変更」「テーマ設計」を実現できる強力な機能です。最初は変数の定義と参照だけを覚えるだけでも、スタイルの保守性は格段に上がります。まずはプロジェクトのカラーパレットと基本スペーシングをカスタムプロパティに置き換えることから始めてみましょう。

・ポイント1:CSSカスタムプロパティは --プロパティ名: 値 で定義し、var() で参照する。:root に書けばサイト全体で使えるグローバル変数になる
・ポイント2:スコープはDOMツリーに基づくため、コンポーネント単位でローカル変数を定義することで柔軟な上書きが可能。ダークモードやテーマ切り替えとの相性も抜群
・ポイント3:命名規則を統一しデザイントークンファイルに集約することで、チーム開発での保守性・一貫性が大幅に向上する

CSSカスタムプロパティをマスターすることは、「修正に強いコード」を書く第一歩。今日から自分のプロジェクトに取り入れて、保守しやすいスタイル設計を実践してみましょう!


WithCodeを体験できる初級コース公開中!

WithCodeでは、Web制作の基礎から実務的な技術まで、実践的なスキルを段階的に学べます。

初級コース(¥49,800)が完全無料に!

  • 期間:1週間
  • 学習内容:ロードマップ/基礎知識/環境構築/HTML/CSS/LP・ポートフォリオ作成
    → 正しい学習方法で「確かな成長」を実感できるカリキュラム

副業・フリーランスが主流になっている今こそ、自らのスキルで稼げる人材を目指してみませんか?

未経験でも心配することはありません。まずは無料カウンセリングで、悩みや不安をお聞かせください!

この記事を書いた人

WithCodeでWeb制作を習得後、フリーランスエンジニアとして活動。HTML/CSS・JavaScript・WordPress案件を中心に年間20件以上の制作実績を持つ。「難しい技術をわかりやすく」をモットーに、初心者〜中級者向けの技術記事を執筆。副業・フリーランス独立を目指す方に向けた情報発信に注力している。

– service –WithGroupの運営サービス

  • WithCode
    - ウィズコード -

    スクール

    「未経験」から
    現場で通用する
    スキルを身に付けよう!

    詳細はこちら
  • WithFree
    - ウィズフリ -

    実案件サポート

    制作会社のサポート下で
    実務経験を積んでいこう!

    詳細はこちら
  • WithCareer
    - ウィズキャリ -

    就転職サポート

    大手エージェントのサポート下で
    キャリアアップを目指そう!

    詳細はこちら

公式サイト より
今すぐ
無料カウンセリング
予約!

目次