メインコンテンツまでスキップ
  • Created:
  • Updated:
  • Author:
    Takeshi Takatsudo

高度なカスタムプロパティ

問題

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の状態橋渡し

ライブプレビュー

スペーストグルトリック
コンポーネントのカスタムプロパティAPI

詳細解説

  • パターンカタログ — インタラクティブなデモ付きのCSSカスタムプロパティパターンの包括的なコレクション
  • テーマレシピ — ライト/ダークモード、ブランドテーマ、コンポーネントライブラリのための完全なテーマシステムレシピ

参考リンク