Tips & Tricks (更新: 2026/6/2)

Claude CodeでCSS変数を実務投入する設計ガイド

Claude CodeでCSS変数、var()、テーマトークン、ダークモードを実装する実務ガイド。

Claude CodeでCSS変数を実務投入する設計ガイド

CSS変数は「色の置き換え」だけではない

CSS変数は、正確には CSSカスタムプロパティ と呼ばれる仕組みです。--color-accent のように自分で名前を付けた値を定義し、var(--color-accent) で別の宣言から参照します。初心者向けに言い換えると、色、余白、角丸、影、フォントサイズに「名前付きの保管場所」を作る機能です。

Claude CodeにUI実装を任せるとき、この保管場所を先に決めておくと、生成されるCSSが散らかりにくくなります。ボタンだけ青、カードだけ微妙に違う影、ダークモードだけ文字色が薄すぎる、という事故を減らせます。

この記事では、Claude Codeに渡せる指示、コピペで動くCSS/HTML/JS、実務で使うユースケース、そして落とし穴までまとめます。前提として、より広い設計はClaude Codeデザインシステム、配色切り替えはダークモード実装、レイアウトはFlexboxパターンも合わせて読むと理解しやすいです。

概念図としては、次の順番で考えると破綻しません。

  • パレットトークン: --blue-600 のような生の色や数値
  • セマンティックトークン: --color-accent のような意味を持つ値
  • コンポーネントトークン: --button-bg のような部品単位の上書き
  • 状態トークン: dark、danger、compactなど、状況に応じた差し替え

Claude Codeに渡す指示の型

いきなり「CSS変数を使って」とだけ頼むと、Claude Codeは見た目の近道を選びがちです。最初に「何をトークン化するか」「どこまで上書き可能にするか」「フォールバックを必ず入れるか」を指定します。

{
  "task": "Create CSS custom properties for an article UI and implement a copy-paste demo.",
  "mustInclude": [
    "palette tokens",
    "semantic theme tokens",
    "component-level tokens",
    "var() fallbacks",
    "dark mode with data-theme and prefers-color-scheme",
    "vanilla JavaScript for theme switching"
  ],
  "constraints": [
    "Use custom properties only for values, not selectors or property names.",
    "Keep contrast readable in light and dark modes.",
    "Add comments for tokens that product designers may edit."
  ]
}

ここでの「トークン」とは、デザイン上の値に名前を付けたものです。#2563eb をあちこちに直接書くのではなく、--color-accent として扱うことで、後からブランド色を変えても修正箇所を小さくできます。

コピペで使えるCSSトークン

まずは最小限のテーマトークンを作ります。var() の第2引数はフォールバックです。たとえば var(--surface, #ffffff) は、--surface が未定義または使えない値だった場合に #ffffff を使います。MDNのvar()解説でも、フォールバックは実務で重要な構文として扱われています。

:root {
  color-scheme: light;

  /* Palette tokens: raw values */
  --blue-50: #eff6ff;
  --blue-400: #60a5fa;
  --blue-600: #2563eb;
  --blue-700: #1d4ed8;
  --slate-50: #f8fafc;
  --slate-100: #f1f5f9;
  --slate-300: #cbd5e1;
  --slate-700: #334155;
  --slate-900: #0f172a;
  --red-600: #dc2626;

  /* Semantic theme tokens: values used by the app */
  --surface: var(--slate-50);
  --surface-raised: #ffffff;
  --text: var(--slate-900);
  --text-muted: var(--slate-700);
  --border: var(--slate-300);
  --color-accent: var(--blue-600);
  --color-danger: var(--red-600);

  /* Typography and spacing */
  --font-body: Inter, "Noto Sans JP", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", Consolas, monospace;
  --step-0: 1rem;
  --step-1: 1.125rem;
  --step-2: 1.5rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --shadow-card: 0 12px 30px rgb(15 23 42 / 0.12);
}

[data-theme="dark"] {
  color-scheme: dark;
  --surface: var(--slate-900);
  --surface-raised: #111827;
  --text: var(--slate-50);
  --text-muted: var(--slate-300);
  --border: #334155;
  --color-accent: var(--blue-400);
  --shadow-card: 0 18px 42px rgb(0 0 0 / 0.35);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --surface: var(--slate-900);
    --surface-raised: #111827;
    --text: var(--slate-50);
    --text-muted: var(--slate-300);
    --border: #334155;
    --color-accent: var(--blue-400);
  }
}

