社内シェア

OKLCH

CSS の新しい色の書き方 oklch(0.7 0.12 250)

Lloyd ・ 2026

HSL の問題

同じ「L 50%」でも、
明るさは揃わない

HSL の L は、RGB の最大と最小の真ん中 — 目の感度は入っていません。
色相だけ 0°→360° に回して、その「50%」の見え方を確かめます。

HSL の問題

明度 50% × 360 色
HSL
hsl(H 100% 50%)
↑ 彩度を抜くと
OKLCH
oklch(0.7 0.12 H)
↑ 彩度を抜くと
60°
hsl(60 100% 50%)
oklch(0.7 0.12 60)
HSL の「明度」は、色相を変えると体感が大暴れする黄のあたりはまぶしく、青のあたりは真っ暗。数字は同じ 50% なのに

HSL の L は、
人の目を見ていない。

(max + min) ÷ 2 — RGB の最大と最小の真ん中。明るさの「体感」とは無関係。
だから lighten() や「hover で 5% 明るく」が色相ごとに壊れる。

どうやって測った?

「見た目で均等」は、
どうすれば作れる?

「知覚的に均等」は物理の式からは導けません。人に色を見せて「同じ?」「どれくらい違う?」と聞き続けるしかない。
その 100 年ぶんの答えを積み上げた先に、OKLCH があります。

どうやって測った? ①

Munsell(1905)— 並べるのが先、測るのが後

どうやって測った? ②

「この灰色、白の何%の明るさに見える?」

光の量で等間隔
(物理)
見た目で等間隔
(知覚)
見た目の明るさ50%
物理の光量
12.5%
「見た目のちょうど半分」は、物理では 8 分の 1暗いほうに敏感な目を打ち消すのが立方根カーブ。LUTCHI(1991)は延べ 43,332 回の「見た目採点」を集めた — 人どうしのばらつきは明度で ±13%

どうやって測った? ③

100 年ぶんの実験を、行列 2 回に蒸留する

1905Munsell
色票
1931CIE XYZ
「同じ」の地図
1942MacAdam
楕円
1976CIELAB
立方根
1998IPT・等色相
データ
2017CAM16-UCS
2020OKLab

「入れ替えテスト」で最適化

明度が同じはずの 2 色の L を入れ替えても何も変わらなければ合格。予測精度より、明るさ L・鮮やかさ C・色相 H の独立を優先した。

立方根 1/3 の正体

最適化の答えは 0.323。青が内側に折れるのを直すため手で 1/3 に固定 — 誤差はほぼ変わらず。整形手術済み。

OKLCH は「発見」ではなく「蒸留」CAM16 の予測と Ebner–Fairchild(1998)の等色相データを、行列→立方根→行列の速い形に押し込んだから CSS で気軽に使える

OKLCH とは

ツマミ 3 本 =
立体の中の「住所」

L は高さ、C は軸からの距離、H は角度 — 円柱座標そのもの。
1 本だけ動かしても、ほかの 2 本は釣られません。

OKLCH とは

L=高さ・C=軸からの距離・H=角度
oklch(0.70 0.120 250) #61a3e6
L 高さ(0–1)0.70
C 軸からの距離(0–0.4)0.120
H 角度(0–360°)250°

ドラッグで回転。いまの色相のところで切り開いてあります — H を回すと切り口も回る。OKLCH に切り替えると、さっきの色票のギザギザがこの断面に現れる。

なぜこの形?

角の高さが揺れるのは、
目のせい

ディスプレイがくれるのは、ただの四角い箱。それを人間の目のレンズ越しに見ると、角の高さが波打つ。
この揺れがどこから来るのか、目の中まで降りて見ていきます。

なぜこの形?

「一番鮮やか」をつなぐ稜線は、ジェットコースター
L 0.968
シアンL 0.905
L 0.866
マゼンタL 0.702
L 0.628
L 0.452

光っているのは各色相の「一番鮮やかな色」— RGB 立方体では中腰の 6 辺そのもの。OKLCH に切り替えると高さ(=明るさ)が 0.45〜0.97 まで波打ち、HSL では逆にまっ平らな「彩度 100% の輪」に化ける。

なぜこの形?

目は波長を測っていない — 光を 3 つの数に潰す

波長530 nm
強さ100%

目印は 530nm・100% の値。600nm で M を揃えると L は 2.3 に跳ぶ

錐体 1 個が返すのは、数字 1 つだけ「感度の高い波長を少し」と「低い波長をたくさん」は同じ答え(単変量原理)。スペクトルはここで (L, M, S) の 3 つに潰れ、波長そのものの情報は永久に失われる

なぜこの形?

