WithCodeMedia-1-pc
previous arrowprevious arrow
next arrownext arrow

WithCodeMedia-1-sp
previous arrowprevious arrow
next arrownext arrow

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

目次

この記事の結論

CSSカスタムプロパティ(CSS変数)は、開発者が自分で定義できるCSS専用の変数で、SassやLessなどのプリプロセッサを使わなくても純粋なCSSだけで色・サイズ・余白などの値を一元管理できます。プロパティ名の先頭に「–」を付けて定義しvar()関数で参照し、:rootに書けばサイト全体で使えるグローバル変数になります。ブラウザ実行時に動的に値を変えられるため、ダークモード切り替えやテーマ設計との相性がよく、命名規則を統一してデザイントークンファイルに集約することで保守性と一貫性が大幅に向上します。

生徒

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


よくある質問(FAQ)

Q1. CSSカスタムプロパティはどう書きますか?

A. プロパティ名の先頭に必ず「–」(ダブルハイフン)を付けて定義し、var()関数で参照します。:root疑似クラスに定義すると、HTML文書全体からアクセスできるグローバル変数として機能します。

Q2. Sass変数とCSSカスタムプロパティの違いは何ですか?

A. 最大の違いはブラウザ上でリアルタイムに値が変わる点です。Sass変数はコンパイル時に静的に決まりJavaScriptから操作できませんが、CSSカスタムプロパティはブラウザ実行時に動的に変化し、JavaScriptから操作でき、メディアクエリ内での再定義も可能で、ビルドツールも不要です。

Q3. ダークモードの切り替えに使えますか?

A. 使えます。CSSカスタムプロパティの最も代表的な応用例がダークモード切り替えです。メディアクエリでの自動切り替えや、data-theme属性やクラスを付け替えてJavaScriptで手動切り替えする方法があり、CSS変数の値だけを切り替えるためコンポーネント側のCSSは変更不要です。

Q4. 変数の命名規則で推奨されるパターンはありますか?

A. 「カテゴリー-役割-状態」(例:–color-primary-hover)、コンポーネントスコープ変数にはプレフィックスを付ける(例:–btn-bg)、–color-redより–color-dangerのようにセマンティックな名前を優先する、スケール系は–font-size-smのように数値・段階サフィックスを使う、といったパターンが推奨されています。

Q5. 使う上での注意点はありますか?

A. 大文字・小文字は区別されるため小文字ケバブケースに統一する、shorthandプロパティで部分的に使う場合は分割して記述する、未定義の変数をvar()で参照するとプロパティ全体が無効になるためフォールバック値を設定するか@propertyで型定義する、といった点に注意が必要です。


関連記事


参考リンク(公式・一次情報)


あわせて読みたい:8の倍数で余白を統一するデザイン設計ガイド

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

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

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

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

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

未経験でも心配することはありません。初級コースを受講される方の大多数はプログラミング未経験です。まずは無料カウンセリングで、悩みや不安をお聞かせください!

この記事を書いた人

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

– service –WithGroupの運営サービス

  • WithCode
    - ウィズコード -

    スクール

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

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

    実案件サポート

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

    詳細はこちら

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

目次