HSL / HSV より人間に寄り添った色表現 CIE L*C*h を使いたい

CIE L*C*h カラーモデルベースの色相環カラーピッカーを作りました。
[<img alt="lch-color-wheel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53009/7f13c9b3-35fd-a638-426d-8b269d0894ce.png" width="200">](https://luncheon.github.io/lch-color-wheel/)
https://luncheon.github.io/lch-color-wheel/

この記事はその経緯です。

## HSL 色表現と色相変数

CSS で使える色表現の 1 つに [HSL カラーモデル](https://ja.wikipedia.org/wiki/HSL%E8%89%B2%E7%A9%BA%E9%96%93) があります。 HSL では色相（Hue）、彩度（Saturation）、輝度（Lightness）の 3 軸で色を表現します。

色相を CSS カスタムプロパティ（変数）にすれば、彩度と輝度を固定して色相だけ変えることが簡単にできます。

```css
.btn {
  background-color: hsl(var(--hue), 100%, 60%);
  border: 2px solid hsl(var(--hue), 100%, 40%);
}
.btn:hover {
  box-shadow: 0 0 8px hsl(var(--hue), 100%, 40%);
}

.outline {
  background: white;
  color: hsl(var(--hue), 100%, 40%);
}

.primary {
  --hue: 210;
}

.accent {
  --hue: 330;
}
```

```html
<button type="button" class="btn primary">Primary</button>
<button type="button" class="btn accent">Accent</button>
<button type="button" class="btn primary outline">Primary Outline</button>
<button type="button" class="btn accent outline">Accent Outline</button>
```

[![スクリーンショット 2020-09-07 11.14.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53009/36880947-5e4e-029c-9063-1f52e386657c.png)](https://codepen.io/luncheon/pen/VwarOPL)
[CodePen](https://codepen.io/luncheon/pen/VwarOPL)

それで、以前、色相環を利用したカラーピッカーを作りました。彩度と明るさを固定して色相を選ぶ、あるいは色相を固定して彩度と明るさを調整するのに最適化しています。（このカラーピッカーは HSL ではなく [HSV カラーモデル](https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93) を採用しています。 HSL モデルのカラーピッカーは私のメンタルモデルに合いませんでした。 HSL と HSV とで色相は同じ値になるので「彩度と明るさを固定して色相を選ぶ」という目的には適います。）
[<img alt="reinvented-color-wheel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53009/4604b420-0d3b-3d9a-6af4-74b597f3b9f3.png" width="200">](https://luncheon.github.io/reinvented-color-wheel/)
https://luncheon.github.io/reinvented-color-wheel/

ところが HSL + 色相変数というアイディアは思ったほどうまくいきませんでした。

同じ輝度でも、黄色や黄緑は明るく、青や紫は暗く見えます。たとえば先ほどのボタンの例を `.accent { --hue: 100; }` にすると...
![スクリーンショット 2020-09-07 11.10.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53009/f9a58aa4-5c2e-de45-ea0e-8651acce1639.png)
同じ「明るさ」には感じられないと思います。黄緑のボタンの白い文字「Accent」はコントラストが弱くて非常に読みづらくなっています。

HSL / HSV カラーモデルでは、結局は色相に合わせて輝度 / 明度も調整する必要があるのです。
色相を変えるたびに明度の調整が必要となるようでは、カラーピッカーの使い勝手としてもよろしくありません。

## CIE L*C*h カラーモデル

そんな私の悩みを解決するのが CIE L*C*h カラーモデルです。 L* は明度（Lightness）、 C* は彩度（Chroma）、 h は色相（hue）を表します。というとまるで HSL や HSV と同じように聞こえますが、 CIE L*C*h 色空間は人間の知覚に合わせて設計されているそうです。私は色に詳しいわけではないので詳しい解説はできませんが、実際に利用してみると使い勝手が全然違います。
CIE L*C*h 色空間は CIE L*a*b* 色空間から軸の取り方を変えた派生です。 CIE L*C*h の解説記事はあまり見当たりませんでした。

* 色の数値化には、表色系を使用します。1-楽しく学べる知恵袋 | コニカミノルタ  
  https://www.konicaminolta.jp/instruments/knowledge/color/section2/02.html
* Lab色空間 - Wikipedia  
  https://ja.wikipedia.org/wiki/Lab%E8%89%B2%E7%A9%BA%E9%96%93

Wikipedia からこの記事にとって重要な部分を引用します。

> RGBやCMYKとは異なり、Lab色空間は人間の視覚を近似するよう設計されている。知覚的均等性を重視しており、L成分値は人間の明度の知覚と極めて近い。したがって、カラーバランス調整を正確に行うために出力曲線を a および b の成分で表現したり、コントラストの調整のためにL成分を使ったりといった利用が可能である。

そんなわけで冒頭の話に戻るのですが、 CIE L*C*h カラーモデルベースの色相環カラーピッカーを作りました。
[<img alt="lch-color-wheel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53009/7f13c9b3-35fd-a638-426d-8b269d0894ce.png" width="200">](https://luncheon.github.io/lch-color-wheel/)
https://luncheon.github.io/lch-color-wheel/

CIE L*C*h カラーモデルを採用したことで、知覚的な明るさを維持したまま色相を変えられるようになりました。プライマリカラーが決まっている状態でアクセントカラーを選ぶような用途では HSL や HSV カラーモデルのカラーピッカーより活躍すると思います。

## CSS で CIE L*C*h 色表現が利用可能に（いずれなるかもしれない）

CSS にも `lch()` 色関数が提案されています。

CSS Color Module Level 4 （日本語訳）
https://triple-underscore.github.io/css-color-ja.html

色相を CSS カスタムプロパティにすれば、彩度と明度を固定して色相だけ変えることが簡単にできるようになるかもしれません。

さらには `color-adjust(peru lightness -20%);` のように色を調整できるようになるかもしれません。

CSS Color Module Level 5 （日本語訳）
https://triple-underscore.github.io/css-color5-ja.html

でもこれらはまだもう少し先の話。