ここ最近、飛躍的な進歩を続ける CSS ですが、CSS のカラー指定においても、従来より使われてきた #RRGGBB の記法から選択肢が大幅に増えました。

  • 「なぜこれだけ指定方法が増えたのか」
  • 「これまでの書き方を変える必要があるのか」

この記事では、そのような疑問について考えながら、色彩の理論もまじえつつ、CSS Color について改めて掘り下げていきます。

CSS は開発のサイクルを活発にするために、モジュール単位で仕様が策定されています。

カラーに関するモジュールは、現在 3 つのレベルが存在しており、2011 年 6 月に勧告(Recommendation)された「CSS Color Level 3」が広く普及しています。「CSS Color Level 4」と「CSS Color Level 5」は勧告には至っておりませんが、すでに主要ブラウザに実装されている機能もいくつかあります。

「CSS Color Level 5」では、2 つの色を混合する color-mix() 関数や、カラーの相対指定が可能になるなど、興味深い機能が追加されているのですが、この記事で取り扱うのは「CSS Color Level 4」までとします。

ちなみに「CSS Color Level 6」も Editor’s Draft では存在しています。

CSS での代表的なカラー指定の種類は以下が挙げられます。

記法HD(高解像度)
キーワードdarkslategraynon-HD(sRGB)
Hex#2f4f4fnon-HD(sRGB)
RGBrgb(47 79 79)non-HD(sRGB)
HSLhsl(180 25% 25%)non-HD(sRGB)
HWBhwb(180 19% 69%)non-HD(sRGB)
Lablab(31% -12 -4)HD
LCHlch(31% 13 198)HD
Oklaboklab(40% -0.036 -0.010)HD
Oklchoklch(40% 0.037 195)HD

実際に使われるのは、以前から馴染みのある Hex、RGB、HSL と、transparentcurrentColor といった一部のキーワードでしょう。

そして、今後のデザインツールやブラウザのサポート状況に応じて、新しい指定方法である LCH や Oklch を採用するケースが増えていくと考えられます。

なお、同じサイト内で複数の記法を混在させるのは、メンテナンス性や正規化の観点から好ましくないので、記法のパターンはできるだけ限定したほうがよいでしょう。

ブラウザのサポート状況

見出し「ブラウザのサポート状況」

新しいカラー関数である、lch()lab()oklab()oklch() のブラウザサポート状況を「Can I Use…」で見る限りでは、Firefox でサポートされれば、主要ブラウザでは使える状態になるようです。(2023 年 3 月 26 日時点)

2023/05/02 追記 Firefox 113 より、新しいカラー関数がすべてサポートされる予定です。

カラー指定が増えた理由

見出し「カラー指定が増えた理由」

このように、カラー指定の種類が増加している理由としては以下の 3 点が考えられます。

  1. sRGB 色空間を超えた表現
  2. 知覚的均等性
  3. 予測可能性

1. sRGB 色空間を超えた表現

見出し「1. sRGB 色空間を超えた表現」

広く普及している sRGB 色空間は、国際電気標準会議(IEC)が定めた国際標準規格で、特定のデバイスに依存せずに、パソコンのディスプレイやプリンタなど、さまざまなデバイス上で再現できる色の領域(色域)です。ただ、人間の視覚の色域はこれよりも広いため、sRGB での色の表現には限界がありました。

Apple が策定した Display P3 では、この sRGB よりも広い色域を表現できます。ここ数年で Display P3 対応ディスプレイが登場したことにより、sRGB の色域に制限されない、Lab、LCH、Oklab、Oklch といった HD カラーのニーズが高まっていると考えられます。

Google Chrome のカラーピッカーでは、以下のように HD カラーを選択すると、sRGB の色域が表示されます。つまり、sRGB の色域よりも外の色を選択できることを意味します。

Google Chrome のカラーピッカーのスクリーンショット

