あまりわかってないくせにRGBでグラデーションするのは間違いでHSLが正解だと思うのはやめてほしい

2つの色の間のグラデーションにlinear-gradientを使ったときにグラデーションが汚ないのは、大抵の場合ガンマカーブを考えずにグラデーションをかけているからであって表色系の問題ではない。色相に沿ってグラデーションをかけたい場合はもちろんあるだろう。でもそうじゃない場合にも色相を回すのが正しいと思ってしまうのは良くない。

 

ガンマカーブとはなにか。それはEIZO株式会社の解説ページなどを見てほしい。

第7回 "曲線美"が色再現性の決め手になる?――液晶ディスプレイの「ガンマ」を知ろう | EIZO株式会社

 

CSSのlinear-gradientはRGB値をリニアに変化させる。ところが今のPCはRGBで指定された値とディスプレイに表示されるピクセルの明るさがリニアに対応しない。ディスプレイのガンマがWindows標準の2.2になっている場合、RGBに指定する0~255の値に対して実際に表示される明るさは下記のようになっている。

RGB値 明るさ(%)
0 0
64 5
128 22
192 54
255 100

 

単純にCSSにlinear-gradientを指定して赤100%→緑100%にグラデーションすると下記のようなかんじになるんだけど、もちろん中央がくすんで汚い。

linear-gradient(to right, #ff0000, #00ff00);

 

 

でもなこの中央がくすんでしまう理由は、この中央の色が「赤50%、緑50%の微妙な色」だからなのではなく、上の表を見てくれればわかるように「赤22%, 緑22%のめちゃ暗い色」だからなんだ。つまり左から右にいくにしたがって、一旦輝度が減少して、中央を超えたところから輝度が増加する、というヤバい表示になってしまっているからなんだ。

 

まともなグラデーションを表示したい場合には上のEIZOのページに書かれているように、ガンマ特性に合わせて色情報を調整したグラデーションをかけてやる必要がある。

f:id:naoya2k:20220411025516p:plain

EIZOのページの解説

 

じゃあどうすればいいのか。上にある表の逆バージョンの、明るさからRGB値を探せる対応表をつくって中間調を持ち上げたグラデーションをつくってやればいいんだ。

明るさ(%) RGB値 HEX値
0 0 0
25 135 87
50 186 BA
75 223 DF
100 255 FF

これによれば、中央は#808000ではダメで、#BABA00であるべきだということだから、これを指定してやる。

linear-gradient(to right, #ff0000, #e08800, #baba00, #88e000, #00ff00)

 

 

上のグラデーションと比べて断然良くなってるし、これでわりと自然なんじゃないか。

 


 

最近何度か話題になっていた下記のようなページではHSL色空間を使うのが正しいというようなことが書かれていた。

qiita.com

f:id:naoya2k:20220411031623p:plain

でも僕はこれは違うと思うんだよなあ。だって真ん中のところ明るすぎるじゃん。不自然じゃん。真ん中の色は#ffff00だろ? #ff0000→ #ffff00→ #00ff00にしてるじゃん。平坦な道を行きたいのに完全に峠を登って下るみたいなことになってんじゃん。

これが「いい感じ」と思えるような人、そしてこういう効果を狙ってやってるならこれはこれでいいんだけど、でもこれが「正しい」って思っちゃうのは、ダメだ。

 

 


 

途中が完全に灰色になってしまうので不評な青→黄色のグラデーションも試してみよう。素のlinear-gradientではこうなる。

linear-gradient(to right, #ffff00, #0000ff)

 

 

ガンマを考慮した場合はこうだ。

linear-gradient(to right, #ffff00, #e0e088, #bababa, #8888e0, #0000ff)

 

 

これは全然それなりに正しい感じになっていて*1、でも中央の色は完全に灰色の#bababaなんだ。だから、グラデーションが不自然なのは、灰色が出現するからじゃなくて、リニアにグラデーションできてないからなんだ。

 

もちろんこれよりも色相を回してグラデーションをさせた下記の記事のようなもののほうが自然だというのであれば、それでもいい。でも僕は個人的には「黄色→青のグラデーション」に下のような緑や水色が出てくるのは、美しいかどうかはともかく、正しくないし、違うと思うんだよなあ。

 

f:id:naoya2k:20220411032540p:plain

グラデーションの中央がグレーに濁ってしまう仕組みをくわしく解説、美しいグラデーションをCSSで実装する方法 | コリス

 

 

 

*1:ここで微妙に弱気なのは、ガンマ補正を代表点5つの折れ線で妥協してしまっていることと、本当はRGBから計算された輝度、つまり 0.299×R + 0.587×G + 0.114×B がリニアに変化していてほしいんだけど、それができている確証がないからだ