🎨

Introduction to CSS Color Function 2022

2022/01/31に公開

CSS Color Module Level 4で定義されている色関数についてざっくりまとめました。
デザインシステムでカラーパレットを実装するときやグラデーションを実装するときに知っていると便利かもしれません。
詳しく知りたい人はW3Cの仕様書を読みましょう。

https://www.w3.org/TR/css-color-4/

補足:色空間とは

色空間(color space)とは色を立体的に表現したもので、空間内の座標で色を定義します。
色空間内の座標定義に使用される変数をチャンネルと言い、色空間を構成する色を数値や計算式などを用いて定量的に表現する方法を表色系と言います。

色が使われる場所(印刷物、ディスプレイ、など)や用いられる指標などに応じていくつかの色空間が定義されています。(RGB、Lab、HLSなど)
ある色空間から別の色空間へは数学的に変換することができますが、変換後の色空間で表現できない情報は失われてしまいます。

sRGB Colors

RGB色空間では赤、青、緑の3色を加色混合して色を表現します。赤、青、緑は光の三原色で、数値が大きくなるほど白に近づきます。

RGB色空間には複数の規格が存在しますが、CSSでは sRGB色空間 がサポートされています。sRGB色空間は国際電気標準会議(IEC)が定めた国際標準規格で、ディスプレイやプリンタなどで色を指定する際に用いられます。

rgb()

rgb()は、red、green、blueの3つのチャンネルを指定してsRGB色を定義します。

rgb(R G B / A)
.sample {
  color: rgb(0 100 202);
}

.sample {
  color: rgb(0 100 202 / 0.8);
}

最初の3つの引数は、順に[red、green、blue]のチャンネルに対応しています。スラッシュで区切られた4つ目の引数は色のalpha、すなわち透過度を指定します。省略した場合は100%になります。

古い構文であるrgba()も引き続きサポートされ、rgb()と同じ引数を受け取り、同じ動作をします。また古いカンマ区切りの構文もサポートされます。

.sample {
  color: rgba(0 100 202 / 0.8);
}

.sample {
  color: rgb(0, 100, 202, 0.8);
}

.sample {
  color: rgba(0, 100, 202, 0.8);
}

16進数表記

16進数を用いてsRGB色を定義することもできます。rgb()より簡潔に記述できますが人間には少し読みにくいです。

.sample {
  color: #0064ca;
}

16進数表記で透過度を指定することも可能です。(00は透過度0%、ffは透過度100%)

.sample {
  color: #0064cacc;
}

HSL Colors

RGBで色を指定する方法は人間にとってはあまり直感的ではなく、色の調整が難しいという問題があります。

HSL色空間は、色相(hue)、彩度(saturation)、明度(luminance) の3つのチャンネルを用いて色を定義します。色相、彩度、明度をそれぞれ独立して調整できるためRGBより直感的に色を調整できます。CSSではHSL色はsRGB色に解決されます

CSSではhsl()でHSL色を定義します。

hsl(H S L / A)
.sample {
  color: hsl(210 100% 40%);
}

.sample {
  color: hsl(210 100% 40% / 0.8);
}
  • H色相角度 (色相環の角度)を指定します。
    • 使用できる単位はdegradgradturnの4つで、単位がない場合はdegとして扱われます。
    • 0deg=red: #ff0000120deg=green: #00ff00240deg=blue: #0000ffとなるように色相環を巡回すると定義されています。
  • S彩度をパーセントで指定します。彩度100%は純色の鮮やかな色で、彩度0%は全く色のないグレーになります。
  • L明度をパーセントで指定します。明度100%は白、明度0%は黒、明度50%は「普通」を表します。
  • A透過度をパーセントで指定します。rgb()の透過度と同じものです。

色相

古い構文であるhsla()も引き続きサポートされ、hsl()と同じ引数を受け取り、同じ動作をします。また古いカンマ区切りの構文もサポートされます。

.sample {
  color: hsla(210 100% 40% / 0.8);
}

.sample {
  color: hsl(210, 100%, 40%);
}

.sample {
  color: hsla(210, 100%, 40%, 0.8);
}

デザイントークンの定義でHSLを使う

HSLを用いることでベースカラーから様々なバリエーションの色(暗い色、明るい色、グレースケールなど)を作る操作がやりやすくなります。
色相を固定して色を操作できるので統一感のあるカラーパレットが作成できます。
次の例では色相と彩度をカスタムプロパティに定義して固定し、明度を操作することでカラーパレットを作成しています。

:root {
  --base-h: 210;
  --base-s: 100%;
  --base: hsl(var(--base-h) var(--base-s) 40%);
  --base-dark: hsl(var(--base-h) var(--base-s) 20%);
  --base-light: hsl(var(--base-h) var(--base-s) 60%);
}