後述する HSL でも取り上げますが、同じトーン(明度・彩度)で色相だけ変えると、知覚的に均等でない(明るさが異なる)ように見えることがあります。例えば hsl(60 100% 50%)hsl(240 100% 50%) では、トーン(明度・彩度)の値は同じで、色相が違うだけなのですが、前者のほうが明るく感じられます。

左が hsl(60 100% 50%) で塗られたオブジェクト、右が hsl(240 100% 50%) で塗られたオブジェクトで、左のほうが知覚的に明るく見える
hsl(60 100% 50%)hsl(240 100% 50%) の比較

Lab や LCH では、この知覚的均等性が向上しており、より直感的に配色を作ることができます。そして、2020 年末に誕生した Oklab と Oklch ではさらに均等性が改善しています。

従来の #2f4f4frgb(47 79 79) の記法では、#ff0000 のような極端な値でない限り、コードからどのような色が表示されるかを予測することが難しく、値を調整することも難しいですが、LCH や Oklch では、ある程度予測がつきやすく、色相・明度・彩度で値が分かれているのでコード上での変更もある程度対応可能です。

例えば、以下のようにホバー効果で明度を 10% だけ上げるといったことが、直感に反することなく指定できます。

oklch() のホバー効果の例
.btn {
  background: oklch(50% 0.09 195);
  color: #fff;
}
.btn:hover {
  background: oklch(60% 0.09 195);
}

color: black のように、キーワードでカラーを指定する方法で、キーワードは sRGB の値に変換されます。大文字と小文字は区別しません(ASCII case-insensitive)。

最初は 16 色の基本色のみでしたが、現在では「CSS Color Level 4」にて Eric Meyer に敬意を表して追加された rebeccapurple を加えた 148 色が使用できます。

キーワード一覧
  • aliceblue
  • antiquewhite
  • aqua
  • aquamarine
  • azure
  • beige
  • bisque
  • black
  • blanchedalmond
  • blue
  • blueviolet
  • brown
  • burlywood
  • cadetblue
  • chartreuse
  • chocolate
  • coral
  • cornflowerblue
  • cornsilk
  • crimson
  • cyan
  • darkblue
  • darkcyan
  • darkgoldenrod
  • darkgray
  • darkgreen
  • darkgrey
  • darkkhaki
  • darkmagenta
  • darkolivegreen
  • darkorange
  • darkorchid
  • darkred
  • darksalmon
  • darkseagreen
  • darkslateblue
  • darkslategray
  • darkslategrey
  • darkturquoise
  • darkviolet
  • deeppink
  • deepskyblue
  • dimgray
  • dimgrey
  • dodgerblue
  • firebrick
  • floralwhite
  • forestgreen
  • fuchsia
  • gainsboro
  • ghostwhite
  • gold
  • goldenrod
  • gray
  • green
  • greenyellow
  • grey
  • honeydew
  • hotpink
  • indianred
  • indigo
  • ivory
  • khaki
  • lavender
  • lavenderblush
  • lawngreen
  • lemonchiffon
  • lightblue
  • lightcoral
  • lightcyan
  • lightgoldenrodyellow
  • lightgray
  • lightgreen
  • lightgrey
  • lightpink
  • lightsalmon
  • lightseagreen
  • lightskyblue
  • lightslategray
  • lightslategrey
  • lightsteelblue
  • lightyellow
  • lime
  • limegreen
  • linen
  • magenta
  • maroon
  • mediumaquamarine
  • mediumblue
  • mediumorchid
  • mediumpurple
  • mediumseagreen
  • mediumslateblue
  • mediumspringgreen
  • mediumturquoise
  • mediumvioletred
  • midnightblue
  • mintcream
  • mistyrose
  • moccasin
  • navajowhite
  • navy
  • oldlace
  • olive
  • olivedrab
  • orange
  • orangered
  • orchid
  • palegoldenrod
  • palegreen
  • paleturquoise
  • palevioletred
  • papayawhip
  • peachpuff
  • peru
  • pink
  • plum
  • powderblue
  • purple
  • rebeccapurple
  • red
  • rosybrown
  • royalblue
  • saddlebrown
  • salmon
  • sandybrown
  • seagreen
  • seashell
  • sienna
  • silver
  • skyblue
  • slateblue
  • slategray
  • slategrey
  • snow
  • springgreen
  • steelblue
  • tan
  • teal
  • thistle
  • tomato
  • turquoise
  • violet
  • wheat
  • white
  • whitesmoke
  • yellow
  • yellowgreen

