色
適応型の役割からインターフェイスの色を組み立て、角丸と影で面を浮かせ、明暗のモードを選びます。
このページの内容
#概要
インターフェイスの色は役割から組み立てます。面、線、文字のクラスは、明暗どちらのモードでも変わりません。イラストやブランドのアクセントなど、色そのものが目的の場合はパレットの色階を使います。色の変化は、役割や状態、読み手が見分ける必要のある違いに結び付けます。
配色が変わっても役割は同じ
役割は一度選ぶだけです。light-dark() の値は要素のカラースキームに従い、別の配色内にある局所的な領域にも対応します。
テキストによる説明
- 役割を保つ. 両方の領域で同じ面、区切り線、強調文字、補助文字のクラスを使います。
- 領域ごとに解決する. 役割の値には light-dark() を使います。クラスを変えずに、各領域の color-scheme が明暗の色を選びます。
#役割とパレットの色階を選ぶ
| 判断したいこと | 使うもの | 例 |
|---|---|---|
| ページ構造と文字の階層 | 色の役割 | bg-surface-raised, b-line-divider, fg-text-muted |
| 特定の色 | パレットの色階 | bg-blue-5, fg-blue-60 |
同じ構成、2つのモード
<section class="p-md r-lg b(1) b-solid b-line-divider bg-surface-raised fg-text-body"> <h2 class="m(0) text-lg font-regular fg-text-strong">Project updates</h2> <p class="mt-xs mb-md text-sm fg-text-muted">Three milestones changed this week.</p> <a class="fg-text-link underline" href="/updates">Continue</a></section>生成された CSS
@layer theme { :root, :host { --color-zinc-40: oklch(68.6% .0028 265); --color-zinc-60: oklch(48.6% .003 265); --color-zinc-90: oklch(24.6% .0022 265) } :root, :host { --color-surface-raised: light-dark(var(--color-white), var(--color-zinc-90)); --color-line-divider: light-dark(oklch(0% 0 none / .12), oklch(100% 0 none / .12)); --color-text-muted: light-dark(var(--color-zinc-60), var(--color-zinc-40)) } :root, :host { --color-white: oklch(100% 0 none) }}@layer utilities { .bg-surface-raised { background-color: var(--color-surface-raised) } .b-line-divider { border-color: var(--color-line-divider) } .fg-text-muted { color: var(--color-text-muted) }}役割は色のキーに含まれます。bg-surface-raised は --color-surface-raised、b-line-divider は --color-line-divider を読み取ります。線の役割で設定するのは色だけなので、境界線の幅とスタイルは別に指定します。すべての役割は色の役割、パレットはカラーパレットを参照してください。
線の色には太さとスタイルが必要
全ボックスは border-style: none から始まります。border-box のサイズは同じで、記載した枠線宣言だけが変わります。
テキストによる説明
- b-line-divider は border-color、b(2) は border-width を設定します。どちらも none の枠線スタイルは変えません。
- b-solid を加えると 2px の枠線を描けます。必要な他の指定がコンポーネントにある場合もあるため、色クラスだけが見える場合はスタイル全体を確認してください。
固定の色階と意味を持つ役割を区別する
特定の色にはパレットの色階を、文脈に従う判断には役割を選びます。
テキストによる説明
2つの経路で、固定のパレット色階と明暗の値を選ぶ役割を分けて示します。
#固定と適応型の色相エイリアス
fg-yellow などの色相エイリアスは固定色で、どのモードでも同じ値です。fg-text-yellow などの文字用色相エイリアスは、各モードで文字の前景色に適した色階を選びます。実際の背景とのコントラストを確認してください。適応型のエイリアスでも、すべての組み合わせを保証するわけではありません。
<svg class="fg-yellow" fill="currentColor" aria-hidden="true">…</svg><p class="fg-text-yellow">Pending review</p>生成された CSS
@layer theme { :root, :host { --color-yellow-40: oklch(91.5% .1909 101.1); --color-yellow-90: oklch(52.17% .1199 62.2) } :root, :host { --color-yellow: var(--color-yellow-40); --color-text-yellow: light-dark(var(--color-yellow-90), var(--color-yellow-40)) }}@layer utilities { .fg-text-yellow { color: var(--color-text-yellow) } .fg-yellow { color: var(--color-yellow) }}色付きのラベルには文字用色相エイリアスを使います。本文、強調、リンクには文字の役割を使います。
#浮き上がった面
浮き上がった面は、面の役割、角丸トークン、影のトークンを組み合わせます。操作できる面では、ホバーやフォーカス時に影を1段階上げます。通常のカードやコントロールには小さな角丸を使い、pill は下のバッジのように全体を丸くしたい形に使います。
浮き上がった面
<a class="block p-md r-lg bg-surface-raised fg-text-body shadow-sm shadow-md:hover shadow-md:focus-visible" href="/notes"> <span class="flex items-center justify-between gap-sm"> <span class="fg-text-strong">Field notes</span> <span class="px-xs py-3xs pill bg-line-subtle text-xs fg-text-muted">12 new</span> </span></a>生成された CSS
@layer theme { :root, :host { --radius-lg: .5rem } :root, :host { --shadow-sm: 0 0 0 1px light-dark(oklch(0% 0 none / .04), oklch(100% 0 none / .05)), 0 1px 1px -.5px light-dark(oklch(0% 0 none / .045), oklch(0% 0 none / .3)), 0 2px 2px -1px light-dark(oklch(0% 0 none / .04), oklch(0% 0 none / .26)), 0 4px 4px -2px light-dark(oklch(0% 0 none / .04), oklch(0% 0 none / .24)); --shadow-md: 0 0 0 1px light-dark(oklch(0% 0 none / .05), oklch(100% 0 none / .06)), 0 1px 1px -.5px light-dark(oklch(0% 0 none / .045), oklch(0% 0 none / .3)), 0 2px 2px -1px light-dark(oklch(0% 0 none / .04), oklch(0% 0 none / .26)), 0 4px 4px -2px light-dark(oklch(0% 0 none / .04), oklch(0% 0 none / .24)), 0 8px 8px -4px light-dark(oklch(0% 0 none / .045), oklch(0% 0 none / .26)) }}@layer utilities { .r-lg { border-radius: var(--radius-lg) } .pill { border-radius: calc(infinity * 1px) } .shadow-sm { box-shadow: var(--shadow-sm) } .shadow-md\:hover:hover { box-shadow: var(--shadow-md) }}プリセットの影は色に light-dark() を使うため、shadow-sm は形状を保ちながら要素のカラースキームに従います。pill は角丸トークンではなく固定ユーティリティで、幅と高さが同じなら円になります。個別の角は rtl-lg、rtr-lg、rbl-lg、rbr-lg で丸められます。スケールとカスタマイズは角丸と影を参照してください。
同じ pill の半径もボックス形状に従う
高さは 64px のままです。pill は角の半径を設定し、例の寸法は別のサイズ宣言で決めます。
テキストによる説明
- pill は角を完全に丸くする半径を設定し、幅、高さ、内側の余白は設定しません。
- 幅と高さが等しければ円、同じ高さで横長ならカプセルになります。クラスだけで円は保証されません。
#ライトモードとダークモード
プリセットはルートに color-scheme: light dark を設定し、役割と影に light-dark() を使うため、クラスを追加せずにシステム設定に従います。モードを選ぶには、ルート、入れ子の領域、またはシャドーホストに data-theme="light" か data-theme="dark" を設定します。
1つのトークン、2つの局所的な配色
@theme { --color-surface-notes: light-dark(#f4f4f5, #27272a);}@layer base { [data-theme="light"] { color-scheme: light; } [data-theme="dark"] { color-scheme: dark; }}<section data-theme="dark" class="p-md r-lg bg-surface-notes fg-text-body wrap-anywhere"> <h2 class="m(0) text-lg font-regular">Dark notes</h2> <p class="mt-xs mb-md text-sm">This region chooses dark.</p> <article data-theme="light" class="p-md r-md bg-surface-notes fg-text-body"> <h3 class="m(0) text-md font-regular">A light region inside</h3> <p class="mt-xs mb(0) text-sm">The same surface token follows this article’s light scheme.</p> </article></section>生成された CSS
@layer base { [data-theme="light"] { color-scheme: light; } [data-theme="dark"] { color-scheme: dark; }}@layer theme { :root, :host { --color-zinc-30: oklch(78% .0025 265); --color-zinc-70: oklch(39.8% .0028 265) } :root, :host { --color-text-body: light-dark(var(--color-zinc-70), var(--color-zinc-30)) } :root, :host { --font-weight-regular: 400; --font-size-sm: .875rem; --font-size-md: 1rem; --font-size-lg: 1.125rem; --text-sm: var(--font-size-sm); --text-sm--line-height: 1.5; --text-sm--letter-spacing: 0; --text-md: var(--font-size-md); --text-md--line-height: 1.6; --text-md--letter-spacing: 0; --text-lg: var(--font-size-lg); --text-lg--line-height: 1.5; --text-lg--letter-spacing: 0; --radius-md: .375rem; --radius-lg: .5rem; --spacing-xs: .5rem; --spacing-md: 1rem } :root, :host { --color-surface-notes: light-dark(#f4f4f5, #27272a) }}@layer utilities { .text-lg { font-size: var(--text-lg); line-height: var(--text-lg--line-height, normal); letter-spacing: var(--text-lg--letter-spacing, normal) } .text-md { font-size: var(--text-md); line-height: var(--text-md--line-height, normal); letter-spacing: var(--text-md--letter-spacing, normal) } .text-sm { font-size: var(--text-sm); line-height: var(--text-sm--line-height, normal); letter-spacing: var(--text-sm--letter-spacing, normal) } .bg-surface-notes { background-color: var(--color-surface-notes) } .r-lg { border-radius: var(--radius-lg) } .r-md { border-radius: var(--radius-md) } .fg-text-body { color: var(--color-text-body) } .font-regular { font-weight: var(--font-weight-regular) } .m\(0\) { margin: calc(0 * 1px) } .mb-md { margin-bottom: var(--spacing-md) } .mt-xs { margin-top: var(--spacing-xs) } .mb\(0\) { margin-bottom: calc(0 * 1px) } .wrap-anywhere { overflow-wrap: anywhere } .p-md { padding: var(--spacing-md) }}プリセットにはこの2つの data-theme セレクターが含まれており、CSS では有効化の仕組みを示すために再掲しています。light-dark() を使う独自の色も同様に適応し、モード変更に再コンパイルは不要です。入れ子の領域は再宣言しない限り親のトークンを継承します。ブランドテーマには [data-brand="ocean"] など独自のセレクターを用意し、そこで役割のトークンを再宣言します。
接尾辞の @light と @dark は prefers-color-scheme メディアクエリーです。手動の data-theme はトークンを変更しますが、これらのクエリーを有効にはしません。クラスを手動の選択に反応させるには、セレクター mixin を宣言して適用します。
@mixin --manual-dark { &:where([data-theme="dark"], [data-theme="dark"] *) { @contents; }}<img class="(opacity:.85)@apply(--manual-dark)" src="/chart.png" alt="Weekly usage" />この mixin は実際のカラースキームではなく属性を調べるため、入れ子のライト領域内にも一致します。適応型のトークンを優先してください。スコープと解決については変数とモードを参照してください。
祖先セレクターは明るい領域内にも届く
破線は明示的な dark 属性をたどります。内側の明るい境界は color-scheme を変え、セレクターが検査する祖先関係は変えません。
テキストによる説明
- この記事の --manual-dark ミックスインは [data-theme="dark"] 自身またはその子孫に一致します。
- 入れ子の data-theme="light" 領域内のチャートも外側の dark 領域の子孫です。そのため light-dark() がローカルの明るい配色を使っていても、不透明度ラッパーは一致します。
- 実際に使う配色に従う値には適応型トークンを使います。属性セレクターは記述した関係をそのまま検査します。
最も近いカラースキームが色を選ぶ
入れ子の境界は color-scheme を表します。トークン名とマークアップは変わりません。
テキストによる説明
ライトの文書がダークの領域を囲んでいます。同じ意味のトークンで、外側は明るい面、内側は暗い面を描きます。
#実際の構成で役割を確認する
同じ内容を両方の配色で確認します。強調と補助の文字を実際の面と組み合わせ、通常時とフォーカス時のリンク、コントロールを識別する境界線も確認します。色のトークンが提供するのは値であり、それだけでコントラスト、フォーカスの見やすさ、状態の意味が成立するわけではありません。
選択項目やステータスでは、色にラベル、アイコンなどの見える手掛かりを組み合わせます。入れ子の領域は個別に検証してください。ダークページ内で手動設定したライト領域にも、読みやすい面と前景の組み合わせが必要です。