スペクトルが違っても、3 つの数が同じなら「同じ色」
単波長の黄 575 nm
630 nm + 緑 530 nm
1 本の波長
2 本を混ぜた光
波長575 nm
赤 630nm の強さ100%
緑 530nm の強さ100%
目にとっては「似ている」ではなく、同一の測定結果分光計なら一瞬で見分けるが、目には区別する手段がそもそも無い。RGB ディスプレイが 3 原色で足りるのはこのおかげ — 画面の #ffff00 も主波長 570nm・純度 79% の「淡い黄」でしかない

なぜこの形?

3 つの数は「色」と「明るさ」、2 本の通路に分かれる

R・G・B の 3 本のライト。錐体の反応は白を 100% として表示 — B だけにすると S は 87% も光るのに、明るさの通路には 7% しか届かない

S → 明るさ: ×0 L 錐体 100% M 錐体 100% S 錐体 100% 色の通路 3 つの数の比 = L − M / S − (L+M)/2 明るさの通路 重み付き和 = 0.70 L + 0.30 M + 0.00 S 100%
青が暗いのは、目の配線明るさの通路は L と M からしか引かれていない(測光の定義上、S の係数はぴったり 0)。S 錐体は全錐体の 5〜10%、中心窩の真ん中には 1 個も無い — 青は「色」では鮮やかでも「明るさ」では票を持たない

今日から使える ①

グラデーションの
「泥ゾーン」が消える

同じ 2 色でも、あいだの通り道はブラウザ任せ。
通り道を OKLCH に変えるだけで、中間の濁りが消えます。

今日から使える ①

グラデーションの泥ゾーン
いつもの
sRGB 補間
in oklch
足しただけ
始点の色相264°
終点の色相90°
background: linear-gradient(in oklch 90deg, blue, yellow);
書き足すのは in oklch の 8 文字だけcolor-mix() にも同じ指定ができる:color-mix(in oklch, var(--brand) 70%, white)

今日から使える ①

泥ゾーンを立体で見る
sRGB 補間
in oklch
始点の色相264°
終点の色相90°

ドラッグで回転。RGB 立方体では sRGB 補間がまっすぐな最短経路。OKLCH に切り替えると、その直線が無彩色の軸のそばをかすめて曲がる——それが泥の正体。

今日から使える ②

1 色から、状態色を全部「計算」する

.btn:hover    { background: oklch(from var(--brand) calc(l + 0.08) c h); }
.btn:active   { background: oklch(from var(--brand) calc(l - 0.06) c h); }
.btn:disabled { background: oklch(from var(--brand) l calc(c * 0.25) h); }
.btn:focus    { outline-color: oklch(from var(--brand) l c h / 0.4); }
hover active disabled focus
ブランド色を差し替えても、hover も disabled も勝手についてくる注意:l は 0–1 の数値。calc(l - 10%) は無効、calc(l - 0.1) と書く

本命はこれ

色相を 1 個変える = テーマが丸ごと変わる

--h: 250
50
100
200
300
400
500
600
700
800
900
950
請求書 #0042支払い済み
明暗の設計(L の階段)はそのまま、色だけ着せ替わるTailwind v4 のデフォルトパレットもこの方式で再設計された

OKLCH の限界 ①

同じ L でも、コントラストは揃わない

WCAG のコントラスト比は輝度 Y から出す、OKLCH とは別の物差し。
下の 4 色は L=0.62・C=0.14 で固定、違うのは色相だけ。

3.90赤 20° 3.66黄 90° 3.45緑 142° 3.70青 264°
それでも白背景とのコントラスト比は 3.45〜3.90 に散る4.5 ぎりぎりの色は必ず実測する。OKLCH は「予測しやすくする」道具であって、検証を省く道具ではない

OKLCH の限界 ②

L が同じ = 同じ明るさ、とは限らない

この 2 枚、どっちが明るく見える?
OKLab L 0.452 ・ 物理の光量 7.2%
OKLab L 0.452 ・ 物理の光量 9.2%
「観察条件と背景色に依存しない、完全に均等な明度スケールは存在し得ない」— Björn Ottosson物理は灰のほうが 28% 明るいのに、多くの人には青が明るく見える(Helmholtz–Kohlrausch 効果、OKLab は非対応)

で、使えるの?

もう普通に使える(Baseline 広く利用可能)

Chrome111〜
Safari15.4〜
Firefox113〜
Edge111〜
2023-05そろって 3 年
.card {
  background: #61a3e6;               /* 古いブラウザはここで停止 */
  background: oklch(0.7 0.12 250);   /* 対応ブラウザは上書き */
}
道具はまず oklch.com だけ覚えれば OKEvil Martians 製のピッカー。色域の崖がどこにあるかも見える

色選びが、
手作業から工学になる。

種明かし:このスライドの色も、ぜんぶ oklch() で書いてます。

アクセントの色相(今:85°
1 / 14