CSS変数を使ってみよう
CSS変数を使うメリット
サイト全体のメインカラーを変更したいとき、CSSファイルの中から同じカラーコードを探して、ひとつずつ書き換えていく。この作業、地味に時間がかかります。また、10箇所、20箇所と増えてくると、どこかで書き換え漏れが出てきがちです。
CSS変数(正式にはカスタムプロパティ)を使うと、色やサイズなどの値を1箇所で定義して、サイト全体で使い回せるようになります。変更が必要になったとき、定義している1箇所を直すだけで全ページに反映されます。
たとえば、メインカラーを変数なしで書くとこうなります。
/* 変数なし:同じ色を何度も書く */
.header { background-color: #1e90ff; }
.btn-primary { background-color: #1e90ff; }
.link { color: #1e90ff; }
.section-title::after { background: #1e90ff; }CSS変数を使うと、こう変わります。
/* 変数あり:定義は1箇所だけ */
:root {
--color-primary: #1e90ff;
}
.header { background-color: var(--color-primary); }
.btn-primary { background-color: var(--color-primary); }
.link { color: var(--color-primary); }
.section-title::after { background: var(--color-primary); }メインカラーを別の色に変えたくなったら、:root の中の1行を書き換えるだけです。書き換え漏れも起きません。
Sass(SCSSの変数 $color-primary など)を使っている方も多いと思います。
Sassの変数との違いは後ほど詳しく触れますが、CSS変数にはSass変数にないブラウザが読み込んだ後に値を切り替えられるという強みがあります。レスポンシブ対応やダークモードなど、「状況に応じて値を変えたい」場面でこの特性が活きてきます。
基本の書き方をおさえよう
:root で宣言する
CSS変数は --(ハイフン2つ)から始まる名前で宣言します。使うときは var() 関数で呼び出します。
:root {
--color-primary: #1e90ff;
--color-text: #333333;
--font-size-base: 16px;
--spacing-md: 24px;
}
.card {
color: var(--color-text);
font-size: var(--font-size-base);
padding: var(--spacing-md);
border-top: 3px solid var(--color-primary);
}:root はHTMLドキュメント全体を指すセレクタです。ここで宣言した変数は、ページ内のどこからでも使えます。サイト共通の色やサイズは :root にまとめておくのが基本です。
var() にはフォールバック値(予備の値)を指定できます。万が一変数が未定義だったときに使われる値です。
/* 第2引数がフォールバック値 */
.card {
color: var(--color-text, #333333);
}フォールバック値は「保険」のようなものです。変数の定義漏れがあっても表示が壊れないので、特に共通パーツには入れておくと安心です。
スコープを活かす
CSS変数は :root だけでなく、任意のセレクタの中で宣言できます。宣言した要素とその子要素の範囲内で有効になります。
:root {
--color-primary: #1e90ff;
}
.card--danger {
--color-primary: #e74c3c;
}
.card {
border-top: 3px solid var(--color-primary);
}
.card__title {
color: var(--color-primary);
}この書き方だと、通常の .card は青いボーダーとタイトルになりますが、.card--danger クラスがついたカードは赤に変わります。HTMLの構造はまったく同じまま、クラスひとつで見た目を切り替えられるわけです。
コンポーネント(パーツ)単位で変数を上書きするこのパターンは、実務でかなり使えます。ボタンのバリエーション、セクションごとの配色変更など、応用範囲が広いです。
実案件で使える管理パターン3つ
カラーパレットを一元管理する
実際の案件で最初に変数化すべきなのは、色です。デザインカンプから色を拾って、役割ごとに名前をつけていきます。
:root {
/* ブランドカラー */
--color-primary: #1e90ff;
--color-primary-light: #e8f4fd;
--color-primary-dark: #1565c0;
/* テキスト */
--color-text: #333333;
--color-text-light: #666666;
--color-text-muted: #999999;
/* 背景 */
--color-bg: #ffffff;
--color-bg-gray: #f5f5f5;
/* アクセント・状態 */
--color-accent: #ffe066;
--color-error: #e74c3c;
--color-success: #2ecc71;
}ポイントは変数名のつけ方です。
--color-で始めて、色の変数であることをすぐわかるようにする- 具体的な色名(
--blue)ではなく、役割名(--color-primary)をつける - バリエーションは
-light/-darkなどのサフィックスで表現する
--blue のような色名にしてしまうと、ブランドカラーが青から緑に変わったとき、変数名と実際の色がちぐはぐになります。役割名にしておけば、値だけ差し替えればOKです。
フォントサイズ・余白をトークンとして管理する
色だけでなく、フォントサイズや余白も変数にしておくとサイト全体の統一感が出ます。デザイントークン(デザインの共通ルールを変数として定義したもの)という考え方です。
:root {
/* フォントサイズ */
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.25rem; /* 20px */
--font-size-xl: 1.5rem; /* 24px */
--font-size-2xl: 2rem; /* 32px */
/* 余白 */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 40px;
--spacing-2xl: 64px;
}使い方はカラーと同じです。
.section {
padding: var(--spacing-2xl) 0;
}
.section__title {
font-size: var(--font-size-2xl);
margin-bottom: var(--spacing-lg);
}
.section__text {
font-size: var(--font-size-base);
margin-bottom: var(--spacing-md);
}「この余白、16pxだっけ?24pxだっけ?」と迷うことがなくなります。デザインカンプのルールと変数名を対応させておけば、コーディング中に何度もFigmaを確認しに行く手間も減ります。
フォントサイズのコメントに /* 16px */ のようにピクセル値を添えているのは、rem の換算をいちいち計算しなくて済むようにするためです。ちょっとした工夫ですが、後から見返したときに助かります。
ブレイクポイントごとに値を切り替える
CSS変数の真価が発揮されるのが、レスポンシブ対応の場面です。メディアクエリの中で変数を上書きするだけで、その変数を使っているすべての箇所に変更が反映されます。
:root {
--font-size-heading: 1.5rem;
--spacing-section: 40px;
--grid-columns: 1;
}
@media (min-width: 768px) {
:root {
--font-size-heading: 2rem;
--spacing-section: 64px;
--grid-columns: 2;
}
}
@media (min-width: 1024px) {
:root {
--grid-columns: 3;
}
}これを使う側はとてもシンプルになります。
.section {
padding: var(--spacing-section) 0;
}
.section__title {
font-size: var(--font-size-heading);
}
.card-grid {
display: grid;
grid-template-columns: repeat(var(--grid-columns), 1fr);
gap: var(--spacing-lg);
}変数を使わない書き方だと、メディアクエリの中で .section と .section__title と .card-grid のそれぞれにスタイルを書き直す必要があります。変数で管理していれば、変数の値を変えるだけで、使っている側は一切触らなくていい。これがCSS変数の大きなメリットです。
特にカラム数の切り替えは便利です。--grid-columns の値をブレイクポイントごとに変えるだけで、グリッドレイアウトが自動的に調整されます。
Sassと組み合わせるときのコツ
Sassの変数($color-primary)とCSS変数(--color-primary)は名前が似ていますが、性質がまったく違います。
- Sass変数はコンパイル時(CSSに変換するタイミング)に値が確定する。ブラウザはSass変数の存在を知らない
- CSS変数はブラウザが読み込んだ後も値として残り続ける。メディアクエリやJavaScriptで動的に切り替えられる
実務では、この2つを完全にどちらかに統一するのではなく、役割で使い分けるのがおすすめです。
// _variables.scss
// Sass変数:ビルド時に確定する設定値
$breakpoint-md: 768px;
$breakpoint-lg: 1024px;
$font-family-base: "Noto Sans JP", sans-serif;
$border-radius: 6px;
// CSS変数:ブラウザ側で変わりうる値
:root {
--color-primary: #1e90ff;
--color-text: #333333;
--font-size-heading: 1.5rem;
--spacing-section: 40px;
}
@media (min-width: $breakpoint-md) {
:root {
--font-size-heading: 2rem;
--spacing-section: 64px;
}
}使い分けの目安はこうです。
- ブレイクポイントの数値、フォントファミリー、border-radiusなど→ サイト全体で固定の値なので、Sass変数で十分
- 色、フォントサイズ、余白など→ レスポンシブやコンポーネントのバリエーションで変わる可能性があるので、CSS変数が向いている
Sass変数でまずCSS変数の初期値を定義して、CSS変数としてブラウザに渡す、というパターンもあります。
// Sassで初期値を管理
$color-primary-default: #1e90ff;
:root {
--color-primary: #{$color-primary-default};
}Sassの #{}(インターポレーション)を使って、Sass変数の値をCSS変数に渡しています。こうすると、Sassのmixinやfunctionの中でも初期値を参照できるので、両方のいいとこ取りができます。
やりがちな失敗と対処法
CSS変数は便利ですが、実案件で使い始めると「あれ?」となるポイントがいくつかあります。先に知っておけば避けられるものばかりです。
フォールバック値の書き忘れ
共通のCSSファイルとは別に、ページ固有のCSSファイルがある構成では注意が必要です。共通CSSで :root に変数を定義しているのに、ページ固有CSSだけ読み込まれるケースで変数が未定義になることがあります。
/* フォールバックなし:変数が未定義だとスタイルが効かない */
.card {
color: var(--color-text);
}
/* フォールバックあり:未定義でも #333 が適用される */
.card {
color: var(--color-text, #333333);
}すべてに書く必要はありませんが、ヘッダーやフッターなど、どのページでも確実に表示されるパーツにはフォールバック値を入れておくと安全です。
変数名がバラバラになる
チームで開発していると、同じ意味の変数に違う名前がついてしまうことがあります。
/* 人によって書き方がバラバラになりがち */
--main-color: #1e90ff;
--primary-color: #1e90ff;
--color-primary: #1e90ff;
--colorPrimary: #1e90ff;案件の最初に命名ルールを決めておくだけで防げます。おすすめは次のルールです。
- カテゴリから始める:
--color-、--font-size-、--spacing- - ケバブケース(ハイフン区切り)で統一する
- サイズの段階には
xs / sm / md / lg / xl / 2xlを使う
ルールの例を表にするとこうなります。
--color-{役割}:--color-primary,--color-text,--color-bg--font-size-{段階}:--font-size-sm,--font-size-base,--font-size-lg--spacing-{段階}:--spacing-sm,--spacing-md,--spacing-xl
CSSファイルの冒頭にコメントで命名規則を書いておくと、後からプロジェクトに入るメンバーにも伝わります。
変数のネストが深くなりすぎる
CSS変数の値に別のCSS変数を使うことができます。便利な機能ですが、やりすぎると追いかけるのが大変になります。
/* 2段階くらいなら問題なし */
:root {
--color-blue: #1e90ff;
--color-primary: var(--color-blue);
}
/* 3段階以上は追いかけにくい */
:root {
--color-blue: #1e90ff;
--color-brand: var(--color-blue);
--color-primary: var(--color-brand);
--color-header-bg: var(--color-primary);
}参照の深さは2段階までにとどめておくのが実用的です。それ以上になるなら、構造を見直したほうがメンテナンスしやすくなります。
まとめ
CSS変数は、サイト全体の色・サイズ・余白を一元管理できる仕組みです。値の変更が1箇所で済み、レスポンシブ対応も楽になります。Sassと組み合わせれば、コンパイル時の便利さとブラウザ側の柔軟さ、両方を活かせます。
まずは、サイトのメインカラー・サブカラー・テキスト色の3つをCSS変数にまとめるのがおすすめです。
色の変更やバリエーション追加のたびにCSSファイルを検索して回る手間がなくなります。
サイトを見ている人には、変数を使っているかどうかは見えません。でも、コードの管理しやすさやミスの起きにくさは、長期的にサイトの品質に直結します。こういった見えない部分への配慮が、信頼されるコーディングにつながっていくと思っています。