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

color-mix()

問題

CSSでティント、シェード、半透明のカラーバリアントを作成するには、従来はすべての色値を手動で計算する必要がありました。AIエージェントはすべてのシェードを個別の hex や rgb 値としてハードコードしがちで(例:#3366cc#5588dd#99bbee を独立して生成)、パレットが脆く保守しにくくなります。ベースのブランドカラーが変わると、すべての派生値を再計算する必要があります。Sassのような CSSプリプロセッサは lighten()darken() でこれを解決しましたが、ネイティブCSSには同等の機能がありませんでした — color-mix() が登場するまでは。

解決方法

color-mix() は、指定されたカラースペースで2つの色をブレンドし、結果の色を返すCSS関数です。カラースペース、2つの色、およびミックス比率を制御するオプションのパーセンテージ値を取ります。

color-mix(in <color-space>, <color> <percentage>?, <color> <percentage>?)

カラースペースパラメータは、補間の計算方法を決定します。oklchoklab を使うと、srgb よりも知覚的に均一なブレンドが得られます。

コード例

基本構文

:root {
--brand: oklch(55% 0.25 264);

/* Mix 70% brand with 30% white = a lighter tint */
--brand-light: color-mix(in oklch, var(--brand) 70%, white);

/* Mix 70% brand with 30% black = a darker shade */
--brand-dark: color-mix(in oklch, var(--brand) 70%, black);

/* Equal mix of two colors */
--blend: color-mix(in oklch, var(--brand), orange);
}

単一ベースカラーからティントとシェードを作成

:root {
--brand: oklch(50% 0.22 264);

/* Tints (lighter) — mixing with white */
--brand-50: color-mix(in oklch, var(--brand) 5%, white);
--brand-100: color-mix(in oklch, var(--brand) 10%, white);
--brand-200: color-mix(in oklch, var(--brand) 25%, white);
--brand-300: color-mix(in oklch, var(--brand) 40%, white);
--brand-400: color-mix(in oklch, var(--brand) 60%, white);

/* Base */
--brand-500: var(--brand);

/* Shades (darker) — mixing with black */
--brand-600: color-mix(in oklch, var(--brand) 80%, black);
--brand-700: color-mix(in oklch, var(--brand) 60%, black);
--brand-800: color-mix(in oklch, var(--brand) 40%, black);
--brand-900: color-mix(in oklch, var(--brand) 25%, black);
}
color-mix() — ティント、シェード、半透明バリアント

半透明バリアント

transparent とミックスすることで、任意の色の半透明バージョンを作成できます。ホバー状態、オーバーレイ、背景に特に便利です:

:root {
--brand: oklch(55% 0.25 264);

/* Semi-transparent variants */
--brand-alpha-10: color-mix(in oklch, var(--brand) 10%, transparent);
--brand-alpha-20: color-mix(in oklch, var(--brand) 20%, transparent);
--brand-alpha-50: color-mix(in oklch, var(--brand) 50%, transparent);
}

.hover-card:hover {
background-color: var(--brand-alpha-10);
}

.overlay {
background-color: var(--brand-alpha-50);
}

.subtle-border {
border-color: var(--brand-alpha-20);
}

インタラクティブステートカラー

:root {
--btn-bg: oklch(55% 0.22 264);

--btn-hover: color-mix(in oklch, var(--btn-bg), white 15%);
--btn-active: color-mix(in oklch, var(--btn-bg), black 15%);
--btn-disabled: color-mix(in oklch, var(--btn-bg) 40%, oklch(70% 0 0));
}

.button {
background: var(--btn-bg);
}

.button:hover {
background: var(--btn-hover);
}

.button:active {
background: var(--btn-active);
}

.button:disabled {
background: var(--btn-disabled);
}

カラースペースの比較

:root {
--red: oklch(60% 0.25 30);
--blue: oklch(55% 0.25 264);

/* sRGB interpolation — can produce muddy, desaturated results */
--mix-srgb: color-mix(in srgb, var(--red), var(--blue));

/* oklch interpolation — maintains vibrancy through the blend */
--mix-oklch: color-mix(in oklch, var(--red), var(--blue));
}

単一ベースカラーからの動的テーマ

:root {
--base: oklch(55% 0.2 264);

--surface: color-mix(in oklch, var(--base) 5%, white);
--surface-raised: color-mix(in oklch, var(--base) 10%, white);
--border: color-mix(in oklch, var(--base) 20%, oklch(80% 0 0));
--text: color-mix(in oklch, var(--base) 40%, black);
--text-muted: color-mix(in oklch, var(--base) 30%, oklch(50% 0 0));
--accent: var(--base);
--accent-hover: color-mix(in oklch, var(--base), white 20%);
}

隣接するカラートークンのブレンド

:root {
--success: oklch(60% 0.2 145);
--warning: oklch(70% 0.2 85);

/* Blend between semantic colors for status transitions */
--status-improving: color-mix(in oklch, var(--warning) 60%, var(--success));
}

AIがよくやるミス

  • color-mix() で単一ベースからティントとシェードを導出する代わりに、すべての色シェードを個別の hex 値としてハードコードしている
  • in oklchin oklab の方が視覚的に均一な結果を生むのに、ブレンドに in srgb を使っている — sRGBブレンドは特に彩度の高い色間でくすんだ中間点を作る
  • カラースペースパラメータを完全に省略している — これは仕様で必須です
  • パーセンテージの意味を混同している:color-mix(in oklch, red 70%, blue) は70%の赤と30%の青を意味し、青の70%を加えるという意味ではない
  • color-mix() がネイティブで処理できる色操作に JavaScript や CSSプリプロセッサ(sass darken()lighten())を使っている
  • transparent とミックスすることで色の半透明バージョンが作れることを知らない — AIエージェントは今でも rgba() や手動のアルファ値を使いがち
  • 明度を調整したシンプルな oklch() 値の方がより明確で保守しやすい場面で color-mix() を使っている

使い分け

  • デザインシステム: 単一のブランドカラーからシェードスケール全体を導出
  • インタラクティブステート: hover、active、focus、disabled のカラーバリアントを体系的に生成
  • 半透明オーバーレイ: rgba 値をハードコードせずにセマンティックカラーのアルファバリアントを作成
  • テーマカスタマイズ: ユーザーにベースカラーを選ばせ、そこからすべてのUIカラーを導出
  • セマンティックトークンのブレンド: ステータス遷移のために success/warning/danger カラー間をミックス

使わない方がよい場面

  • ベースに関連付ける必要のないシンプルな静的カラー — oklch()hex を直接使いましょう
  • すべてのシェードが、白/黒との単純なミックスに従わない、デザイナーが正確に指定した値を必要とする場合
  • 正確な仕様に一致する必要がある重要なブランドカラー(ミックス結果は補間カラースペースに依存します)

参考リンク