しかし、これらのキーワードの中には darkgraygray よりも明るく見えるといった直感に反する色名や、適切ではない名前があるため、W3C のドキュメントでも非推奨扱いです。

そのほかのキーワードとして transparentcurrentColor がありますが、こちらは問題なく使用できます。

transparent キーワードは透明色を意味し、rgba(0, 0, 0, 0) のショートカットです。

currentColor キーワードは、通常 color 以外のプロパティに指定することで、カラー値の管理をシンプルにすることができます。

たとえば、border-color や SVG の fill がテキストカラーと同じ場合には、currentColor キーワードを指定できます。

currentColor の例
.elem {
  /* 罫線の色が `#007373` になる */
  border: 1px solid currentColor;
  color: #007373;
}
.elem svg {
  /* SVG の色が `#007373` になる */
  fill: currentColor;
}
.elem:hover {
  /* `color` を変更すれば `currentColor` にも反映される */
  color: #00a8a8;
}

なお「CSS Color Level 4」からは、すべて小文字表記の currentcolor ですが、大文字と小文字は区別しないため、どちらの値でも同じ結果になります。

#007373

「Hex」は「Hexadecimal notation」の略で、0-9 から A-F までの値で指定する 16 進数を意味し、とても馴染み深いカラー指定です。sRGB 色空間内の色を #RRGGBB の 16 進数表記で指定する方法で #RGB のように省略することも可能です。

原理は次の rgb() と同じで、光の三原色を混合した比率によって色をつくる加法混色なので、すべての値を最大にすると「White」になります。

アルファ(透過性)を指定する場合には #RRGGBBAA または #RGBA ですが、16 進数で指定するため、直感的ではありません。

Hex の例
/* #RRGGBB */
#778899

/* #RRGGBBAA */
#778899cc

/* #RGB */
#789

/* #RGBA */
#789c

前述したように、Hex の値からどのような色が表示されるかを予測するのが難しいため、色相・明度・彩度を調整するには何かしらのツールを使用することになります。

光の三原色である赤・緑・青(RGB)を混ぜ合わせることで、どのような色もつくり出すことができるという原理で、グラスマンの法則によって定義されました。

加法混色の例

ヤング・ヘルムホルツの三色説

見出し「ヤング・ヘルムホルツの三色説」

人間には赤・緑・青それぞれの光の刺激に反応する神経細胞があり、その反応の変化によって色を知覚できるという説です。ヤングによって提唱され、その後、ヘルムホルツによって体系化されました。

この神経細胞とは、網膜に存在する 3 種類の錐体(L 錐体、M 錐体、S 錐体)のことで、赤・緑・青の波長(分光分布)に対応します。L、M、S は強く反応する光の波長の長さを指します。

rgb(0 115 115)

rgb() 関数記法で、sRGB 色空間での「Red」「Green」「Blue」の値を指定します。それぞれ 0 から 255 までの数値もしくは、0% から 100% までのパーセントで指定できますが、数値とパーセントを混在させることはできません。

Hex 同様に、光の三原色を混合した比率によって色をつくる加法混色です。

アルファ(透過性)を指定する場合には、0 から 1 までの数値もしくは、0% から 100% までのパーセントで指定します。

また、RGB のそれぞれの値をカンマ(,)で区切る記法と、空白( )で区切る記法があり、それによってアルファ値の区切り方も異なります。

rgb() の例
/* カンマ区切り */
rgb(119, 136, 153)
rgb(47%, 53%, 60%)

rgb(119, 136, 153, 0.5)
rgb(119, 136, 153, 50%)

