CSSで広色域の色を扱うなら color(display-p3 ...)、色を「作る・調整する」なら oklch()。この2つを使い分けるのが2026年時点の実務的な答えです。
まず対応状況をはっきりさせておきます。color()関数は Chrome / Edge 111(2023年3月)、Firefox 113(2023年5月)、Safari 15 で対応済みで、グローバル利用率は94%を超えています。「Firefoxは対応予定」という情報は古いので注意してください。
この記事では、color()の基本構文から、より使用頻度の高いoklch()・color-mix()・相対カラー構文までを、実際に書けるコードで整理します。
スポンサーリンク
color() 関数の基本構文
color()は、「どの色空間の座標なのか」を明示して色を指定する関数です。RGBの3値を0〜1の範囲で書きます(0〜255ではありません)。
color(<色空間> <値1> <値2> <値3> / <不透明度>)
.button {
background-color: color(display-p3 1 0.5 0); /* 鮮やかなオレンジ */
border-color: color(display-p3 0.5 0.2 0.8 / 0.6);
}
| 色空間 | 特徴 | 主な用途 |
|---|---|---|
srgb |
従来のWeb標準 | 互換性重視 |
srgb-linear |
ガンマ補正なしのsRGB | 合成・ブレンド計算 |
display-p3 |
sRGBより約25%広い色域 | Web用途で実質これ一択 |
rec2020 |
超広色域 | 映像制作 |
a98-rgb |
Adobe RGB相当 | 写真・印刷 |
prophoto-rgb |
非常に広い色域 | 写真編集 |
xyz / xyz-d50 / xyz-d65 |
デバイス非依存の基準空間 | 色変換の中間 |
Webサイトの実装で意味があるのは実質display-p3だけです。rec2020やprophoto-rgbを指定しても、それを表示できるディスプレイがほぼ存在しません。
フォールバックは本当に必要か
必要です。ただし理由は「非対応ブラウザ」より「非対応ディスプレイ」の方が大きいです。
広色域を表示できないモニターでは、display-p3の色はsRGBの範囲に自動でクリップされます。つまり壊れはしませんが、狙った鮮やかさにはなりません。むしろ、クリップの結果として意図と違う色味に寄ることがあります。
基本形は、単純に2行並べる書き方です。
.button {
background-color: rgb(255 128 0); /* 非対応ブラウザ用 */
background-color: color(display-p3 1 0.5 0); /* 対応ブラウザで上書き */
}
クリップを避けて「広色域ディスプレイのときだけ鮮やかにする」なら、@media (color-gamut: p3)で分岐します。
.button {
background-color: rgb(255 128 0);
}
@media (color-gamut: p3) {
.button {
background-color: color(display-p3 1 0.5 0);
}
}
この書き方だと、ディスプレイが実際に広色域を出せるときだけP3の色が使われます。ブランドカラーの微妙な差が問題になる場面では、こちらの方が安全です。
スポンサーリンク
実務で使用頻度が高いのは oklch()
color()は「色域を広げる」ための関数ですが、日常的なUI設計で効くのはoklch()です。hsl()の使い勝手を残したまま、その最大の欠点を解消しています。
oklch(<明度> <彩度> <色相> / <不透明度>)
/* 例 */
--brand: oklch(0.65 0.2 250); /* 明度65% 彩度0.2 色相250度(青) */
hsl()の欠点とは、「明度(L)が同じでも、色相によって実際の明るさが全然違う」ことです。hsl(60 100% 50%)の黄色とhsl(240 100% 50%)の青は、同じ明度指定なのに、黄色の方が圧倒的に明るく見えます。
oklch()は人間の知覚に合わせた色空間なので、明度の数値が見た目の明るさと一致します。この性質のおかげで、次のようなことが安全にできます。
:root {
--hue: 250;
/* 明度だけを変えれば、色相が変わっても明るさの階段は崩れない */
--c-100: oklch(0.95 0.03 var(--hue));
--c-300: oklch(0.80 0.10 var(--hue));
--c-500: oklch(0.65 0.20 var(--hue));
--c-700: oklch(0.50 0.16 var(--hue));
--c-900: oklch(0.30 0.10 var(--hue));
}
--hueを変えるだけでテーマカラー全体が入れ替わり、しかもコントラスト比の関係が保たれます。hsl()で同じことをすると、色相を変えた瞬間に文字が読めなくなる組み合わせが出てきます。
さらにoklch()はsRGBの外側の色も表現できるので、広色域ディスプレイでは自動的に鮮やかに出ます。「広い色域」と「扱いやすさ」を両立したい場合、color(display-p3 ...)ではなくoklch()を選ぶ方が実用的です。
色関数の使い分け早見表
| 関数 | 指定するもの | 選ぶ場面 |
|---|---|---|
rgb() / hex |
赤緑青 | デザインツールから受け取った値をそのまま使う |
hsl() |
色相・彩度・明度 | 今から選ぶ理由は薄い(明度が知覚と合わない) |
color() |
色空間+座標 | 広色域の色を明示したいとき |
lab() / lch() |
知覚的な明度・彩度・色相 | 印刷・色差計算 |
oklch() |
知覚的な明度・彩度・色相(改良版) | UIのカラーパレット設計 |
color-mix() |
2色の混合 | ホバー色・淡色の生成 |
スポンサーリンク
color-mix() でホバー色を自動生成する
ホバー時に少し暗くする、といった処理のために色を2つ定義するのは面倒です。color-mix()を使えば1色から作れます。
.button {
--bg: oklch(0.65 0.2 250);
background-color: var(--bg);
}
.button:hover {
/* 元の色に黒を12%混ぜる */
background-color: color-mix(in oklab, var(--bg), black 12%);
}
.button:disabled {
/* 背景色に馴染ませて淡くする */
background-color: color-mix(in oklab, var(--bg) 30%, canvas);
}
混合する色空間にin oklabを指定するのがコツです。in srgbで混ぜると、中間色が濁ってグレーに寄ります。グラデーションでも同じことが起きます。
/* 中間が濁る */
background: linear-gradient(to right, blue, yellow);
/* 中間まで鮮やかなまま */
background: linear-gradient(in oklab to right, blue, yellow);
相対カラー構文で既存の色から派生させる
fromキーワードを使うと、既存の色を分解して一部だけ書き換えた色を作れます。CSS変数と組み合わせると、テーマ定義が一気に短くなります。
:root {
--brand: oklch(0.65 0.2 250);
}
.card {
/* 明度だけ上げた淡い背景色 */
background: oklch(from var(--brand) 0.95 c h);
/* 彩度を落とした枠線 */
border-color: oklch(from var(--brand) l calc(c * 0.4) h);
/* 補色(色相を180度回す) */
--accent: oklch(from var(--brand) l c calc(h + 180));
}
l c h は元の色の各成分を指す変数として使えます。1つのブランドカラーからパレット全体を導出できるので、テーマ切り替えの実装が大幅に簡単になります。
対応状況と機能検出
ここまで挙げた機能は、いずれも主要ブラウザで対応済みです。
| 機能 | Chrome / Edge | Firefox | Safari |
|---|---|---|---|
color() |
111 | 113 | 15 |
oklch() / oklab() |
111 | 113 | 15.4 |
color-mix() |
111 | 113 | 16.2 |
相対カラー構文(from) |
119 | 128 | 16.4 |
古い環境を切り捨てたくない場合は@supportsで分岐します。
.button { background-color: #ff8000; }
@supports (background-color: oklch(0.65 0.2 250)) {
.button { background-color: oklch(0.65 0.2 250); }
}
確認するときは、DevToolsのカラーピッカーで色空間を切り替えられます。広色域ディスプレイでないと差が見えないので、sRGBモニターでレビューして「変わっていない」と判断しないよう注意してください。
まとめ
color()は Chrome/Edge 111、Firefox 113、Safari 15 で対応済み。「Firefox未対応」は古い情報- Web用途で意味があるのは
display-p3だけ。値は0〜1で書く - 非対応ディスプレイではsRGBにクリップされる。
@media (color-gamut: p3)で分けると確実 - UIのパレット設計は
oklch()。明度の数値が見た目の明るさと一致する - ホバー色や淡色は
color-mix(in oklab, ...)で生成する。in srgbだと濁る - 相対カラー構文
oklch(from var(--brand) ...)で1色からパレットを導出できる
「広い色を使う」ことが目的ならcolor()、「色を設計する」ことが目的ならoklch()。この切り分けで迷わなくなります。状態に応じたスタイル切り替えにはCSS :has()セレクターを組み合わせると便利です。