body {
  margin: 0;
  font-family: var(--font-body, system-ui, sans-serif);
  background: var(--surface, #ffffff);
  color: var(--text, #111827);
}

.pricing-card {
  --card-padding: var(--space-6);
  --card-border: var(--border);

  max-width: 34rem;
  margin: var(--space-6) auto;
  padding: var(--card-padding);
  background: var(--surface-raised, #ffffff);
  border: 1px solid var(--card-border, #d1d5db);
  border-radius: var(--radius-lg, 0.75rem);
  box-shadow: var(--shadow-card, none);
}

.pricing-card h2 {
  margin: 0 0 var(--space-2);
  font-size: var(--step-2, 1.5rem);
}

.pricing-card p {
  color: var(--text-muted, #4b5563);
  line-height: 1.75;
}

.button {
  --button-bg: var(--color-accent);
  --button-text: #ffffff;
  --button-border: transparent;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  padding: 0 var(--space-4);
  border: 1px solid var(--button-border);
  border-radius: var(--radius-md);
  background: var(--button-bg, #2563eb);
  color: var(--button-text, #ffffff);
  font-weight: 700;
  cursor: pointer;
}

.button[data-variant="secondary"] {
  --button-bg: transparent;
  --button-text: var(--color-accent);
  --button-border: var(--color-accent);
}

このCSSのポイントは、コンポーネントの中でも変数を使っていることです。.button[data-variant="secondary"]backgroundcolor を直接書き換えず、--button-bg などを上書きしています。後から dangerghost を追加しても、基本構造を崩さずに済みます。

HTMLとJavaScriptでテーマを切り替える

次のHTMLとJSを同じページに置けば、ライト/ダーク切り替えとアクセントカラー変更を試せます。JSはフレームワークなしで動く形にしています。

<section class="pricing-card">
  <h2>Claude Code UI Token Demo</h2>
  <p>
    This card uses CSS custom properties for surface, text, border,
    shadow, and button colors.
  </p>
  <button class="button" type="button" data-theme-toggle>
    Toggle theme
  </button>
  <button class="button" type="button" data-variant="secondary">
    Secondary action
  </button>
  <label>
    Accent color
    <input type="color" value="#2563eb" data-accent-picker>
  </label>
</section>
const root = document.documentElement;
const themeKey = "claude-code-css-variable-theme";
const savedTheme = localStorage.getItem(themeKey);
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;

function applyTheme(theme) {
  root.setAttribute("data-theme", theme);
  localStorage.setItem(themeKey, theme);
}

function toggleTheme() {
  const current = root.getAttribute("data-theme") || "light";
  applyTheme(current === "dark" ? "light" : "dark");
}

function setAccentColor(color) {
  if (CSS.supports("color", color)) {
    root.style.setProperty("--color-accent", color);
  }
}

applyTheme(savedTheme || (prefersDark ? "dark" : "light"));

document.querySelector("[data-theme-toggle]")?.addEventListener("click", toggleTheme);
document.querySelector("[data-accent-picker]")?.addEventListener("input", (event) => {
  setAccentColor(event.target.value);
});

prefers-color-scheme はユーザーのOSやブラウザ設定を参照するメディア特性です。詳細はMDNのprefers-color-schemeが正確です。手動切り替えを優先したい場合は、上の例のように data-themehtml 要素に付けて上書きします。

実務で効く3つ以上のユースケース

1つ目は、記事サイトやLPのCTA改善です。本文、カード、ボタン、警告枠で同じ --color-accent を使えば、キャンペーンごとの色変更が1行で済みます。広告やGumroad導線のABテストでも、CSS全体を触らずに見た目を変えられます。

2つ目は、SaaS管理画面のテーマ統一です。部署ごとに画面を作ると、灰色の濃さや余白が少しずつズレます。--surface--border--space-* を共有しておくと、Claude Codeが新しい画面を生成しても既存UIに寄せやすくなります。

3つ目は、ホワイトラベルや顧客別ブランディングです。顧客Aは青、顧客Bは緑、社内環境はグレーというように、data-brand="customer-a" でトークンだけ差し替えます。コンポーネントコードを複製しないため、保守コストが増えにくいです。

4つ目は、アクセシビリティ対応です。高コントラストテーマ、大きめの余白、読みやすいフォントサイズをトークンとして分ければ、アクセシビリティ実装のレビュー観点をCSSに反映しやすくなります。

よくある失敗と落とし穴

一番多い失敗は、フォールバックなしの var() です。color: var(--text-primary); と書いたのに定義が漏れると、その宣言は期待通りに効きません。公開ページでは color: var(--text-primary, #111827); のように保険を入れてください。

次に、カスタムプロパティ名の大文字小文字です。MDNのカスタムプロパティ仕様ページにもある通り、--main-color--Main-color は別物です。Claude Codeには「命名は小文字、単語区切りはハイフン」と明示すると揺れが減ります。

3つ目は、CSS変数をメディアクエリの条件やプロパティ名に使おうとすることです。@media (min-width: var(--breakpoint-md)) のような書き方は期待通りに動きません。変数は基本的に「プロパティの値」に使うものだと理解してください。

4つ目は、JavaScriptでユーザー入力をそのまま setProperty() することです。色ピッカーのように値の範囲が決まっている場合でも、CSS.supports() で検証する癖をつけると安全です。

5つ目は、ダークモードの影と境界線を忘れることです。背景と文字色だけ変えても、薄い境界線や黒い影が残るとUIが濁ります。--border--shadow-card もテーマごとに見直してください。

Claude Codeでレビューさせるチェックリスト

実装後は、次のようなレビュー依頼をClaude Codeに渡します。ビルドやデプロイを任せる前に、CSSの破綻だけを批判的に見てもらうのがコツです。

{
  "reviewTarget": "CSS custom properties and theme implementation",
  "checks": [
    "undefined custom properties without fallback",
    "light and dark contrast issues",
    "component variants that bypass tokens",
    "duplicated raw colors outside :root",
    "JavaScript setProperty calls without validation",
    "mobile overflow caused by fixed spacing tokens"
  ],
  "output": "List findings with file name, selector, risk, and suggested fix."
}

この指示を使うと、Claude Codeが「動くかどうか」だけでなく、保守しやすいか、テーマ変更に耐えるか、収益導線のCTAが崩れないかまで見やすくなります。

まとめと次の一手

CSS変数は、色を置き換える小技ではなく、UIを長く運用するための設計部品です。パレット、意味、コンポーネント、状態の4段階でトークンを分け、var() フォールバックとダークモードを最初から入れておくと、Claude Codeが生成するCSSの品質が安定します。

仕様を深掘りするならMDNのCSSカスタムプロパティガイドvar()関数color-schemeを参照してください。Claude Code自体の基本はAnthropic公式ドキュメントが一次情報です。

手元でClaude Codeの基本コマンドも確認したい場合は、無料のClaude Code Quick Reference Cheatsheetから始めてください。レビュー、デバッグ、UI改善の依頼文をすぐ使いたいなら50 Prompt Templates、チームで CLAUDE.md、権限、hooks、検証手順まで固めるならSetup Guide導入相談が次の候補です。

この記事で紹介した内容を実際に試した結果、CTAカードと記事本文の色変更は --color-accent の差し替えだけで済み、ダークモード時の境界線漏れもレビュー指示で検出しやすくなりました。特に「生の色をコンポーネントに直書きしない」と決めるだけで、Claude Codeの修正差分がかなり読みやすくなります。

#Claude Code #CSS変数 #カスタムプロパティ #デザイントークン #テーマ
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。