/* 空白区切り */
rgb(119 136 153)
rgb(47% 53% 60%)

rgb(119 136 153 / 0.5)
rgb(119 136 153 / 50%)

ただ、この記法も Hex 同様に直感的ではなく、値からどのような色になるかを想像するのが難しいため、色相・明度・彩度を調整するには何かしらのツールを使用することになります。

カンマ区切りと空白区切り

見出し「カンマ区切りと空白区切り」

「CSS Color Level 4」以降、カンマ区切りはレガシーな指定となり、互換性のため rgb()rgba()hsl()hsla() でのみ使用できます。

サイト内で表記を統一することが第一ですが、可能な限りレガシーな指定を避け、空白区切りを使用することが望ましいでしょう。

/* カンマ区切り(レガシーな指定) */
rgb(119, 136, 153)
hsla(210, 14%, 53%, 50%)

/* 空白区切り(CSS Color Level 4 以降) */
rgb(119 136 153)
hsl(210 14% 53% / 50%)

また、上記以降に登場したカラー関数ではカンマ区切りの記法は使用できないため、空白区切りの記法を用います。

rgba() 関数および hsla() 関数を用いたアルファ値の指定についても同様に、「CSS Color Level 4」以降レガシーな指定で、互換性のために残っています。

主要なブラウザでは、すでに rgb()hsl() でのアルファ値の指定をサポートしているので、こちらも可能な限りレガシーな指定は避けた方がよいでしょう。

それ以降に登場したカラー関数で、例えば HWB のアルファ指定の際に、hwba() のような関数は存在しないため使用できません。

hsl(180 100% 23%)

hsl() 関数記法で、sRGB 色空間での「Hue(色相)」「Saturation(彩度)」「Lightness(明度)」を指定します。

この 3 つの属性は色の三属性なので、カラーパレットを作成するときに、同系の色相で彩度や明度で変化をつけたり、逆に同系のトーン(明度・彩度)のまま色相の違いで変化をつけたりと、パターンが作りやすくなります。

しかし、前述したとおり、同じトーン(明度・彩度)で色相だけ変えた場合、知覚的に均等でない(明るさが異なる)ように見えることがあるので注意が必要です。

左が hsl(60 100% 50%) で塗られたオブジェクト、右が hsl(240 100% 50%) で塗られたオブジェクトで、左のほうが知覚的に明るく見える
hsl(60 100% 50%)hsl(240 100% 50%) を比較すると、前者のほうが明るく見える

h は色相環の角度を、単位のない数値、もしくは degradgradturn 単位をつけて指定できます。角度を指定する場合には 0 から 360 までの間で値を指定します。

s は彩度を 0% から 100% の値で指定し、l は明度を 0% から 100% で指定します。

アルファ(透過性)を指定する場合には、0 から 1 までの数値もしくは、0% から 100% までのパーセントで指定します。

こちらも RGB 同様に、それぞれの値をカンマ(,)で区切る記法と、空白( )で区切る記法があり、それによってアルファの区切り方も異なります。

hsl() の例
/* カンマ区切り */
hsl(180, 25%, 25%)
hsl(180deg, 25%, 25%)

hsl(180, 25%, 25%, 0.5)
hsl(180, 25%, 25%, 50%)

/* 空白区切り */
hsl(180 25% 25%)
hsl(180deg 25% 25%)

hsl(180 25% 25% / 0.5)
hsl(180 25% 25% / 50%)
hwb(180 0% 55%)

HWB は一見すると HSL に似ていますが、hwb() 関数記法を用い、sRGB 色空間での「Hue(色相)」「Whiteness(白さ)」「Blackness(黒さ)」を指定します。

h は HSL と同様に色相環の角度を、単位のない数値、もしくは degradgradturn 単位をつけて指定できます。

b は黒の割合を w は白の割合を 0% から 100% で指定します。HWB は人間が直感的に操作しやすいと謳われていますが、色の三属性に慣れているためか、これらの値を操作してトーンを調整するのは難しく感じます。

