ジャンルから探す

Web Design English

CSS color()関数の使い方と実用例【2023年のアプデ】

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だけです。rec2020prophoto-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()セレクターを組み合わせると便利です。