このカラーパレット作成方法について詳しく知りたい方はこちらの記事を読んでみてください。
https://web.dev/building-a-color-scheme/

HWB Colors

HWBはHue-Whiteness-Blacknessの略称で、基底となる色相混合される白さ混合される黒さの3つの変数を用いてsRGB色空間の色を定義します。
HSLと似ていますがHSLよりも人間が直感的に操作しやすいと言われており、カラーピッカーなどで利用されることが想定されているようです。

色選択UI

CSSではhwb()でHSL色を定義します。2022年1月31日時点ではFirefoxとSafariにのみ実装されています。

hwb(H W B / A)
.sample {
  color: hwb(210 0% 21%);
}

.sample {
  color: hwb(210 0% 21% / 0.8);
}
  • HはHSLと同様に色相角度(色相環の角度)を指定します。(0度〜360度)
  • WBはそれぞれ混合するwhiteの量混合するblackの量をパーセントで指定します。
    • 100%より大きい値が指定された場合は100%に切り捨てられます。
    • その上でこの2つの合計が100%より大きい場合、2つの合計が100%になるように同じ比で正規化されます。(例:W=600%, B=400%→W=60%, B=40%)
  • A透過度を指定します。rgb()の透過度と同じものです。

HWBで定義される色は 「指定された色相の彩度100%明度50%の色に白と黒を混ぜた色」 だと考えることができます。また白と黒を50%ずつ混合するとグレー(#808080)になります。

2022/04/22追記:Chrome 101でhwb()が使えるようになりそう

https://blog.chromium.org/2022/03/chrome-101-federated-credential.html
https://developer.chrome.com/blog/new-in-devtools-101/

Device-independent Colors

CSS Color Module Level 4ではデバイスに依存しない色の定義が追加されています。
ここではLabLCHを取り上げます。

Lab

CSSでLabL*a*b*色空間(CIE Lab)のことを指します。
Lab色空間は人間の視覚に近くなるように設計されており人間の目で見える全ての色を記述できます。そのため物体の色を表す指標としてあらゆる分野で利用されています。
Lab色空間では明度a(緑~赤の間の位置)b(青~黄の間の位置)の3つの変数を用いて色を定義します。

CSSではlab()を使用することでLab色を定義できます。2022年1月31日時点ではSafariにのみ実装されています。

lab(L a b / A)
.sample {
  color: lab(80% -80 -100);
}
  • LはHSLと同様にパーセントで指定しますが、100%を超えることも可能です。
  • abは理論的には上限も下限もないですが、実際は-160から160の範囲で変化します。
  • A透過度を指定します。rgb()の透過度と同じものです。

LCH

LCHはlightnesschromahueの略称で、明度色度色相の3つの変数を用いて色を定義します。

CSSではlch()を使用することでLCH色を定義できます。2022年1月31日時点ではSafariにのみ実装されています。

lch(L C H / A)
.sample {
  color: lch(80% 210 50);
}
  • LはLabと同様に100%を越えた値も指定できます。
  • Cは「色の含有量」を表す引数です。
    • 最小値は0、理論的な上限値はありませんが、ブラウザやディスプレイが表示できる色数に限界があるため、実際には230が上限と定義されています。
    • 負の値は0に変換されます。
  • Hは色相角度を指定します。(0度〜360度)
    • HSLの色相とは違う色の対応をしています。(詳細はこちら
  • A透過度を指定します。rgb()の透過度と同じものです。

LabやLCHが必要な理由

LabとLCHはHSLに近い色の指定の仕方をしているように見えますが、なぜLabやLCHが必要なのでしょう?

その理由の一つに、より広い範囲の色にアクセスできるという点があります。前述の通りLabとLCHは人間が見えるすべての色を表現できるため、次のようなことが可能になります。

  • デザインツールでディスプレイに表示される色と実際に印刷される色を同じように表現できる
  • より自然なグラデーションを生成できる

またHSLとRGBは知覚的に均一ではない(Not perceptually uniform)という問題もあります。特にHSLでは、明度を上げ下げしたときの色の変化が色相によってかなり異なるということが知られています。
LCHを利用すればよりperceptually uniformなカラーパレットを定義することができます。

下記サンプルでは色をグレースケールに変換することで知覚的な明るさを体感できるようになっています。
LCHの場合は色度や色相を変化させても明るさは均一ですが、HSLの場合色相や彩度を変化させると(明度は変化していないにもかかわらず)明るさが大きく変化していることがわかります。

まとめ

いかがだったでしょうか。
この記事で取り上げていない色関数や色空間についての定義もあり、色というものの奥深さに気付かされますね。
興味のある人は是非CSS Color Module Level 4の仕様書を読んでみましょう。頭が痛くなりますがとても楽しいですよ。
https://www.w3.org/TR/css-color-4/#specifying-lab-lch

Discussion