なお、前述の RGB や HSL とは異なり、HWB はカンマ区切りはサポートしていないので、必ず空白で区切る必要があります。

アルファ(透過性)を指定する場合にはスラッシュ(/)の後にアルファ値を指定します。値は 0 から 1 までの数値もしくは、0% から 100% までのパーセントで指定できます。

hwb() の例
/* hwb() */
hwb(180 19% 69%)
hwb(180deg 19% 69%)

/* hwb() アルファ値を指定 */
hwb(180 19% 69% / 0.5)
hwb(180 19% 69% / 50%)
lab(43% -28 -8)

lab() 関数記法で、「CIE Lightness(CIE 明度)」「a(緑から赤への軸)」「b(青から黄への軸)」を指定します。sRGB よりも広い色域の Lab 色空間のため、人間が認識できるすべてのカラーを再現できるとされています。

l0% を黒、100% を白とする明度の軸です。Lab の色空間は知覚的に均等のため、l=50% であればミッドグレーを指します。% 単位を付けるのが一般的ですが、単位を省略することもできます。

以下は HSL と Lab で白から黒のグラデーションを作った例ですが、比較すると Lab のグラデーションのほうが中間地点のグレーの位置が自然に見えます。これは Lab 色空間の知覚的均等性が高いためです。

左が HSL で作成した白から黒のグラデーション、右が Lab で作成した白から黒のグラデーション
HSL と Lab で白から黒のグラデーションを作った例

a は緑から赤への軸、b は青から黄の軸です。軸の両端はそれぞれ補色の関係にあり、この 4 色はヘリングの反対色説に裏づけされます。値はそれぞれ正の数か負の数を指定できます。

a を正の数値にすると紫みの赤になり、負の数値にすると緑になります。b を正の数値にすると黄になり、負の数値にすると青・菫になります。理論上は値の制限はありませんが、現実的な数値は -160 から 160 までです。

ただ、ここまでの説明のとおり、a b の軸を使って色を作るのは複雑で直感的ではありません。

lab() の例
/* lab() */
lab(31% -12 -4)

/* lab() アルファ値を指定 */
lab(31% -12 -4 / 0.5)
lab(31% -12 -4 / 50%)

国際照明委員会(CIE)

見出し「国際照明委員会(CIE)」

CIE Lightness の CIE は、国際照明委員会(Comission internationale de l’Eclairage)のことで、照明・色彩の尺度や利用方法に関する国際標準を定める団体です。Lab 色空間も CIE によって開発されました。

そのほかにも、標準的な視細胞の感度である CIE 測色標準観察者における分光視感効率や、基準となる太陽の光(自然昼光)の分光分布である CIE 昼光、物体の色を評価するための標準の光(標準イルミナント)などを定めています。

人間の目には「赤 - 緑物質」「黄 - 青物質」「白 - 黒物質」が存在し、受けた光によって「同化(合成)」と「異化(分解)」という化学反応が起こることで、色を感じることができるという理論です。

例えば「赤 - 緑物質」が同化すれば緑、異化すれば赤の感覚をもたらします。「赤 - 緑物質」「黄 - 青物質」は、補色の関係にあり、補色残像の仕組みを説明できます。

このヘリングの反対色説は、ヤング・ヘルムホルツの三色説の反証として提唱されましたが、その後、2 つの理論は光を受けて錐体細胞が反応するときと、脳に信号が送られるときで、段階が違うだけで両立しうるという、段階説に移行しています。

三色説に裏づけされる、L 錐体、M 錐体、S 錐体がそれぞれ赤・緑・青の光の刺激を受け、L + M で「輝度チャネル」、L - M で「赤 - 緑チャネル」、S - (L + M) で「青 - 黄チャネル」が反応する。この各チャネルが反対色説に裏づけされる
三色説と反対色説の両立を裏づける段階的な色覚メカニズム
lch(43% 29 196)

