OKLCHと現代のCSSカラー — なぜあなたのパレットがいくつかのブラウザで見栄えが悪いのか
RGBとHSLはCRTモニタ用に設計されました。OKLCHが視覚的均一性を解決する理由、color-mix()がグラデーションのブレンドを変えること、そしてプリプロセッサなしで相対色構文が解放されることを説明します。
あなたはメインボタンに青色を選択しました。ブラウザでは適切に見えます。しかし、新しいMacBook Proでスタージング環境を開くと、少しぼやけたように見えます。デザイナーがiPhoneからスクリーンショットを送り、同じボタンが明らかに鮮やかに見えます。同じヘキサコードでも、表示が異なります。
これはP3のギャップです。そして、これはCSSの色モデルがあなたを裏切っている理由の最も興味の薄い部分です。大きな問題はHSLの数学的根拠にあります。
sRGBの上限
すべてのヘキサコードと rgb() これまでに書いた値は、sRGB色空間に存在しています——1996年にCRTモニタ用に構築された標準です。sRGBは人間の目で見える色の約35%をカバーしています。P3色空間は2017年以降のすべてのiPhoneおよび2016年以降の大多数のMacBookで使用されており、約45%をカバーしています。
あなたが書く #3b82f6、その色はsRGBに制限されます。P3ディスプレイでは、ブラウザがより濃い青を表示できる理論がありますが、あなたのCSSはそれを求めていません。そのため、デバイスの能力を無駄にしています。
P3色を直接アクセスするには color(display-p3 0.2 0.4 0.9)を使用します。これは機能しますが、OKLCHが重要である理由ではありません。大きな失敗はHSLの基本的な前提にあります。
HSLの明度は嘘です
HSLはヘキサコードよりも本質的に改善されたものです。色調、彩度、明度——人間が直感的に理解できる概念です。問題は、「L」があなたが思っているものとは異なります。
黄色を hsl(60, 100%, 50%) と青を hsl(240, 100%, 50%) を並べてください。どちらも正確に50%の明度です。
.yellow { background: hsl(60, 100%, 50%); }
.blue { background: hsl(240, 100%, 50%); }
黄色はほぼ白に見え、青は中程度の暗さに見えます。視覚的にまったく同じ明るさではありません。これはHSLの視覚的非一貫性——L軸が人間の視覚が色の明るさを処理する方法とは一致していないということです。
色スケールの構築において、これは実際のメンテナンス問題を生み出します。HSLでL値を9段階にステップアップして生成した場合、黄色やシアンは過剰に明るく、青や紫は濁って見えます。そのため、手動で値を調整しなければならず、システム的なアプローチの目的を失ってしまいます。
OKLCH:視覚に合わせた設計
OKLCHは2020年にBjörn Ottossonによって設計されました。CIELAB(1970年代に開発された視覚的色空間)を基にしていますが、その知られている色調シフトを修正しています——特に、彩度を調整すると視覚的に色調が変化する「紫・青の問題」です。
3つのチャンネル:
- L(明度) —— 0から1まで、視覚的に一貫しています。黄色のL 0.5と青のL 0.5は、実際には同じ明るさに見えます。
- C(彩度) —— 0(灰色)から、高度に飽和した色に至るまで0.3〜0.4に増加します。固定上限はありません——色調と目標色空間によって上限が変化します。
- H (色相) —— 0から360度まで、HSLの色調とほぼ同等です。
以下はTailwindのblue-500が両システムでどのように見えるかです:
/* sRGB hex */
background: #3b82f6;
/* OKLCH equivalent — same color, different notation */
background: oklch(0.623 0.214 259.1);
/* Push chroma past sRGB — more vivid blue on P3 displays, clips gracefully on sRGB */
background: oklch(0.623 0.27 259.1);
その最終値はsRGBの色空間を超えています。P3対応のブラウザでは、より鮮やかな色が表示され、古いブラウザではsRGBの近い値に切り捨てられます。プログレッシブエンハンスメントで、まったくの無労働です。
color-mix() と色空間がブレンドを変える理由
color-mix() Chrome 111、Firefox 113、Safari 16.2で導入されました。2つの色を比率で混ぜるというシンプルな機能ですが、指定された色空間が結果を大きく変えることがあります。
/* Mixes through sRGB — midpoint is a washed-out brown-grey */
background: color-mix(in srgb, oklch(0.7 0.2 30), oklch(0.7 0.2 270));
/* Mixes through the OKLCH color wheel — midpoint is a vivid purple */
background: color-mix(in oklch, oklch(0.7 0.2 30), oklch(0.7 0.2 270));
sRGBでオレンジと青を混ぜると、チャンネル値の平均を取るため、中間点は脱色されたブラウングレーになります。OKLCHでは、色輪に沿って補間し、鮮やかな紫に到達します。正しいかは意図に依存しますが、UIのトランジション、グラデーション、ホバー状態などでは、OKLCHの補間がほぼ常に望ましいです。
実用的な用途:ハードコードせずに無効状態を生成する。
.button--disabled {
background: color-mix(in oklch, var(--color-primary) 40%, white);
cursor: not-allowed;
}
相対色構文
相対色構文(Chrome 119+、Firefox 128+、Safari 16.4+)は、既存の色の個々のチャンネルを変更することで新しい色を導出できます:
:root {
--brand: oklch(0.623 0.214 259.1);
}
.button:hover {
/* Lighten by 8% lightness units */
background: oklch(from var(--brand) calc(l + 0.08) c h);
}
.button:active {
/* Darken and reduce chroma slightly */
background: oklch(from var(--brand) calc(l - 0.08) calc(c - 0.02) h);
}
.button--muted {
/* Drop chroma to near-zero: perceptual grey at the same lightness */
background: oklch(from var(--brand) l 0.03 h);
}
これはSassの lighten(), darken()と、 desaturate() をネイティブCSSに置き換えます——プレプロセッサ、ビルドステップ、並行するヘキサコードを維持する必要がなくなります。さらに、OKLCHで「明るくする」操作は、すべての色調において実際に明るく見えるようになります。
一つの実際の制限:複雑なチャンネル制約(例:彩度を制限して色空間内に保つ)は、長くなる calc() チェーンが必要で、すぐに複雑になります。シンプルな明度と彩度の変更には構文がきれいです。より高度な機能には、ビルド時に計算し、CSSカスタムプロパティを生成する方が保守性が高くなります。
2026年のブラウザサポート
| 特徴 | Chrome | Firefox | Safari |
|---|---|---|---|
oklch() | 111+ | 113+ | 15.4+ |
color-mix() | 111+ | 113+ | 16.2+ |
| 相対色構文 | 119+ | 128+ | 16.4+ |
color(display-p3) | 111+ | 113+ | 10+ |
2026年中盤時点で oklch() のグローバルサポートは90%を超えています。例外は、古いChromiumベースの企業向けブラウザおよび113未満のFirefoxです。もしユーザーベースにそれらが含まれているなら、2行のフォールバックで十分です:
.button {
background: #3b82f6; /* sRGB fallback */
}
@supports (background: oklch(0 0 0)) {
.button {
background: oklch(0.623 0.214 259.1);
}
}
実際の状況:あなたの分析がChrome 111+、Firefox 113+、Safari 15.4+を確認した場合、フォールバックを完全にスキップできます。 @supports ラッパーは、ブラウザバージョンを制御できない内部ツールで安心感を提供するために存在します。
既存のパレットへの変換
OKLCHの採用における摩擦ポイントは、現在のヘキサコード値からOKLCH座標へ変換し、各色のチャンネルが意味を持つように理解することです。 統一色空間変換器 は、両方向の変換を処理しており、ヘキサコードまたはHSL値を貼り付け、OKLCHを出力し、LとCを実際の参照点から調整できます。HSL、RGB、Lab、LCH、HSV、OKLCHを1か所でサポートしており、Figmaファイルからヘキサコードを受け取ってOKLCH値に変換する際に役立ちます。
実際に移行する方法
すべてを一度に書き直す必要はありません。実用的な順序は次の通りです:
- インタラクティブな色から始めましょう —— メイン、セカンダリ、および破壊的なトークンです。これらはすでにホバー、アクティブ、無効状態のバリエーションを生成しています。OKLCHと相対色構文は、その論理をネイティブCSSで即座に置き換えます。
- 静的色は現在のところヘキサコードで残してください —— テキスト、背景、ボーダーです。これらはプログラム的に操作されていないため、変換の報酬がまだありません。
- 次の新しいシステムをOKLCHからゼロから構築しましょう —— ここでは視覚的均一性のメリットが構造的に現れます。中立スケールのステップ500が実際に視覚的に中央に位置し、すべての色調で飽和した色が手動調整なしで一貫しています。
目的はOKLCHのためではなく、色システムが目で見えるように数学的に設計されていること——そのため、わずかに明るい青を必要とするたびに手動で補正しなくてもよいのです。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
