高度なカスタムプロパティ
問題
CSSカスタムプロパティ(変数)は広く使われていますが、ほとんどの開発者やAIエージェントは表面をなぞるだけにとどまります — :rootにシンプルな色やサイズのトークンを定義し、var()で参照するだけです。スペーストグルトリック、フォールバックチェーン、計算によるプロパティの関連付けといった高度なパターンはほとんど活用されず、条件付きスタイリングに不要なJavaScript、硬直的なテーマシステム、重複した宣言につながります。
解決方法
CSSカスタムプロパティは単純な変数の置換よりもはるかに強力です。カスケードに参加し、任意の要素にスコープでき、多段階のフォールバックチェーンをサポートし、スペーストグルトリックと組み合わせることでブーリアンのような条件ロジックを作成できます — すべて純粋なCSSでJavaScriptなしで実現できます。
コード例
スペーストグルトリック
スペーストグルはvar()のフォールバックの仕組みを利用します。カスタムプロパティを単一のスペース( )に設定すると有効で「パススルー」し、initialに設定するとフォールバック値が使用されます。
/* The toggle: space = ON, initial = OFF */
.card {
--is-featured: initial; /* OFF by default */
/* When ON, value becomes " blue"; when OFF, fallback "gray" is used */
background: var(--is-featured) blue, gray;
color: var(--is-featured) white, #333;
border-width: var(--is-featured) 3px, 1px;
}
.card.featured {
--is-featured: ; /* ON (single space) */
}
ダークモード用のスペーストグル
:root {
--dark: initial; /* Light mode by default */
}
@media (prefers-color-scheme: dark) {
:root {
--dark: ; /* Enable dark mode */
}
}
body {
background: var(--dark) #1a1a2e, #ffffff;
color: var(--dark) #e0e0e0, #1a1a2e;
}
.card {
background: var(--dark) #2d2d44, #f5f5f5;
border-color: var(--dark) #444, #ddd;
}
テーマ用のフォールバックチェーン
コンポーネントが段階的に広いデフォルトを確認するレイヤード設定システムを作成します。これは3層カラー戦略の背後にあるメカニズムです — コンポーネントトークンはテーマトークンにフォールバックし、テーマトークンはパレット値にフォールバックします。
.button {
/* Check component-specific → theme-level → hardcoded default */
background: var(--button-bg, var(--accent-color, #2563eb));
color: var(--button-color, var(--accent-contrast, white));
padding: var(--button-padding, var(--spacing-sm, 0.5rem 1rem));
border-radius: var(--button-radius, var(--radius, 4px));
}
/* Theme-level override: changes all components using --accent-color */
.theme-warm {
--accent-color: #ea580c;
--accent-contrast: white;
}
/* Component-specific override: changes only buttons */
.cta-section {
--button-bg: #16a34a;
--button-color: white;
}
コンポーネントバリアント用のスコープ付きカスタムプロパティ
すべてのバリアントに個別のクラスを作成する代わりに、カスタムプロパティをスタイリングAPIとして使用します。
.badge {
--_bg: var(--badge-bg, #e5e7eb);
--_color: var(--badge-color, #374151);
--_size: var(--badge-size, 0.75rem);
background: var(--_bg);
color: var(--_color);
font-size: var(--_size);
padding: 0.25em 0.75em;
border-radius: 999px;
font-weight: 600;
}
/* Variants set only the custom properties */
.badge-success {
--badge-bg: #dcfce7;
--badge-color: #166534;
}
.badge-error {
--badge-bg: #fee2e2;
--badge-color: #991b1b;
}
calc()による計算された関係
.fluid-type {
--min-size: 1;
--max-size: 1.5;
--min-width: 320;
--max-width: 1200;
font-size: calc(
(var(--min-size) * 1rem) +
(var(--max-size) - var(--min-size)) *
(100vw - var(--min-width) * 1px) /
(var(--max-width) - var(--min-width))
);
}
h1 { --min-size: 1.5; --max-size: 3; }
h2 { --min-size: 1.25; --max-size: 2; }
CSSとJavaScript間の状態共有
.progress-bar {
--progress: 0;
width: calc(var(--progress) * 1%);
background: hsl(calc(var(--progress) * 1.2) 70% 50%);
transition: width 0.3s, background 0.3s;
}
<div class="progress-bar" style="--progress: 75"></div>
<script>
// Update from JavaScript — CSS handles the visual mapping
element.style.setProperty('--progress', newValue);
</script>
プライベートカスタムプロパティの命名規則
--の後にアンダースコアを付けて、コンシューマーが設定すべきでない「内部」プロパティであることを示します。
.tooltip {
/* Public API */
--tooltip-bg: var(--surface-inverse, #1f2937);
--tooltip-color: var(--text-inverse, white);
/* Private (internal computation) */
--_arrow-size: 6px;
--_offset: calc(100% + var(--_arrow-size) + 4px);
background: var(--tooltip-bg);
color: var(--tooltip-color);
transform: translateY(calc(-1 * var(--_offset)));
}
ブラウザサポート
- Chrome 49+
- Firefox 31+
- Safari 9.1+
- Edge 15+
カスタムプロパティはほぼユニバーサルなサポート(98%以上)があります。スペーストグルトリックで使用されるinitialキーワードの動作は、カスタムプロパティをサポートするすべてのブラウザで動作します。パフォーマンスを最適にするために、3レベルを超えるフォールバックチェーンは避け、setProperty()の呼び出しは:rootではなく最も具体的な要素にスコープしましょう。
AIがよくやるミス
- スペーストグルトリックで処理できるビジュアル状態のトグルにJavaScriptを使用する
- カスタムプロパティをコンポーネントにスコープする代わりに
:rootにのみ定義する - テーマ可能なコンポーネントAPIにフォールバックチェーンを活用しない
- カスタムプロパティベースのバリアントを使う代わりに、すべてのバリアントに個別のCSSクラスを作成する
calc()内でカスタムプロパティなしの生の値を使用し、値間の関係を不透明にする- フォールバックチェーンを深くネストする(4レベル以上)ことで解決のオーバーヘッドを増やす
- パブリックとプライベートのカスタムプロパティを区別するための命名規則(
--_プレフィックスなど)を使用しない
使い分け
- フォールバックチェーンによるコンポーネントレベルのオーバーライドを持つテーマシステム
- スペーストグルトリックによるブーリアンのような条件付きスタイリング(ダークモード、フィーチャーフラグ)
- コンシューマーがプロパティを設定して外観をカスタマイズするコンポーネントバリアントAPI
- 値間の計算された関係(レスポンシブサイジング、カラーパレット)
- クラストグルなしのCSSとJavaScriptの状態橋渡し
ライブプレビュー
詳細解説
- パターンカタログ — インタラクティブなデモ付きのCSSカスタムプロパティパターンの包括的なコレクション
- テーマレシピ — ライト/ダークモード、ブランドテーマ、コンポーネントライブラリのための完全なテーマシステムレシピ