lch() 関数記法で、「CIE Lightness(CIE 明度)」「Chroma(彩度)」「Hue(色相)」を指定します。Lab 色空間の広い色域により、人間が認識できるすべてのカラーを再現できるとされています。

指定方法は HSL と同様に、色の三属性(色相・明度・彩度)で調整ができるため lab() 関数と比較すると直感的に配色できます。ただ、概念的には HSL に似ていますが、同じ値を指定しても異なる結果になるので注意が必要です。

l は明度の割合をパーセントで指定します。% 単位を付けるのが一般的ですが、単位を省略することもできます。

c は彩度を 0 を最小値として、理論上は正の値を制限なしで指定できますが、現実的には 230 を超えることはありません。

h は HSL と同様に色相環の角度を 0 から 360 までの範囲で指定します。

lch() の例
/* lch() */
lch(31% 13 198)

/* lch() アルファ値を指定 */
lch(31% 13 198 / 0.5)
lch(31% 13 198 / 50%)

Lab / LCH には既知の問題があり、以下の 3 点が挙げられています。

  • h(色相)の値が 270 から 330 の青色の領域での直線性に問題があり、高い彩度から彩度を下げていくと紫みが増す
  • Lab / LCH の色相は HSL や HWB よりは優れているが、均等性は完全ではない
  • 高彩度の色になると彩度の変化が目立たなくなる
oklab(50% -0.083 -0.022)
oklch(50% 0.086 195)

Oklab と Oklch は、Lab と LCH の問題を解消するために 2020 年末に誕生しました。Oklab 色空間により色相の直線性や均等性、彩度の均等性が改善されています。

指定方法は Lab、LCH に近いですが若干の違いがあります。

  • oklab()a b の現実的な範囲は -0.5 から 0.5 まで
  • oklch()c の現実的な範囲は 0 から 0.5 まで
oklab() の例
/* oklab() */
oklab(40% -0.04 -0.01)

/* oklab() アルファ値を指定 */
oklab(40% -0.04 -0.01 / 0.5)
oklab(40% -0.04 -0.01 / 50%)
oklch() の例
/* oklch() */
oklch(40% 0.04 194)

/* oklch() アルファ値を指定 */
oklch(40% 0.04 194 / 0.5)
oklch(40% 0.04 194 / 50%)

ツールやブラウザのサポート状況が充実した段階では、Lab や LCH よりも、その改良版である Oklab や Oklch を使用したほうが望ましい結果が得られるでしょう。

ちなみに、Photoshop のグラデーションツールでは Oklab 色空間がサポートされているため、知覚的均等性の高いグラデーションを含んだ画像を作るといったように、部分的に取り入れて慣れ親しんでいくのもよいかもしれません。

2023/03/30 追記

ここまで CSS カラー指定の種類を見てきましたが、結局どの書き方を選べばよいのか?

現時点ではケースバイケースといえます。

デザインデータから直接カラーの値を取得するような場合には、従来の Hex タイプの指定でよいでしょう。ただ、アルファ(透明度)を指定する場合には、Hex は直感的ではないので、それ以外のカラー関数が適しています。

また、デザインシステムのカラー設計のように、段階的にトーンを変えたカラーパレットを作る場合には、HSLHWBLCHOklch が向いていますが、Oklch 以外では、知覚的に均等になるように個別の調整が必要になるかもしれません。

Display P3 のような広色域をターゲットとしている場合や、より自然な色の変化のグラデーションを作成したい場合には、LCH や Oklch が適しています。

課題としては、デザインツールで直接扱えない場合には拡張機能や変換ツールが必要になり、状況に応じて対応していないブラウザ向けのフォールバックの指定も必要になります。

また、そもそも制作環境でのディスプレイが広色域に対応しているのが前提条件で、デザインツールでの色空間の設定の変更も必要になるかもしれません。

LCH と Oklch を比較すると、改良版である Oklch が優れていますが、Oklab がまだ歴史の浅い色空間のため、その点は留意して使う必要があるかもしれません。

本記事の作成にあたり、以下のウェブページや書籍を参考にしました。