CSSカラー・モジュール レベル4

W3C勧告案ドラフト、

この文書の詳細情報
このバージョン:
https://www.w3.org/TR/2026/CRD-css-color-4-20261009/
最新公開バージョン:
https://www.w3.org/TR/css-color-4/
編集者ドラフト:
https://drafts.csswg.org/css-color-4/
以前のバージョン:
履歴:
https://www.w3.org/standards/history/css-color-4/
実装報告:
https://wpt.fyi/results/css/css-color
フィードバック:
CSSWG課題リポジトリ
編集者:
Tab Atkins Jr. (Google)
Chris Lilley (W3C)
Lea Verou (Invited Expert)
Former Editor:
L. David Baron (Google)
元編集者:
L. David Baron (Mozilla)
この仕様への編集提案:
GitHub 編集者
テストスイート:
https://wpt.fyi/results/css/css-color/

概要

本仕様は、CSS <color>値、および前景色とグループ不透明度のプロパティについて説明します。 また、色の補間方法や色域マッピングの方法についても説明します。

CSS は、画面、紙などで 構造化された文書(HTMLやXMLなど)のレンダリングを記述する言語です。

この文書のステータス

このセクションは、発行時点でのこの文書のステータスを説明します。 現在のW3C出版物の一覧や この技術レポートの最新の改訂版は W3C標準およびドラフトのインデックスでご覧いただけます。

この文書は CSS作業グループによって 勧告候補ドラフトとして 勧告トラックを利用して 公開されました。 勧告候補としての公開は、 W3C およびその会員による支持を意味するものではありません。 勧告候補ドラフトは、直前の勧告候補から作業グループが 次回の勧告候補スナップショットに含める意図がある変更を統合しています。

この文書はドラフトであり、 いつでも他の文書によって更新、置換、 または廃止される場合があります。 作業途中の文書以外として引用することは適切ではありません。

フィードバックは GitHubでissueを提出(推奨)してお寄せください。 タイトルに仕様コード「css-color」を含めて、次のようにお願いします: “[css-color] …コメントの概要…”。 すべてのissueおよびコメントは アーカイブされています。 または、(アーカイブ済み)の公開メーリングリスト www-style@w3.orgに送信することもできます。

この文書は 2025年8月18日 W3Cプロセス文書 によって管理されています。

この文書は W3C特許方針の下で運営されるグループによって作成されました。 W3Cは、 グループの成果物に関連して行われた特許開示の公開リスト を管理しています。 そのページには特許の開示方法も記載されています。 個人が“必須クレーム”を含むと信じる特許を実際に知っている場合、 W3C特許方針第6節 に従い情報を開示する必要があります。

1. はじめに

このセクションは規範的ではありません。

このモジュールは、要素のテキスト内容の前景色と不透明度を指定するためのCSSプロパティを説明します。 また、CSSの<color>値型についても詳細に説明します。

このモジュールは、CSS1、CSS2、 およびCSS Color 3に既に存在する色関連のプロパティと値を定義するだけでなく、 新しいプロパティと値も定義します。

特に、sRGB以外の色空間での色指定を可能にします。 以前は、ディスプレイデバイスが対応していても、sRGBガマット外のより飽和した色はCSSで使用できませんでした。

ドラフト実装レポートが利用可能です。

1.1. 値の定義

本仕様は CSSプロパティ定義の慣習([CSS2] を参照)に従い、値の定義構文([CSS-VALUES-3] 参照)を用いています。 本仕様で定義されていない値型は CSS Values & Units [CSS-VALUES-3] で定義されています。 他のCSSモジュールと組み合わせることで、これらの値型の定義が拡張される場合があります。

プロパティ固有の値に加えて、 この仕様で定義されているすべてのプロパティは、 プロパティ値としてCSS全体のキーワードも受け入れます。 可読性を考慮し、それらは明示的に繰り返されていません。

2. 色彩の用語

色は、人間の視覚による光または光で照らされた物体の知覚を数値的または文字列的に表現したものです。 人間の色知覚の客観的な研究は、色彩計測と呼ばれます。

物理的な物体の色は、 各可視波長でどれだけの光を反射するか、 およびそれを照らす光の実際の色 (再び、各波長でどれだけの光があるか)に依存します。 これは分光光度計で測定されます。

光を放つもの(コンピュータ画面上の色を含む)の色は、 各可視波長でどれだけの光を放つかに依存します。 これは分光放射計で測定されます。

もし2つの物体が異なるスペクトルを持っていても、 それでも同じ物理的な感覚を生じる場合、 それらは同じ色を持つと言います。 スペクトルをCIE XYZ(三つの数値)に変換することで、 2つの色が同じかどうかを計算できます。

例えば、緑の葉、コンピュータ画面に表示されたその葉の写真、 そしてその写真の印刷物は、 すべて異なる手段で緑の感覚を生じています。 もし画面とプリンターがキャリブレーションされている場合、 葉、写真、印刷物の緑は同じように見えます。

色空間は、 基礎となる色彩計測モデルに基づいて色を組織化したもので、 その色空間内の任意の色に対して明確で客観的に測定可能な意味を持たせるものです。 これにより、同じ色が複数の色空間で表現されたり、 一つの色空間から別の色空間へ変換されたりしても、 見た目が同じであることが可能になります。

葉を分光光度計で測定したところ、 色が lch(51.2345% 21.2 130) または lab(51.2345% -13.6271 16.2401) であることが判明しました。

同じ色はさまざまな色空間で表現できます:

 color(sRGB 0.41587 0.503670 0.36664);
 color(display-p3 0.43313 0.50108 0.37950);
 color(a98-rgb 0.44091 0.49971 0.37408);
 color(prophoto-rgb 0.36589 0.41717 0.31333);
 color(rec2020 0.42210 0.47580 0.35605);

加法的色空間とは、 座標系が光の強度において線形であることを意味します。 CIE XYZ色空間は加法的色空間です。 XYZのY成分は輝度で、単位面積あたりの光の強度、 つまり「どれだけ明るいか」です。輝度はカンデラ毎平方メートル (cd/m²)で測定され、ニットとも呼ばれます。

加法的色空間では、正確に予測できる色混合の計算を行うことができます。 ほとんどのRGB空間は加法的ではありません。 これは、成分がガンマエンコードされているためです。 このガンマエンコードを解消することで、線形光値が生成されます。

例えば、照明器具に2つの同一の色の光があり、 片方だけが点灯されているとき、 測定された色が color(xyz 0.13 0.12 0.04) である場合、 両方が点灯されると色は正確にその2倍となり、 color(xyz 0.26 0.24 0.08) になります。

異なる色のスポットライトが2つ、ステージ上で照らしている場合、 一方が測定値 color(xyz 0.15 0.24 0.17) を持ち、もう一方が color(xyz 0.11 0.06 0.06) の場合、 その色の光束が重なるようにすると、 混合の色はXYZ成分値の合計となり、 color(xyz 0.26 0.30 0.23) になります。

色度とは、 明度成分を取り除いた色の測定値です。 上記の同一の光の例では、 1つの光におけるu',v'色度は (0.2537, 0.5268) であり、 両方の光で色度は同じです (色は同じで、ただ明るさが増加しているだけです)。

色度は加法的であるため、 混合の色度を正確に予測することができます (ただし、結果として得られる明度は除きます)。 二次元であるため、色度は色度図で簡単に表現でき、 色混合の色度を予測することができます。 任意の2つの色を混合すると、結果の色は 図上でそれらを結ぶ直線上に位置します。 3つの色は平面を形成し、結果の色は 図上でそれらが形成する三角形内に位置します。

display-p3色空間のuv色度図
実線で示されたdisplay-p3色空間 と、比較のために (淡色で)示されたsRGB色空間の色度図。 また、白色点(D65)も示されています。

したがって、線形化されると、RGB色空間は加法的であり、 そのガマットは 赤、緑、青の原色の色度、 および白色点 (3つの原色がすべて最大強度で形成する色)の色度によって定義されます。

ほとんどの色空間は、いくつかの昼光を模した 白色点のいずれかを使用します。 これらは、対応する黒体放射体の相関色温度(CCT)[Understanding_CCT] によって命名されています。 例えば、D65は相関色温度 6500ケルビンに対応する昼光白色点です (実際には6504、 プランク定数の値が色が最初に定義された時から変更されたためです)。

累積的な往復誤差を避けるためには、 計算のすべての箇所で 同一の色度値が一貫して使用されることが重要です。 したがって、最大限の互換性のために、 この仕様では以下の2つの標準的な昼光を模した 白色点が定義されています:

名称 x y CCT
D50 0.345700 0.358500 5003K
D65 0.312700 0.329000 6504K

測定された物理的特性 (使用する原色の色度 や、特定の入力セットに応じて生成される色など)が 色空間または 色を生成するデバイスに既知の場合、 それは特性化されたと言います。

さらに、デバイスが白色点、グレーの中立性、トーン応答の予測可能性と一貫性などの キャリブレーション目標を満たすように調整された場合、 それはキャリブレーションされたと言います。

実際の物理デバイスはまだ人間の目が見ることのできるすべての色を生成することはできません。 特定のデバイスが生成できる色の範囲はガマット (ガンマと混同しないでください)と呼ばれます。 ガマットが限られているデバイスでは、 虹に見られるような非常に飽和した色を生成できません。

3つのガマットを上から見た図。Oklab空間にプロットされており、正のa軸は右方向、正のb軸は上方向、 l軸を下に向けて見ているため、白と中間色は中心にあります。 3つのガマットの中で最大のものはITU Rec BT.2020、中間サイズはDisplay P3、最小はsRGBです。 レンダリングはAlexey Ardovによるものです。

異なる色空間のガマットは、 表現できる色の体積(立方Lab単位)を比較することで評価できます。 以下の表は、CSSで利用可能な事前定義された色空間を調査しています。

色空間 体積(百万Lab単位)
sRGB 0.820
display-p3 1.233
a98-rgb 1.310
prophoto-rgb 2.896
rec2020 2.042

CSSにおける色は、以下で説明する各構文形式に従い、 無効な色 または有効な色のいずれかです。

無効な色でない色はすべて、 有効な色です。

色は有効な色である場合でも、 出力デバイス(画面、プロジェクター、またはプリンター)で生成可能な範囲外にあることがあります。

その場合、それはガマット外と呼ばれます。

各有効な色は、特定の出力デバイス(画面やプリンター)に対して ガマット内であるか、 ガマット外であるかのいずれかです。

例えば、display-p3色空間を100%カバーしているがそれ以上はカバーしていない画面の場合、 以下の色はガマット外です:
 color(prophoto-rgb 0.88 0.45 0.10)
display-p3で表現すると、 1つ以上の座標が1.0を超えるか0.0未満であるためです:
 color(display-p3 1.0844 0.43 0.1)
この色は有効であり、 例えばグラデーションの停止点として使用できますが、 表示のためにはCSSガマットマッピングが必要であり、 似た外観ながら彩度の低い色(飽和度が低い色)に変換されます。

3. CSSにおける色の適用

3.1. アクセシビリティと色を用いた情報伝達

色は文書に重要な情報を付加し、読みやすくすることができますが、 それ自体のみで重要な情報を伝える手段であってはなりません。 作成者は、文書で色を使用する際にW3Cのウェブコンテンツアクセシビリティガイドライン [WCAG21] を考慮する必要があります。

1.4.1 色の使用: 色は情報を伝達する唯一の視覚的手段として、 行動を示す、応答を促す、または視覚的要素を区別するために使用されません

3.2. 前景色: color プロパティ

名称: color
値: <color>
初期値: CanvasText
適用対象: すべての要素とテキスト
継承プロパティ: はい
パーセンテージ: 該当なし
計算値: 計算された色、色の値解決を参照
正規順序: 文法による
アニメーションタイプ: 計算値タイプに基づく

このプロパティは要素の主要な前景色を指定します。 これはそのテキスト内容の塗りつぶし色として使用されるだけでなく、 currentcolorが解決される際の使用値も指定します。 これにより、この前景色への間接的な参照が可能となり、 border-colorやtext-emphasis-colorのような 他のさまざまな色プロパティの初期値にも影響を与えます。

<color>
指定された<color>に主要な前景色を設定します。
<color>型は、 特定の色を文法的に指定するための複数の方法を提供します。 例えば、以下の宣言はすべてsRGB色「lime」を指定しています:
em { color:  lime; }   /* color keyword  */
em { color:  rgb(0 255 0); } /* RGB range 0-255   */
em { color:  rgb(0% 100% 0%); } /* RGB range 0%-100% */
em { color:  color(sRGB 0 1 0); } /* sRGB range 0.0-1.0 */

テキストに適用された場合、このプロパティ(アルファ成分を含む)は、 「色付きグリフ」(一部のフォントの絵文字など)には影響を与えません。 それらは組み込みパレットによって着色されています。 しかし、一部のカラーフォントは文脈的な「前景色」を参照することが可能です。 例えば、OpenTypeのCOLRテーブル内のパレットエントリ0xFFFFや、 SVG-in-OpenTypeのcontext-fill値によって設定される場合です。 そのような場合、このプロパティによって前景色が設定され、 currentcolorの値を設定する場合と同じです。

3.3. 透明性: opacity プロパティ

Opacityは後処理操作として考えることができます。 概念的には、要素(その子孫を含む)がRGBAのオフスクリーン画像にレンダリングされた後、 opacityの設定によって、そのオフスクリーンレンダリングが現在の合成レンダリングへどのようにブレンドされるかが指定されます。 詳細は単純アルファ合成を参照してください。

名前: opacity
値: <opacity-value>
初期値: 1
適用対象: すべての要素
継承: いいえ
パーセンテージ: [0,1] の範囲にマップされる
算出値: 指定された数値で、[0,1]の範囲にクランプされる
標準順序: 文法順
アニメーション型: 算出値型による
<opacity-value>
要素に適用される不透明度です。 得られる不透明度は、特定の色ではなく、要素全体に適用されます。

[0,1]の範囲外のopacity値は無効ではなく、指定値として保持されますが、 算出値では[0,1]の範囲にクランプされます。

CSSにおけるopacityは、<opacity-value> 構文で表現されます。例えばopacityプロパティで使用されます。

<opacity-value> = <number> | <percentage>

<number>として表現された場合、 有用な値の範囲は0(完全な透明)から1(完全な不透明)です。 また、<percentage>として記述することもできます。 これは、算出値として同等の<number>(0%は0、100%は1)に変換されます。

opacityプロパティは、指定された不透明度を要素全体に適用します。 内容も含めて、各子孫に個別に適用するのではありません。 つまり、例えば、不透明な子要素が要素の背景の一部を隠していても、opacityが1未満でもそのまま隠し続けますが、 要素と子要素全体が下層のページを透かして表示します。

また、要素内のすべての文字に対応するグリフも全体として扱われます。 重なり合った部分があっても、不透明度は増加しません。

重なったグリフの正しいレンダリングと誤ったレンダリング
1未満のopacity値を持ち、グリフが重なるテキストの 正しいレンダリングと誤ったレンダリング

各グリフごとに個別の不透明度が必要な場合は、 opacityプロパティを設定するのではなく、 アルファ値を含む色値を使用することで実現できます。

ボックスのopacityが1未満の場合、 その子要素のためのスタッキングコンテキストを形成します。 (これにより、その内容がZ軸で外側のコンテンツと混在するのを防ぎます。)

さらに、ボックスにz-index プロパティが適用されている場合、 auto値はその要素に対して0として扱われます。 それ以外は、親のスタッキングコンテキスト内で積層レベル0の配置要素と同じレイヤーに描画されます (z-index:0の配置済み要素として扱われるかのように)。

スタッキングコンテキストについての詳細は、section 9.9およびAppendix Eを参照してください。[CSS2]

これらのz-orderに関する規則はSVG要素には適用されません。 SVGは独自のレンダリングモデル([SVG11]、第3章)を持っています。

opacityプロパティの値は ヒットテストには影響しません。

3.4. タグ付き画像の色空間

タグ付き画像とは、画像フォーマットによって明示的にカラープロファイルが割り当てられている画像のことです。 これは通常、International Color Consortium(ICC)プロファイル [ICC] を含めることで行われます。

例えば、JPEG [JPEG]、PNG [PNG]、TIFF [TIFF] のいずれもICCプロファイルを埋め込む手段を定めています。

画像フォーマットは、簡潔さのために他の同等の方法を使う場合もあります。

例えばPNGでは、sRGBチャンク により、sRGBカラースペースであることを明示的にタグ付けする方法が規定されていますが、 sRGB ICCプロファイル自体は含まれていません。

同様に、PNGはよりコンパクトな方法として (cICPチャンク)を規定しており、 ICCプロファイルを含めずにDisplay P3やBT.2100 HLGなど さまざまなSDRまたはHDR色空間のいずれかであることを明示的にタグ付けできます。

タグ付きRGB画像や、YCbCrのようなRGBの変換を利用したタグ付き画像は、 カラープロファイルや他の識別情報が有効であれば、指定された色空間として扱わなければなりません。

例えば、Display P3モニターを搭載したシステム上のブラウザーが、 ITU Rec BT.2020 [Rec.2020] 色空間としてタグ付けされたJPEG画像を表示する場合、 色をITU Rec BT.2020からDisplay P3に変換して正しく表示しなければなりません。 ITU Rec BT.2020の値をDisplay P3の値として扱ってはならず、そうすると色が正しく表示されません。

カラープロファイルや他の識別情報が無効な場合、画像はタグなし画像として記載された方法で扱われます。

3.5. タグなし色の色空間

互換性のため、HTMLで指定された色や、 タグなし画像は 特に指定がない限りsRGB色空間([SRGB])として扱わなければなりません。

タグなし画像とは、 画像フォーマットによって明示的にカラープロファイルが割り当てられていない画像のことです。

この規則はタグなし動画には適用されません。タグなし動画はITUで定義された色空間にあると推定すべきです。

4. 色の表現: <color> 型

CSSの色は、色空間の軸を表す色成分のリストとして表現されます。 これらは「チャンネル」と呼ばれることもあり、 色空間内の各軸を表します。 各成分には最小値と最大値があり、 その間の任意の値をとることができます。 さらに、すべての色には どれだけ透明かを示すアルファ成分が付属しており、 これによって色を通してどれだけ背景が見えるかが決まります。

CSSでは色値を指定するための構文が複数あります:

カラー関数は、 CSSの関数型表記を使って、各成分座標を指定することで 様々な色空間の色を表現します。 そのうちのいくつかは円筒極座標の色モデルを使い、 色相角<hue>、 明度(黒〜白)を示す中心軸、 彩度またはクロマ(色がニュートラルグレーからどれだけ離れているか)を示す半径で色を指定します。 その他は直交座標の色モデルを使い、 3本の直交成分軸で色を指定します。

カラー関数で Level 4で利用できるものは次の通りです:

他の仕様で参照しやすいよう、 不透明な黒は rgb(0 0 0 / 100%)の色として定義します。 透明な黒は 同じ色ですが、完全に透明です—すなわちrgb(0 0 0 / 0%)です。

4.1. <color>構文

CSSの色は<color>型で表現されます:

<color> = <color-base> | currentColor | <system-color>

<color-base> = <hex-color> | <color-function> | <named-color> | transparent
<color-function> = <rgb()> | <rgba()> |
              <hsl()> | <hsla()> | <hwb()> |
              <lab()> | <lch()> | <oklab()> | <oklch()> |
              <color()>

絶対色とは、算出値が絶対的な色度解釈を持つ<color>です。 これは、値が以下ではないことを意味します:

sRGBに解決される色は次の通りです:

レガシーカラー構文をサポートする関数は次の通りです:

<hsl()>、<hsla()>、<hwb()>、<lch()>、<oklch()>はカラー関数であり、円筒極座標の色 表現で<hue>角度を使います。 その他のカラー関数は直交座標の色表現を使います。

4.1.1. モダン(空白区切り)カラー関数構文

この仕様で初めて定義されたすべての絶対色 関数型はモダンカラー構文を使用します。 これは以下を意味します:

次は、飽和したsRGB赤で透過度50%を表します:

rgb(100% 0% 0% / 50%)

4.1.2. レガシー(カンマ区切り)カラー関数構文

Web互換性のため、 rgb()、rgba()、hsl()、hsla()の構文 (従来仕様で定義されたもの)は 次のような違いがあるレガシーカラー構文もサポートします:

次は、飽和したsRGB赤で透過度50%を表します:

rgba(100%, 0%, 0%, 0.5)

この仕様または後続レベルで導入されたカラー関数 について、Web互換性の問題がない場合は レガシーカラー構文は無効です。

4.2. 色の透明度の表現: <alpha-value>構文

<alpha-value> = <number> | <percentage>

注: この構文は、従来の色 構文ではそのまま使用されます。 現代の色 構文では、 アルファ成分が 値 none も取れるように拡張されます。

特に指定がない限り、 色の<alpha-value>成分は省略時に100%となります。 [0,1]の範囲外の値は無効ではありませんが、パース時にその範囲へクランプされます。

4.3. 円筒座標系の色相の表現: <hue>構文

色相は色環の角度で表現されます (虹を輪にねじったものと考え、紫色が赤とすみれの間に追加されます)。

<hue> = <number> | <angle>

この値は度数で指定されることが非常に多いため、 引数を数値で指定することもでき、 これは度数として解釈され 標準単位となります。

この数値は [0,360) の範囲に正規化されます。

例えば hsl(-540 0 0) や hsl(540 0 0) では、 <hue>成分は180度に正規化されます。

hsl(360 0 0)では<hue>成分は0度に正規化されます。

hsl(calc(-infinity) 0 0) や hsl(calc(infinity) 0 0)では <hue>成分も0度に正規化されます。

注: 特定の色相に対応する角度や間隔は 色空間によって異なります。 例えば、sRGB色空間を使うHSLやHWBでは sRGBの緑は120度です。 LCHではsRGBの緑は134.39度、 display-p3の緑は136.01度、 a98-rgbの緑は145.97度、 prophoto-rgbの緑は141.04度です (これらはすべて異なるグリーンの色調になるためです)。

<hue> 成分は無効成分となる最も一般的な成分です。 中心の無彩色軸に十分近い色は 無効な色相成分になります。

4.4. 「欠落」した色成分とnoneキーワード

特定の場合には、 色に1つ以上の 欠落している 色成分が存在することがあります。

この仕様では、 一部の色(whiteなど)について、色相ベースの補間により これは自動的に発生します。 他の仕様では、成分が自動的に欠落する 追加の状況を定義できます。

色関数内の成分に対して、キーワード none を指定することによって、明示的に指定することもできます。 すべての色関数では、 (従来の色構文を使用するものを除き) その任意の成分を none として指定できます。

これは慎重に行うべきであり、 そうすることによる特定の効果が望まれる場合にのみ行うべきです。

欠落成分の扱いについて 2色を組み合わせる場合(色補間など)は § 13.3 欠落成分での補間を参照してください。

その他の目的では、欠落成分はその成分に適した単位のゼロ値として扱われます: 0、0%、または0deg。 これには色を直接レンダリングする場合、 別の色空間に変換する場合、 色成分値で演算する場合などが含まれます。

欠落成分を持つ色をシリアライズしたり著者に直接提示する場合、 レガシーカラー構文ではゼロ値として表現され、 それ以外ではnoneキーワードとして表現されます。

円筒色空間での補間時に色相が欠落することはよくあります。 例えばcolor-mix()関数([CSS-COLOR-5]で定義)を使って color-mix(in hsl, white 30%, green 70%)と書けます。 白は無彩色なので、 欠落した色相をhsl()で持ちます(実質的にhsl(none 0% 100%)。どんな色相でも同じ色になるため) そのためcolor-mix関数は 緑と同じ色相(実質的にhsl(120deg 0% 100%))とみなし、 その成分で補間します。

結果は、本当に緑と白を混ぜたような色になり、 もし白の色相が0degにデフォルトされた場合のように 赤みがかった色になることはありません。

欠落成分を明示的に指定することで、 特定の成分だけ色補間したいという効果を得ることができます。

例えば、どんな色でも「グレースケール」へアニメーションしたい場合、 oklch(none 0 none)と補間すれば可能です。 これにより、開始色の色相と明度は保ったまま、 クロマだけを0へアニメーションし、 明度一定・色相一定のグレーに変化させることができます。

手動で行う場合、開始色の色相や明度を明示的に合わせる必要があります。

4.4.1. 「無効」な色成分

個々の色構文は、場合によっては、 その構文の特定の成分が無効色成分になることを指定できます。 これは、その成分の値がレンダリングされる色に影響しないことを示します。 どんな値を指定しても、画面上に表示される色は同じになります。

例えば、hsl()では、彩度成分が0%のとき色相成分は無効となります。 0%の彩度はグレースケール色を示し、 色相はまったく持たないため、 0degでも180degでも、他のどんな角度でも 結果は全く同じになります。

影響を持たない成分が手動で指定された場合は、通常通り動作します。 影響を持たない成分であること自体に、特別な効果はありません。

しかし、色空間変換によって自動的に色が生成された場合は、 結果の無効成分は変換処理で得られた値ではなく、 欠落として設定しなければなりません。

円筒極座標色空間への色空間変換を行う際、 ユーザーエージェントは、色相成分を無力として扱わなければならない。 これは、彩度(または、hsl における彩度など、色鮮やかさを表すその他の尺度) が、その色空間に指定されたイプシロン(ε)以下である場合である。 例えば、灰色を oklch() に変換すると、 数値誤差により、 彩度が正確に 0% ではなく極めて小さい値になる場合がある。 その結果、色相成分は無力となる。

無力な色相成分を欠落成分に変更する場合、 浮動小数点ノイズの増幅を避けるため、クロマ(または、hsl における彩度など、色鮮やかさを表すその他の尺度。類似成分を参照)はゼロに設定されます。 負の値はゼロにクランプされません。 この値がゼロより大きく、かつ ε 以下である場合にのみ、ゼロに設定されます。 hwb では、代わりに 次の手順に従います。

1. W + B が ε 以上で、かつ W + B が 100 未満の場合
  1.1. W と B が欠落していない場合
    1.1.1. B を 100 - W に設定する
  1.2. それ以外で W が欠落していない場合
    1.2.1. W を 100 に設定する
  1.3. それ以外で B が欠落していない場合
    1.3.1. B を 100 に設定する

4.5. <color>値の構文解析

CSSの<color>値を構文解析するには、 文字列 inputと、オプションでコンテキストとなる要素elementが与えられたとする:
  1. CSS文法に従ってinputを <color>として構文解析する。 失敗した場合は失敗を返し、 成功した場合は結果をcolorとする。

  2. colorを使用色に解決して used colorとする。 要素の他のプロパティ値が <color>の解決に必要な場合 (例えばcurrentcolorやシステムカラーの解決など)、 elementがあればそれを使い、 なければプロパティの初期値を使う。

  3. used colorを返す。

注: このアルゴリズムは CSSスタイルシートやCSSOMインターフェースで指定された CSSの<color>値を構文解析することを意図したものではなく、 HTML属性やCanvasインターフェースなど 他の場所で使われることを目的としています。

5. sRGBカラー

sRGB色空間のCSSカラーは、 sRGB色空間内の1点を示す値(赤、緑、青の三つ組)で表現されます[SRGB]。 これは国際的に認められたデバイス非依存の色空間であり、 コンピュータ画面に色を表示するためだけでなく、 プリンタなど他の種類のデバイスの色指定にも有用です。

CSSでは、sRGB以外の色空間も § 10 定義済み色空間で説明されている通り利用可能です。

CSSはsRGBカラーを直接指定するために、16進カラー、rgb()/rgba()のカラー関数、hsl()/hsla()カラー関数、hwb()カラー関数、色名カラー、 およびtransparentキーワードなど複数の方法を提供します。

5.1. RGB関数: rgb() と rgba()

rgb() と rgba() 関数は r, g, b(赤、緑、青)の成分を直接指定することでsRGBカラーを定義します。 その構文は以下の通りです:

rgb() = [ <legacy-rgb-syntax> | <modern-rgb-syntax> ]
rgba() = [ <legacy-rgba-syntax> | <modern-rgba-syntax> ]
<legacy-rgb-syntax> = 	rgb( <percentage>#{3} , <alpha-value>? ) |
                  rgb( <number>#{3} , <alpha-value>? )
<legacy-rgba-syntax> = rgba( <percentage>#{3} , <alpha-value>? ) |
                  rgba( <number>#{3} , <alpha-value>? )
<modern-rgb-syntax> = rgb(
  [ <number> | <percentage> | none]{3}
  [ / [<alpha-value> | none] ]?  )
<modern-rgba-syntax> = rgba(
  [ <number> | <percentage> | none]{3}
  [ / [<alpha-value> | none] ]?  )
パーセンテージ r, g, bで利用可能
パーセント基準範囲 r, g, b: 0% = 0.0, 100% = 255.0 alpha: 0% = 0.0, 100% = 1.0

最初の3つの引数は、それぞれ色のr, g, b(赤、緑、青)成分を指定します。0%はsRGB色域における最小値、 100%は最大値を表します。

色成分のパーセンテージ基準範囲は、 多くのグラフィックエンジンが内部的に色成分を1バイト整数(0〜255)で保存していたという歴史的事実に由来します。 実装はできる限り著者や計算された成分の精度を維持すべきです。 それができない場合は、+∞方向に丸めるべきです。

最後の引数<alpha-value>は色のアルファを指定します。 省略された場合は100%がデフォルトです。

これらの範囲外の値は無効ではありませんが、 パース時にここで定義された範囲にクランプされます。

歴史的理由により、rgb() および rgba() はレガシーカラー構文もサポートしています。

5.2. RGB16進数表記: #RRGGBB

CSSの16進カラー表記は、sRGBカラーの成分を16進数で指定することができ、 これはコンピューターコードで色を書く方法とよく似ています。 また、同じ色をrgb()表記で書くよりも短くなります。

<hex-color>の構文は、値が3、4、6、または8桁の16進数で構成される<hash-token>トークンです。 つまり、16進カラーはハッシュ記号「#」に続いて、0〜9またはa〜fの桁がいくつか並びます (文字の大文字小文字は区別しません。#00ff00は#00FF00と同じ色を表します)。

指定された16進数の桁数によって、16進数表記をRGBカラーにデコードする方法が決まります:

6桁
最初の2桁を16進数として解釈し、赤成分を指定します。 00は最小値、 ff(10進で255)は最大値です。 次の2桁が緑、最後の2桁が青成分です。 アルファ成分は完全不透明です。
つまり、 #00ff00は rgb(0 255 0)(ライムグリーン)と同じ色です。
8桁
最初の6桁は6桁表記と同じように解釈されます。 最後の2桁を16進数として解釈し、色のアルファ成分を指定します。 00は完全な透明色、 ffは完全な不透明色です。
つまり、 #0000ffccは rgb(0 0 100% / 80%)(少し透明な青)と同じ色です。
3桁
6桁表記の短縮形です。 最初の1桁が赤成分を16進数として指定し、 0は最小値、 fは最大値です。 次の2桁が緑、青成分です。 アルファ成分は完全不透明です。
この構文は「すべての桁を重複させて6桁表記にする」と説明されることが多いです。 例えば、 #123は #112233と同じ色です。 この方法は6桁表記よりも「解像度」が低く、 3桁の16進数では4096色しか表現できませんが、 6桁では約1700万色表現可能です。
4桁
8桁表記の短縮形で、 3桁表記と同様に「展開」されます。 最初の1桁が赤成分を16進数として指定し、 0は最小値、 fは最大値です。 次の3桁が緑、青、アルファ成分になります。

6. カラーキーワード

さまざまな数値構文による<color>指定に加え、 CSSでは用途や利点ごとに複数のカラーキーワードセットが定義されています。

6.1. 名前付きカラー

CSSは多数の名前付きカラーを定義しており、 よく使われる色を簡単に書けて読みやすくなっています。 <named-color>は<ident>として記述され、 <color>が使える場所ならどこでも利用できます。 CSSで定義される<ident>はすべて ASCII大文字小文字を区別しません。

名前はsRGBの色に解決されます。

CSSの名前付きカラーのうち16色はVGAパレット由来で、HTMLにも採用されました: aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, yellow。 その他の多くはUnix系システムのコンソール色指定に使われたX11カラ―システム由来で、 SVGにも採用されています。

注:これらの色名は良いからではなく、 長年広く使われ実装されてきた現実を標準化で反映するためにここで標準化されています。 実際、名前だけではどんな色か想像しづらい場合も多く(下記リスト参照)、 名前の分布はsRGB色空間全体に均等ではなく、 名前の内部整合性もありません ( darkgrayは grayより明るく、 lightpinkは pinkより暗い)、 一部の名前( indianredなど)は 不快とされることもあります。 したがって、これらの使用は推奨されません。

(特別な色値transparentとcurrentcolorは それぞれ独自の節で定義されています。)

次の表は、すべての不透明な名前付きカラーについて、 他の色構文での同等の数値指定を示します。

名前付き 数値 カラー名 16進rgb 10進数
aliceblue #f0f8ff 240 248 255
antiquewhite #faebd7 250 235 215
aqua #00ffff 0 255 255
aquamarine #7fffd4 127 255 212
azure #f0ffff 240 255 255
beige #f5f5dc 245 245 220
bisque #ffe4c4 255 228 196
black #000000 0 0 0
blanchedalmond #ffebcd 255 235 205
blue #0000ff 0 0 255
blueviolet #8a2be2 138 43 226
brown #a52a2a 165 42 42
burlywood #deb887 222 184 135
cadetblue #5f9ea0 95 158 160
chartreuse #7fff00 127 255 0
chocolate #d2691e 210 105 30
coral #ff7f50 255 127 80
cornflowerblue #6495ed 100 149 237
cornsilk #fff8dc 255 248 220
crimson #dc143c 220 20 60
cyan #00ffff 0 255 255
darkblue #00008b 0 0 139
darkcyan #008b8b 0 139 139
darkgoldenrod #b8860b 184 134 11
darkgray #a9a9a9 169 169 169
darkgreen #006400 0 100 0
darkgrey #a9a9a9 169 169 169
darkkhaki #bdb76b 189 183 107
darkmagenta #8b008b 139 0 139
darkolivegreen #556b2f 85 107 47
darkorange #ff8c00 255 140 0
darkorchid #9932cc 153 50 204
darkred #8b0000 139 0 0
darksalmon #e9967a 233 150 122
darkseagreen #8fbc8f 143 188 143
darkslateblue #483d8b 72 61 139
darkslategray #2f4f4f 47 79 79
darkslategrey #2f4f4f 47 79 79
darkturquoise #00ced1 0 206 209
darkviolet #9400d3 148 0 211
deeppink #ff1493 255 20 147
deepskyblue #00bfff 0 191 255
dimgray #696969 105 105 105
dimgrey #696969 105 105 105
dodgerblue #1e90ff 30 144 255
firebrick #b22222 178 34 34
floralwhite #fffaf0 255 250 240
forestgreen #228b22 34 139 34
fuchsia #ff00ff 255 0 255
gainsboro #dcdcdc 220 220 220
ghostwhite #f8f8ff 248 248 255
gold #ffd700 255 215 0
goldenrod #daa520 218 165 32
gray #808080 128 128 128
green #008000 0 128 0
greenyellow #adff2f 173 255 47
grey #808080 128 128 128
honeydew #f0fff0 240 255 240
hotpink #ff69b4 255 105 180
indianred #cd5c5c 205 92 92
indigo #4b0082 75 0 130
ivory #fffff0 255 255 240
khaki #f0e68c 240 230 140
lavender #e6e6fa 230 230 250
lavenderblush #fff0f5 255 240 245
lawngreen #7cfc00 124 252 0
lemonchiffon #fffacd 255 250 205
lightblue #add8e6 173 216 230
lightcoral #f08080 240 128 128
lightcyan #e0ffff 224 255 255
lightgoldenrodyellow #fafad2 250 250 210
lightgray #d3d3d3 211 211 211
lightgreen #90ee90 144 238 144
lightgrey #d3d3d3 211 211 211
lightpink #ffb6c1 255 182 193
lightsalmon #ffa07a 255 160 122
lightseagreen #20b2aa 32 178 170
lightskyblue #87cefa 135 206 250
lightslategray #778899 119 136 153
lightslategrey #778899 119 136 153
lightsteelblue #b0c4de 176 196 222
lightyellow #ffffe0 255 255 224
lime #00ff00 0 255 0
limegreen #32cd32 50 205 50
linen #faf0e6 250 240 230
magenta #ff00ff 255 0 255
maroon #800000 128 0 0
mediumaquamarine #66cdaa 102 205 170
mediumblue #0000cd 0 0 205
mediumorchid #ba55d3 186 85 211
mediumpurple #9370db 147 112 219
mediumseagreen #3cb371 60 179 113
mediumslateblue #7b68ee 123 104 238
mediumspringgreen #00fa9a 0 250 154
mediumturquoise #48d1cc 72 209 204
mediumvioletred #c71585 199 21 133
midnightblue #191970 25 25 112
mintcream #f5fffa 245 255 250
mistyrose #ffe4e1 255 228 225
moccasin #ffe4b5 255 228 181
navajowhite #ffdead 255 222 173
navy #000080 0 0 128
oldlace #fdf5e6 253 245 230
olive #808000 128 128 0
olivedrab #6b8e23 107 142 35
orange #ffa500 255 165 0
orangered #ff4500 255 69 0
orchid #da70d6 218 112 214
palegoldenrod #eee8aa 238 232 170
palegreen #98fb98 152 251 152
paleturquoise #afeeee 175 238 238
palevioletred #db7093 219 112 147
papayawhip #ffefd5 255 239 213
peachpuff #ffdab9 255 218 185
peru #cd853f 205 133 63
pink #ffc0cb 255 192 203
plum #dda0dd 221 160 221
powderblue #b0e0e6 176 224 230
purple #800080 128 0 128
rebeccapurple #663399 102 51 153
red #ff0000 255 0 0
rosybrown #bc8f8f 188 143 143
royalblue #4169e1 65 105 225
saddlebrown #8b4513 139 69 19
salmon #fa8072 250 128 114
sandybrown #f4a460 244 164 96
seagreen #2e8b57 46 139 87
seashell #fff5ee 255 245 238
sienna #a0522d 160 82 45
silver #c0c0c0 192 192 192
skyblue #87ceeb 135 206 235
slateblue #6a5acd 106 90 205
slategray #708090 112 128 144
slategrey #708090 112 128 144
snow #fffafa 255 250 250
springgreen #00ff7f 0 255 127
steelblue #4682b4 70 130 180
tan #d2b48c 210 180 140
teal #008080 0 128 128
thistle #d8bfd8 216 191 216
tomato #ff6347 255 99 71
turquoise #40e0d0 64 224 208
violet #ee82ee 238 130 238
wheat #f5deb3 245 222 179
white #ffffff 255 255 255
whitesmoke #f5f5f5 245 245 245
yellow #ffff00 255 255 0
yellowgreen #9acd32 154 205 50

注: このカラーリストと定義は SVG 1.1で定義された名前付きカラーのリストの上位集合です。

歴史的な理由で、これはX11カラ―セットとも呼ばれます。

注: X11カラ―システムの歴史は興味深く、 Alex Sextonによる "Peachpuffs and Lemonchiffons" 講演で見事にまとめられています。

6.2. システムカラー

一般に、<system-color>キーワードは ユーザー、ブラウザー、またはOSによって選択されたデフォルトの色を反映します。 そのため、通常はブラウザーのデフォルトスタイルシートで使用されます。

可読性を維持するため、 <system-color> キーワードも 要素のカラースキームに応答します。

しかし、強制カラーモードでは ページ上のほとんどの色は制限された、ユーザー選択のパレットに強制されます。 詳しくはCSS Color Adjustment 1 § 5.2 強制カラーモード用カラーパレットを参照してください。 <system-color>キーワードは これらユーザー選択色を公開するため、 他のページ部品もこの制限下パレットと統合できます。

forced-colors メディア特性がactiveの場合、 著者は可能な限り <system-color>キーワードを CSS Color Adjustment 1 § 3.1 強制カラーモードの影響を受けるプロパティに載っていない プロパティの色値として使うべきです。 そうすることでページ全体の可読性と一貫性を確保し、 ユーザー強制色とページ独自色のちぐはぐな混在を回避できます。

<system-color>キーワードの値が (OSやユーザー選択によるデフォルトではなく)ブラウザーによって提供される場合、 ブラウザーは一致する前景/背景ペアが WCAG AAコントラストの最低基準を満たすように配慮すべきです。 ただし、ユーザーの好み(高コントラストや低コントラストの指定)は ブラウザーの設定・ユーザースタイルシート・OSのデフォルト変更を問わず この要件より優先されなければなりません。

著者がこれらのキーワードをいつでも使用しても問題ありませんが、 対応する背景-前景ペアで 適切なコントラストとなるよう注意すべきです。 非対応ペア間(例: Canvas と ButtonText)の コントラスト関係が常に保証されるわけではありません。

<system-color>キーワードは以下の通り定義されます:

AccentColor
 アクセント付きUIコントロールの背景。
AccentColorText
 アクセント付きUIコントロールのテキスト。
ActiveText
 アクティブなリンクテキスト。明色系背景では従来は赤。
ButtonBorder
 プッシュボタンのベース枠線色。
ButtonFace
 プッシュボタンの表面背景色。
ButtonText
 プッシュボタン上のテキスト。
Canvas
 アプリケーションコンテンツや文書の背景。
CanvasText
 アプリケーションコンテンツや文書内のテキスト。
Field
 入力フィールドの背景。
FieldText
 入力フィールド内のテキスト。
GrayText
 無効化テキスト。(多くの場合グレーだが必ずしもそうではない)
Highlight
 選択されたテキストなどの背景(例: ::selection)。
HighlightText
 選択されたテキストの文字色。
LinkText
 非アクティブ・未訪問リンクのテキスト。明色系背景では従来は青色。
Mark
 特別にマークされたテキストの背景 (例:HTMLの mark 要素)。
MarkText
 特別にマークされたテキスト (例:HTMLの mark 要素)。
SelectedItem
 選択中のアイテム(例: 選択されたチェックボックス等)の背景。
SelectedItemText
 選択中アイテムのテキスト。
VisitedText
 訪問済みリンクのテキスト。明色系背景では従来は紫色。

注: 他のキーワード同様、 これらの名前はASCII大文字小文字を区別しません。 可読性のためここでは混在した大文字小文字で表示しています。

特定のシステムUI概念が存在しないシステムでは、 指定値は最も関連性の高いシステムカラー値にマッピングされるべきです。 次のシステムカラー組み合わせは 可読な背景-前景色を形成すると期待されます:

さらに、GrayTextは どの背景でも読めることが期待されますが、 コントラスト評価は低い場合もあります。

ウィジェットのアクセント色のスタイリングとの一貫性を保つために、 AccentColorはaccent-colorから値を取得します。 ただし、強制色モード(Forced Colors Mode)が有効の場合は除きます。 AccentColorTextは AccentColorに対するコントラストのある前景色から値を取得します。 これはウィジェットのアクセント色スタイリングについて説明されている通りです。

例えば、現在利用中のブラウザーのシステムカラー組み合わせ:

Canvas+CanvasText: CanvasText

Canvas+LinkText: LinkText

Canvas+VisitedText: VisitedText

Canvas+ActiveText: ActiveText

Canvas+GrayText: GrayText

Canvas+ButtonBorder+隣接Canvas: CanvasTextAdjacent

ButtonFace+ButtonText: ButtonText

ButtonFace+ButtonText+ButtonBorder: ButtonText

ButtonFace+GrayText: GrayText

Field+FieldText: FieldText

Field+GrayText: GrayText

Mark+MarkText: MarkText

Mark+GrayText: GrayText

Highlight+HighlightText: HighlightText

Highlight+GrayText: GrayText

SelectedItem+SelectedItemText: SelectedItemText

AccentColor+AccentColorText: AccentColorText

AccentColor+GrayText: GrayText

CSSの過去バージョンでは追加の<system-color>が定義されていましたが、 すでに廃止されています。 詳細は付録A: 廃止CSSシステムカラーを参照してください。

注: <system-color>には§ 22 プライバシーの考慮や§ 20 セキュリティの考慮で説明されているように 一部プライバシー・セキュリティリスクがあります。

ユーザーエージェントは、 指紋取得などのプライバシー・セキュリティリスクを軽減するために、 システムカラーの使用値として固定値を返し、 ユーザーによるカスタマイズやテーマ選択を反映しないことを選択することができます。

6.3. transparentキーワード

transparentキーワードは透明な黒を指定します。 <named-color>型の一種です。

6.4. currentcolorキーワード

currentcolorキーワードは、同じ要素上のcolorプロパティの値を表します。 <named-color>とは異なり、sRGBに限定されません。 値は任意の<color>型となりえます。 使用値は色値の解決により決定されます。

currentcolorキーワードの使い方例:
.foo {
  color:  red;
  background-color:  currentcolor;
}

これは次のように書くのと同じです:

.foo {
  color:  red;
  background-color:  red;
}
例えば、text-emphasis-colorプロパティ[CSS3-TEXT-DECOR]の初期値はcurrentcolorであり、 デフォルトではテキストの色と一致します。 そしてcolorプロパティが要素ごとに変わってもそれに追従します。
<p><em>Some <strong>really</strong> emphasized text.</em>
<style>
p { color: black; }
em { text-emphasis: dot; }
strong { color: red; }
</style>

rendered emphasized text with the word 'really' in red with red emphasis dots

上記の例では、「Some」や「emphasized text」部分の強調記号は黒ですが、「really」部分は赤になります。

注: CSSの複数語からなるキーワードは通常、語句の間をハイフンで区切ります。 currentcolorはそうなっていません。理由は(深呼吸してください)、 もともとSVGでプロパティ値 "current-color"(一般的なCSSの綴り)として導入されたためです。 それが(他の全てのプロパティや値とともに) プレゼンテーション属性・属性値(およびプロパティ)にもなり、 XSLTでの生成を容易にする設計となりました。 その後、すべてのプレゼンテーション属性がハイフン区切りからキャメルケースに変更されましたが、 DOMではハイフンが「マイナス」を意味し問題となっていたためです。 しかし、これだとCSSの慣習に従わなくなったので、 すでにCSSの一部だったプロパティと値はハイフン区切りに戻されました! currentcolorはその時点ではCSSの一部ではなかったため、 キャメルケースのまま残りました。 その後、CSSがcurrentcolorを採用し、 キーワードの大文字小文字が重要ではなくなりました。 CSSキーワードはASCII大文字小文字非区別だからです。

7. HSLカラー: hsl() と hsla()関数

RGB方式による色指定は、 機械やグラフィックライブラリには便利ですが、 人間が直感的に理解するのは非常に難しいとよく言われます。 例えば、RGBの色をどう変更すれば同じ色相のより明るいバリエーションになるのかを 判断するのは容易ではありません。

他にもいくつかの色体系が考案されています。 そのひとつがHSL [HSL]色体系です。 これはより直感的に使える一方で、 RGB色にも容易に変換できます。

HSLカラーは 色相・彩度・明度の3つ組で指定します。 hsl()およびhsla()関数の構文は次の通りです:

hsl() = [ <legacy-hsl-syntax> | <modern-hsl-syntax> ]
hsla() = [ <legacy-hsla-syntax> | <modern-hsla-syntax> ]
<modern-hsl-syntax> = hsl(
    [<hue> | none]
    [<percentage> | <number> | none]
    [<percentage> | <number> | none]
    [ / [<alpha-value> | none] ]? )
<modern-hsla-syntax> = hsla(
    [<hue> | none]
    [<percentage> | <number> | none]
    [<percentage> | <number> | none]
    [ / [<alpha-value> | none] ]? )
<legacy-hsl-syntax> = hsl( <hue>, <percentage>, <percentage>, <alpha-value>? )
<legacy-hsla-syntax> = hsla( <hue>, <percentage>, <percentage>, <alpha-value>? )
パーセンテージ SとLで利用可能
パーセント基準範囲 SとL: 0% = 0.0, 100% = 100.0
無効色相ε S <= 0.001

最初の引数は色相角度を指定します。

HSL(およびHWB)では、0degはsRGB主赤色を表します (360deg、720deg等も同様)、 他の色相は円周上に配置されるので 120degはsRGB主緑、240degはsRGB主青などを表します。

次の2つの引数は、彩度と明度です。 彩度については、100%または100が完全に鮮やかな明るい色、 0%または0が完全に無彩色のグレーです。 明度については、50%または50が「標準」色、 100%または100が白、0%または0が黒です。

歴史的理由により、 彩度が0%未満の場合はパース時に0%へクランプされ、 sRGB色に変換されます。

最後の引数は色のアルファ成分を指定します。 rgb()関数の第4引数と同様に解釈されます。 省略時は100%がデフォルトです。

HSLカラーはsRGBに解決されます。

HSLカラーの彩度が0%または0なら、 色相成分は無効です。

例えば通常の赤、 redキーワードや #f0016進表記と同じ色は、 HSLではhsl(0deg 100% 50%)で表されます。

HSLの利点はRGBよりも直感的であることです。 欲しい色を推測して微調整できます。

たとえば、基本の「緑」色相を使って 他の2つの引数だけを変えることで、次のような色が生成できます:
hsl(120deg 100% 50%) ライムグリーン
hsl(120deg 100% 25%) ダークグリーン
hsl(120deg 100% 75%) ライトグリーン
hsl(120deg 75% 85%)  パステルグリーン

HSLの欠点はOKLChと比べて 色相操作で見た目の明度が変化すること、 色相が均等に分布していないことです。

HSLでは色相を固定して彩度・明度だけ変化させることで セットの色を作りやすく、 sRGB成分値を操作するよりも簡単です。 ただし、明度はガンマ補正後の赤・緑・青成分の平均値なので、 色相全体で見た目の明度と一致しません。

例えば、blueはHSLではhsl(240deg 100% 50%)、 yellowは hsl(60deg 100% 50%)です。 両者ともHSL明度は50%ですが、 実際には黄色の方が青よりもずっと明るく見えます。

OKLChでは、sRGB青はoklch(0.452 0.313 264.1)、 sRGB黄色はoklch(0.968 0.211 109.8)であり、 OKLCh明度0.452と0.968は見た目の明度差を正確に反映しています。

HSLの色相角は知覚的に均一ではなく、 一部の領域では色が密集し、 他の領域では広く分布します。

例えば、色相hsl(220deg 100% 50%)とhsl(250deg 100% 50%)は HSL色相差が30度ですが、見た目はかなり近く見えます。 一方、hsl(50deg 100% 50%)と hsl(80deg 100% 50%)も 色相差は30度ですが、見た目は大きく異なります。

OKLChでは、同じ色のペア oklch(0.533 0.26 262.6)と oklch(0.462 0.306 268.9)は 色相差6.3度、 もう一方のペア oklch(0.882 0.181 94.24)と oklch(0.91 0.245 129.9)は 色相差35.66度となり、見た目の分離を正しく反映しています。

歴史的理由により、hsl()およびhsla()はレガシーカラー構文もサポートします。

7.1. HSLカラーからsRGBへの変換

HSLカラーをsRGBに変換することは数学的に簡単です。 こちらは変換アルゴリズムのJavaScriptによるサンプル実装です。 配列で赤・緑・青成分(sRGBガマット内の場合は[0, 1]範囲)を返します。

このコードは、パース時に負の彩度のクランプ処理が既に適用されていることを前提とします。

/**
 * @param {number} hue - 色相(度数 0..360)
 * @param {number} sat - 彩度(基準範囲 [0,100])
 * @param {number} light - 明度(基準範囲 [0,100])
 * @return {number[]} sRGB成分の配列。ガマット内は[0..1]
 */
function hslToRgb(hue, sat, light) {

    sat /= 100;
    light /= 100;

    function f(n) {
        let k = (n + hue/30) % 12;
        let a = sat * Math.min(light, 1 - light);
        return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
    }

    return [f(0), f(8), f(4)];
}

7.2. sRGBカラーからHSLへの変換

逆方向の変換も同様に行います。

sRGBガマット外の色では中間値に負の彩度が生じる場合があるため、 その処理に注意します。

/**
 * @param {number} red - 赤成分 0..1
 * @param {number} green - 緑成分 0..1
 * @param {number} blue - 青成分 0..1
 * @return {number[]} HSL値の配列: 色相は度数0..360、彩度と明度は参照範囲[0,100]
 */
function rgbToHsl (red, green, blue) {
    let max = Math.max(red, green, blue);
    let min = Math.min(red, green, blue);
    let [hue, sat, light] = [NaN, 0, (min + max)/2];
    let d = max - min;
    let epsilon = 1 / 100000;   // このコードでは最大彩度は1

    if (d !== 0) {
        sat = (light === 0 || light === 1)
            ? 0
            : (max - light) / Math.min(light, 1 - light);

        switch (max) {
            case red:   hue = (green - blue) / d + (green < blue ? 6 : 0); break;
            case green: hue = (blue - red) / d + 2; break;
            case blue:  hue = (red - green) / d + 4;
        }

        hue = hue * 60;
    }

    // ガマット外の色は負の彩度になる場合がある
    // その場合、色相を180度回転し、正の彩度を使う
    // 詳細:https://github.com/w3c/csswg-drafts/issues/9222
    if (sat < 0) {
        hue += 180;
        sat = Math.abs(sat);
    }

    if (hue >= 360) {
        hue -= 360;
    }

    if (sat <= epsilon) {
        hue = NaN;
    }

    return [hue, sat * 100, light * 100];
}

7.3. HSL色の例

このセクションは規範的ではありません。

以下の表は、さまざまなHSL色の幅広いバリエーションを示しています。 各表は1つの色相を表しており、 30°ごとに選択されています。 これは一般的な「コア」色相を示すためです: 赤、 黄、 緑、 シアン、 青、 マゼンタ、 そしてこれらの間に位置する6つの中間色です。

各表では、X軸は彩度を、 Y軸は明度を表しています。

0° レッド
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
30° レッド-イエロー(=オレンジ)
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
60° イエロー
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
90° イエローグリーン
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
120° グリーン
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
150° グリーン-シアン
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
180° シアン
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
210° シアン-ブルー
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
240° ブルー
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
270° ブルー・マゼンタ
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
300° マゼンタ
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%
330° マゼンタ-レッド
100% 80% 60% 40% 20% 0%
100%
90%
80%
70%
60%
50%
40%
30%
20%
10%
0%

8. HWB色: hwb() 関数

HWB(Hue-Whiteness-Blacknessの略)[HWB] は、sRGB色を指定するもうひとつの方法であり、 HSLに似ていますが、しばしば人間にとってさらに扱いやすいものです。 最初に色相を指定し、 その基本色相に白さと黒さの度合いを混ぜることで色を表します。

多くのカラーピッカーはHWBカラーモデルを基にしており、 その直感的な使いやすさが理由です。

HWB色はsRGBに解決されます。

これはChromeのカラーピッカーのスクリーンショットです。 ユーザーが <input type="color"> を操作した際に表示されます。 外側のホイールで色相を選択し、 内側の三角形をクリックすることで白と黒の割合を選択します。

hwb() 関数の構文は次の通りです:

hwb() = hwb(
  [<hue> | none]
  [<percentage> | <number> | none]
  [<percentage> | <number> | none]
  [ / [<alpha-value> | none] ]? )
パーセンテージ WとBで使用可能
パーセント参照範囲 WとB:0% = 0.0、100% = 100.0
無効色相 ε W + B >= 99.999

最初の引数は色相を指定し、 hsl()と同じ定義です; つまり同じ欠点(色相の均一性など)を持ちます。

2番目の引数は、混ぜる白の量をパーセンテージで指定します。0%(白なし)から100%(完全に白)までです。 同様に、3番目の引数は混ぜる黒の量を指定し、 0%(黒なし)から100%(完全に黒)までです。

例: hwb(150 20% 10%) は、 hsl(150 77.78% 55%) および rgb(20% 90% 55%) と同じ色です。

注: hwb() はアブニー効果を考慮していません [Abney] これは、単色光源に白色光を加えたときに生じる 知覚上の色相のずれです。

これらの範囲外の値は 無効ではありません; 色相角が[0,360)の範囲外ならその範囲に正規化され、 白と黒の値の合計が100%以上の場合は 以下に記載するように無彩色が生成されます。

得られる色は、選択した色相の絵の具、白の絵の具、黒の絵の具を混ぜた混合物と概念的に考えることができます。 各割合はパーセンテージで決まります。

white+blackの合計が100%以上の場合、 それは無彩色(グレーの一種)を定義します。 sRGBに変換した場合、R・G・Bの値はすべて同じになり、 値は white / (white + black) となります。

例:色 hwb(45 40% 80%) は white と black を足すと120になり、これは無彩色です。 R・G・B成分は 40 / 40 + 80 = 0.33 となります rgb(33.33% 33.33% 33.33%) 。

無彩色のHWB色は、選択した色相の情報を持ちません。 この場合、色相成分は無効です。

4番目の引数は色のアルファ成分を指定します。 rgb()関数の4番目の引数と同じ解釈です。 省略した場合は 100% になります。

このレベルの仕様で新たに導入された hwb には、 Web 互換性の問題がないため、 hwb() は、すべての引数をカンマで区切る 旧来の色構文を サポートしません。 hwb() 内でカンマを使用するとエラーになります。

8.1. HWB色をsRGBに変換する

HWB色をsRGBに変換するのは簡単で、 HSLをRGBに変換する方法と関連しています。 以下のJavascriptによるアルゴリズム実装は まず白と黒の成分を正規化し、 その合計が100%を超えないようにします。

/**
 * @param {number} hue -  色相(度数 0..360)
 * @param {number} white -  白さ(参照範囲 [0,100])
 * @param {number} black -  黒さ(参照範囲 [0,100])
 * @return {number[]} RGB成分の配列(0..1)
 */
function hwbToRgb(hue, white, black) {
    white /= 100;
    black /= 100;
    if (white + black >= 1) {
        let gray = white / (white + black);
        return [gray, gray, gray];
    }
    let rgb = hslToRgb(hue, 100, 50);
    for (let i = 0; i < 3; i++) {
        rgb[i] *= (1 - white - black);
        rgb[i] += white;
    }
    return rgb;
}

8.2. sRGB色をHWBに変換する

逆方向の変換も同様に進みます。

/**
 * @param {number} red - 赤成分(0..1)
 * @param {number} green - 緑成分(0..1)
 * @param {number} blue - 青成分(0..1)
 * @return {number} 色相(度数 0..360)
 */
function rgbToHue(red, green, blue) {
    // rgbToHslと似ていますが、彩度と明度は計算せず、
    // 負の彩度になる可能性は無視します。
    let max = Math.max(red, green, blue);
    let min = Math.min(red, green, blue);
    let hue = NaN;
    let d = max - min;

    if (d !== 0) {
        switch (max) {
            case red:   hue = (green - blue) / d + (green < blue ? 6 : 0); break;
            case green: hue = (blue - red) / d + 2; break;
            case blue:  hue = (red - green) / d + 4;
        }

        hue *= 60;
    }

    if (hue >= 360) {
        hue -= 360;
    }

    return hue;
}

/**
 * @param {number} red - 赤成分(0..1)
 * @param {number} green - 緑成分(0..1)
 * @param {number} blue - 青成分(0..1)
 * @return {number[]} HWB値の配列: 色相(度数 0..360)、白さと黒さ(参照範囲 [0,100])
 */
function rgbToHwb(red, green, blue) {
    let epsilon = 1 / 100000;  // 100倍を考慮
    var hue = rgbToHue(red, green, blue);
    var white = Math.min(red, green, blue);
    var black = 1 - Math.max(red, green, blue);
    if (white + black >= 1 - epsilon) {
        hue = NaN;
    }
    return([hue, white*100, black*100]);
}

8.3. HWB色の例

このセクションは規定ではありません。

0° レッド
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
30° レッド-イエロー(オレンジ)
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
60° イエロー
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
90° イエロー-グリーン
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
120° グリーン
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
150° グリーン-シアン
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
180° シアン
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
210° シアン-ブルー
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
240° ブルー
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
270° ブルー・マゼンタ
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
300° マゼンタ
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%
330° マゼンタ-レッド
白\黒 0% 20% 40% 60% 80% 100%
0%
20%
40%
60%
80%
100%

9. デバイス非依存色:CIE Lab と LCH、Oklab と OkLCh

9.1. CIE LabとLCH

このセクションは規定ではありません。

色の物理測定値は、通常CIE L*a*b* [CIELAB] 色空間で表されます。 これは1976年にCIEによって作成され、一般的にLabと呼ばれています。 デバイス間の色変換でもLabが中間ステップとして使われることがあります。 人の視覚実験に基づいて派生したLabは、人間が見える色の全範囲を表現しています。

Labは、中央に明度(L)軸を持つ直交座標系です。 この値は通常単位なしの数値として記述されますが、 CSSの互換性のためにパーセンテージとして記述することもできます。 100%はL値が100を意味し、1.0ではありません。 L=0%または0は完全な黒(光がまったくない)、 L=100%または100は拡散白です。

便利なことに、L=50%または50は設計上中間のグレーであり、 Lの等間隔の増分は視覚的にも均等です。 Lab色空間は知覚的に均一を意図しています。

この図は、左側にCIE Lab色空間の明度軸を示しています。 21個のニュートラルスウォッチ(L=0%、L=5%からL=100%まで)が表示されています。 ステップは視覚的に等間隔です。 右側は、輝度における同じ数のステップを光エネルギーで等間隔にした場合ですが、視覚的には等間隔ではありません。

a軸とb軸は色相を表します。 a軸の正の値は紫がかった赤、 負の値は補色である緑を示します。 同様に、b軸の正の値は黄色、 負の値は補色の青/バイオレットを示します。 脱彩色の色はaとbの値が小さくL軸に近く、 彩度の高い色はL軸から遠くにあります。

光源はD50ホワイトであり、色温度5000Kの標準化された昼光スペクトルです。 完全拡散反射体で反射されたものとして定義され、晴天の日の太陽光の色に近似します。 D50はICC色変換におけるプロファイル接続空間のホワイトポイントでもあり、 Lab編集を提供する画像編集ソフトのホワイトポイント、 物理測定機器(分光光度計や分光放射計)がLabで測色値を報告するときも使われる値です。

他のホワイトポイントで指定された色からの変換は色順応変換と呼ばれます。 これは新しい照明条件に人の視覚が順応する変化をモデル化します。 線形Bradfordアルゴリズム [ICC](元のBradfordアルゴリズム[Bradford-CAT]の単純化版)は 業界標準の色順応変換であり、単なる行列乗算なので計算は容易です。

CIE LCHはLabと同じL軸を持ちますが、 極座標C(彩度)とH(色相)を使い、 極円筒座標系となっています。 CはL軸からの幾何学的距離、 Hは正のa軸から正のb軸方向への角度です。

この図はCIE Lab色空間のL=50平面を示しています。 CIE LCHで20度刻みの色相円が3段階のChroma(20、40、60)で表示されています。 Chroma 20の色はすべてsRGBガマット内に収まりますが、 40や60の一部はガマット外です。 ガマット外の色はグレーで、赤い警告枠で表示されています。

注意: LabやLCHのL軸は、HSLのL軸と混同しないでください。 例えば、HSLではsRGBの青(#00F)と黄色(#FF0)は同じL値(50%)ですが、視覚的には青の方がずっと暗いです。 Labではより明確です: sRGB青は lab(29.567% 68.298 -112.0294)、 sRGB黄色は lab(97.607% -15.753 93.388) です。 LabやLCHでL値が同じ2色は、視覚的な明度が同じです。 HSLや関連する極座標RGBモデルは、 LabのLCHが提供した使いやすさをRGBに持ち込むために開発されましたが、 精度は大きく劣ります。

CIE LabやLCHは広く使われていますが、 いくつかの問題が知られています。特に:

色相の線形性
青領域(LCH色相270°から330°)で、視覚的色相がLCHの予測から外れます。 同じ色相でChromaのみ異なる青をプロットすると、 本来ニュートラル軸から直線になるはずが、 曲線になります。 言い換えると、 彩度の高い青のChromaを徐々に減らしていくと、 目立って紫がかってきます。
色相の均一性
LCHの色相は概ね均等間隔ですが (HSLやHWBより遥かに良い)、 完全な均一性ではありません。
高Chroma差の過大予測
Chromaが高い色では Chromaの変化は中間色と比べて 視覚的に目立ちません。

これらの欠点は、たとえば 均等間隔グラデーションの作成や 色空間間のガマットマッピング、 2色間の視覚的差分計算などに影響します。

これへの対処として、 2色間の視覚的差分(ΔE)算出式は より正確に進化してきました (計算も複雑化しています)。 現在の業界標準式は ΔE2000で、 LabやLCHの問題をある程度緩和します。 実装例は § 20.2 ΔE2000 に示されています。

ただし、色相の曲がりには対応できません。

9.2. Oklab および OkLCh

このセクションは規定ではありません。

最近、Oklabという 改良型Lab類似空間が開発されました [Oklab]。 極座標形はOKLChと呼ばれます。 大規模な視覚的類似色データセットの数値最適化によって作られ、 従来のCIE LCHに比べ 色相の線形性、 色相の均一性、 彩度の均一性が改善されています。

CIE Labと同様、中央に明度L軸があり 通常は[0,1]範囲の単位なし数値で記述されますが、 CSS互換のためパーセンテージ記述も可能です。100%はL値1.0を意味します。 L=0%または0.0は完全な黒、L=100%または1.0は拡散白です。

注意: CIE Labが拡散白への順応を仮定するのに対し、 Oklabは定義される色への順応を仮定し、 スケール不変性を持たせることを意図しています。

CIE Labと同様、a軸とb軸が色相を伝えます。 a軸正は紫がかった赤、 負は補色の緑です。 b軸正は黄色、 負は補色の青/バイオレットです。

光源はD65で、 ほとんどのRGB色空間と同じホワイトポイントです。

OKLChはOklabと同じL軸を持ち、 極座標C(彩度)とH(色相)で表します。

注意: CIE LCHではChromaが200以上になることもありますが、 OKLChのChromaは0.5程度までです。 CIE LCHとOKLChの色相角は大まかに似ていますが、 完全一致ではありません。

diagram showing purpling in CIE LCH
一定のCIE LCH色相スライスで、 sRGBガマットの主青周辺を示します。 紫化がはっきり見られます。
diagram showing hue constancy in OKLCh
一定のOKLCh色相スライスで、 sRGBガマットの主青周辺を示します。 視覚的色相は一定のままです。

OklabはCIE Labより知覚的均一性が高いため、 色差は3次元空間の単純な距離(2乗和の平方根)になります。 実装は trivial ですが、 サンプルは § 20.3 ΔEOK に示されています。

9.3. LabおよびLCHの指定:lab() および lch() 関数表記

CSSではLabおよびLCHで色を直接表現できます。

lab() = lab( [<percentage> | <number> | none]
      [ <percentage> | <number> | none]
      [ <percentage> | <number> | none]
      [ / [<alpha-value> | none] ]? )
パーセンテージ L、a、bで使用可能
パーセント参照範囲 L: 0% = 0.0, 100% = 100.0
a, b: -100% = -125, 100% = 125

Labでは、 最初の引数はCIE明度Lを指定します。 これは0%または0から 100%または100までの数値です。 0%または0未満の値は解析時に0%に丸められます。 100%または100より大きい値は解析時に100%に丸められます。

第2および第3引数は、Lab色空間における「a」軸および「b」軸に沿った距離です。 詳細は前節で説明しています。 これらの値は符号付き (プラスとマイナスの両方が可能)であり、 理論上は無限ですが (実際には実世界の色では±160を超えることはありません)。

4番目の<alpha-value>成分はオプションです。 スラッシュで区切られ、アルファ成分を表します。

Lab色の明度(clampされた後)が0%または100%の場合、 ディスプレイのガマットマッピングのため、 それぞれ黒または白として表示されます。

 lab(29.2345% 39.3825 20.0664);
 lab(52.2345 40.1645 59.9971);
 lab(60.2345 -5.3654 58.956);
 lab(62.2345% -34.9638 47.7721);
 lab(67.5345 -8.6911 -41.6019);
 lab(29.69% 44.888% -29.04%)
lch() = lch( [<percentage> | <number> | none]
      [ <percentage> | <number> | none]
      [ <hue> | none]
      [ / [<alpha-value> | none] ]? )
パーセンテージ L、Cで使用可能
パーセント参照範囲 L: 0% = 0.0, 100% = 100.0
C: 0% = 0, 100% = 150
無効色相 ε C <= 0.0015

CIE LCHでは最初の引数がCIE明度Lを指定し、 lab() の明度引数と同じ解釈です。

2番目の引数はクロマC (「色の量」を大まかに表す)。 最小値は0で、 最大値は理論上は制限されません (実用上は230を超えません)。 負の値は解析時に0に丸められます。

3番目の引数は色相角Hです。 <hue>引数やhsl()と類似の解釈ですが、 CIE LCHは知覚的均一性で均等になるため RGBの色相角とは一致しません。 0degは正のa軸(赤紫方向)で、 360degや720degも同じ方向です。 90degは正のb軸(マスタードイエロー方向)、 180degは負のa軸(シアン方向)、 270degは負のb軸(空色方向)です。

4番目の引数として、スラッシュで区切られたオプションの<alpha-value>成分があります。 これはアルファ成分を表します。

LCH色のクロマが0%の場合、 色相成分は無効です。 LCH色の明度(丸め後)が0%または100%の場合、 ディスプレイへのガマットマッピングにより、それぞれ黒または白で表示されます。

 lch(29.2345% 44.2 27);
 lch(52.2345% 72.2 56.2);
 lch(60.2345 59.2 95.2);
 lch(62.2345% 59.2 126.2);
 lch(67.5345% 42.5 258.2);
 lch(29.69% 45.553% 327.1)

labやlchは勧告案の新機能であり、Web互換性の問題はありません。 したがってlab()やlch()は、引数をカンマ区切りするレガシーカラー構文をサポートしません。 これらの関数内でカンマを使用するとエラーとなります。

9.4. Oklab と OkLCh の指定: oklab() および oklch() 関数表記

CSSではOklabおよびOKLChで色を直接表現できます。

oklab() = oklab( [ <percentage> | <number> | none]
    [ <percentage> | <number> | none]
    [ <percentage> | <number> | none]
    [ / [<alpha-value> | none] ]? )
パーセンテージ L、a、bで使用可能
パーセント参照範囲 L: 0% = 0.0, 100% = 1.0
a, b: -100% = -0.4, 100% = 0.4

Oklabでは、最初の引数がOklabの明度を指定します。 これは0%または0から 100%または1.0までの数値です。

0%または0.0未満の値は解析時に0%に丸められます。 100%または1.0より大きい値は解析時に100%に丸められます。

2番目と3番目の引数はOklab色空間の「a」「b」軸方向の距離です(前節参照)。 これらは符号付き(正・負どちらも可)で、理論上は制限されません (実際は±0.5を超えません)。

4番目の引数として、スラッシュで区切られたオプションの<alpha-value>成分があります。 これはアルファ成分を表します。

Oklab色の明度が0%または0、 100%または1.0の場合、 ディスプレイへのガマットマッピングにより、それぞれ黒または白で表示されます。

 oklab(40.101% 0.1147 0.0453);
 oklab(59.686% 0.1009 0.1192);
 oklab(0.65125 -0.0320 0.1274);
 oklab(66.016% -0.1084 0.1114);
 oklab(72.322% -0.0465 -0.1150);
 oklab(42.1% 41% -25%)
oklch() = oklch( [ <percentage> | <number> | none]
      [ <percentage> | <number> | none]
      [ <hue> | none]
      [ / [<alpha-value> | none] ]? )
パーセンテージ L、Cで使用可能
パーセント参照範囲 L: 0% = 0.0, 100% = 1.0
C: 0% = 0.0 100% = 0.4
無効色相 ε C <= 0.000004

OkLChでは 第1引数はOkLChの明度Lを指定し、 oklab()の明度引数と同じように解釈されます。

第2引数は彩度Cです。 その有効な最小値は0であり、 最大値は理論上は制限されませんが (実際には0.5を超えることはありません)。 指定値が負の場合、パース時に0まで丸められます(clampされます)。

第3引数は色相角Hです。 <hue>引数として hsl()や lch()と 似たように解釈されますが、色相と角度のマッピング方法は同じではありません。 0degは正の「a」軸(赤紫寄りの赤方向)を指します (360degや720degなども同様)。 90degは正の「b」軸(マスタードイエロー方向)を指し、 180degは負の「a」軸(グリーン寄りのシアン方向)を指し、 270degは負の「b」軸(空色方向)を指します。

4番目の<alpha-value>成分はオプションです。 スラッシュで区切り、アルファ成分を表します。

OkLCh色の彩度が0%または0の場合、 色相成分は非効果成分(powerless)となります。 OkLCh色の明度が0%または0、 もしくは100%または1.0の場合、 ディスプレイのガマットマッピングによってそれぞれ黒または白として表示されます。

 oklch(40.101% 0.12332 21.555);
 oklch(59.686% 0.15619 49.7694);
 oklch(0.65125 0.13138 104.097);
 oklch(0.66016 0.15546 134.231);
 oklch(72.322% 0.12403 247.996);
 oklch(42.1% 48.25% 328.4)

この仕様レベルで新たに導入された oklab または oklch にはウェブ互換性の問題がないため、 oklab() および oklch() は、 すべての引数をコンマで区切る 従来の色構文を サポートしません。 これらの関数内でコンマを使用するとエラーになります。

9.5. LabまたはOklab色をLCHまたはOkLCh色へ変換

極座標形式への変換は簡単です:

  1. C = sqrt(a^2 + b^2)
  2. if (C > epsilon) H = atan2(b, a) else Hは欠落
  3. Lはそのまま

aとbが極端に小さい値の場合(クロマがほぼゼロ)、 視覚的な色はニュートラル軸上のまま変化しませんが、 その値をわずかに変更すると報告される色相角は激しく揺れたり ほぼランダムになります。 CSSではこの場合、色相はpowerless(無効)とみなされ、 LCHまたはOkLChへ変換するときはmissing(欠落)として扱われます。 CSS以外のコンテキストではNaNなどの「欠落値」として反映される場合があります。

9.6. LCHまたはOkLCh色をLabまたはOklab色へ変換

直交座標形式への変換は簡単です:

  1. Hが欠落している場合、H = 0
    1. a = C cos(H)
    2. b = C sin(H)
  2. Lはそのまま

10. 定義済み色空間

CSSは複数の定義済み色空間を提供しています。 例えば、display-p3 [Display-P3]は勧告案の広色域モニターで典型的な広色域空間であり、 prophoto-rgbは写真家に広く使われています。 また、rec2020 [Rec.2020]は放送業界標準の超広色域空間で、ほぼすべての現実世界の可視色を表現できます。

10.1. 定義済み色の指定:color() 関数

color() 関数は、 特定の色空間(他の色関数は暗黙のsRGB色空間)で色を指定できます。 構文は以下の通りです:

color() = color( <colorspace-params> [ / [ <alpha-value> | none ] ]? )
<colorspace-params> = [ <predefined-rgb-params> | <xyz-params>]
<predefined-rgb-params> = <predefined-rgb> [ <number> | <percentage> | none ]{3}
<predefined-rgb> = srgb | srgb-linear | display-p3 | display-p3-linear | a98-rgb | prophoto-rgb | rec2020
<xyz-params> = <xyz-space> [ <number> | <percentage> | none ]{3}
<xyz-space> = xyz | xyz-d50 | xyz-d65

color関数は、明示的にリストされた色空間で色のパラメータを指定します。

この関数は、下記のような無効色 または有効色を表します。

パラメータの形式は以下の通りです:

ガマット外色は成分値が 0や0%未満、1や100%超です。 これらは無効ではなく、中間計算のため保持されます。 ただし表示時にはcssガマットマッピングにより色空間(ディスプレイ空間)で 0/0%~1/100%に収まるよう相対色域マッピングで値が調整されます(actual-value時)。

color()は 勧告案の新機能であり、Web互換性の問題はありません。 したがってcolor()は、引数をカンマ区切りするレガシーカラー構文をサポートしません。 この関数内でカンマを使うとエラーとなります。

無効色 またはガマット外色は表示できません。

指定した色が表示できる場合 (無効色でもガマット外でもない場合)、 それがcolor()関数のactual valueとなります。

指定した色が 有効色だが表示できない場合、 actual valueは指定色のcssガマットマッピング後の値となります。

色が無効色の場合、 used valueは不透明な黒です。

この非常に強烈なライム色は、rec.2020のガマット内です:
color(rec2020 0.42053 0.979780 0.00579);
LCHでは、その色は
lch(85.9017% 166.116 138.207);
display-p3では、その色は
color(display-p3 -0.350289 1.00707 -0.144209);
そして display-p3 ではガマット外です (赤と青は負、緑が1より大きい)。 display-p3画面をお持ちの場合、その色は: 表示のために使われる色は、ガマットマッピングによって自動生成される より弱い色になります。
この例はタイプミスがあります! profoto-rgb空間(存在しない)で鮮やかな緑を指定しています。 これは無効なので、used valueは不透明な黒となります。
color(profoto-rgb 0.4835 0.9167 0.2188)

10. 定義済みsRGB色空間:sRGB キーワード

sRGB 定義済み色空間は 以下に定義されており、 レガシーsRGB色(rgb()など)で使われるものと同一です。

srgb
srgb [SRGB] 色空間は3つの数値パラメータを受け取り、 色の赤・緑・青成分を表します。 ガマット内色は3成分とも[0, 1]の範囲です。 ホワイトポイントはD65です。

[SRGB] では「エンコーディング」と「典型」の2つの視聴条件を規定しています。[ICC]は色変換や最適視聴には「エンコーディング」条件の値(下記表)を推奨しています。

sRGBはCSSのデフォルト色空間であり、 レガシー色関数すべてに使われます。

特徴は次の通りです:

x y
赤色度 0.640 0.330
緑色度 0.300 0.600
青色度 0.150 0.060
白色度 D65
伝達関数 下記参照
白輝度 80.0 cd/m2
黒輝度 0.20 cd/m2
画像状態 display-referred(ディスプレイ基準)
パーセンテージ R, G, Bで使用可能
パーセント参照範囲 R,G,B: 0% = 0.0, 100% = 1.0
let sign = c < 0? -1 : 1;
let abs = Math.abs(c);

if (abs <= 0.04045) {
  cl = c / 12.92;
}
else {
  cl = sign * (Math.pow((abs + 0.055) / 1.055, 2.4));
}
cはガンマエンコードされたR, G, B成分です。 clは対応する線形光成分です。
Oklch における sRGB の原色と二次色の図
Oklch における sRGB 色空間の視覚化。原色と二次色が示されています。

10.3. 定義済み線形光sRGB色空間:srgb-linear キーワード

sRGB-linear 定義済み色空間は srgb と同じですが、 伝達関数が線形光(ガンマエンコードなし)です。

srgb-linear
srgb-linear [SRGB] 色空間は3つの数値パラメータを受け取り、 色の赤・緑・青成分を表します。 ガマット内色は3成分とも[0, 1]の範囲です。 ホワイトポイントはD65です。

特徴は次の通りです:

x y
赤色度 0.640 0.330
緑色度 0.300 0.600
青色度 0.150 0.060
白色度 D65
伝達関数 恒等(unity)、下記参照
白輝度 80.0 cd/m2
黒輝度 0.20 cd/m2
画像状態 display-referred(ディスプレイ基準)
パーセンテージ R, G, Bで使用可能
パーセント参照範囲 R,G,B: 0% = 0.0, 100% = 1.0
cl = c;
cは赤・緑・青成分。 clは対応する線形光成分で、同じ値です。

バンディング(階調の縞模様)を防ぐため、srgb-linearは srgb-linear の方が srgb よりも高い精度が必要です。

例えば、これらは同じ色です
 color(srgb 0.691 0.139 0.259)
 color(srgb-linear 0.435 0.017 0.055)

10.4. 定義済みDisplay P3色空間:display-p3 キーワード

display-p3
display-p3 [Display-P3] 色空間は3つの数値パラメータを受け取り、 色の赤・緑・青成分を表します。 ガマット内色は3成分とも[0, 1]の範囲です。 [DCI-P3]と同じ主色度を使いますが、 ホワイトポイントはD65であり、伝達曲線はsRGBと同じです。

現代のディスプレイ、テレビ、ノートPCやスマートフォンの画面は display-p3のガマットをすべて、またはほぼすべて表示できます。

特徴は次の通りです:

x y
赤色度 0.680 0.320
緑色度 0.265 0.690
青色度 0.150 0.060
白色度 D65
伝達関数 srgbと同じ
白輝度 80.0 cd/m2
黒輝度 0.80 cd/m2
画像状態 display-referred(ディスプレイ基準)
パーセンテージ R, G, Bで使用可能
パーセント参照範囲 R,G,B: 0% = 0.0, 100% = 1.0
Oklch における P3 の原色と二次色の図
Oklch における P3 色空間の視覚化。 原色と二次色が示されています (ただし、正しい色ではなく sRGB で表示されています)。 比較のため、sRGB の原色と二次色も 破線の円で示されています。 P3 の原色はより高いクロマを持ちます。

10.5. 定義済み線形光 Display P3 色空間: display-p3-linear キーワード

display-p3-linear
display-p3-linear 定義済み色空間は、伝達関数が 線形光である(ガンマ符号化がない)点を除いて、display-p3 と同じです。

これは以下の特性を持ちます:

x y
赤の色度 0.680 0.320
緑の色度 0.265 0.690
青の色度 0.150 0.060
白色度 D65
伝達関数 1、以下を参照
白輝度 80.0 cd/m2
黒輝度 0.80 cd/m2
画像状態 ディスプレイ参照
パーセンテージ R、G、B に許可
パーセント参照範囲 R、G、B について: 0% = 0.0、100% = 1.0
cl = c;

c は赤、緑、青のいずれかの成分です。 cl は対応する線形光成分であり、同一です。

バンディングアーティファクトを避けるため、 より高い精度が必要です 。display-p3-linear には、display-p3 よりも高い精度が必要です。

例えば、これらは同じ色です
 color(display-p3 0.591 0.123 0.264)
 color(display-p3-linear 0.3081 0.014 0.0567)

10.6. 事前定義されたA98 RGB色空間: a98-rgbキーワード

a98-rgb
a98-rgb色空間は3つの数値パラメータを受け取ります。 それぞれ色の赤・緑・青成分を表します。 ガマット内の色は3成分すべてが[0, 1]の範囲です。 伝達曲線はガンマ関数ですが、正確に1/2.2ではありません。

特性は以下の通りです:

x y
赤の色度 0.6400 0.3300
緑の色度 0.2100 0.7100
青の色度 0.1500 0.0600
白の色度 D65
伝達関数 256/563
白色輝度 160.0 cd/m2
黒色輝度 0.5557 cd/m2
画像状態 ディスプレイ参照
パーセンテージ R, G, Bに対し許可
パーセント基準範囲 R, G, Bについて: 0% = 0.0, 100% = 1.0
Oklch における a98 の原色と二次色の図
Oklch における A98 色空間の視覚化。 原色と二次色が示されています (ただし、正しい色ではなく sRGB で表示されています)。 比較のため、sRGB の原色と二次色も 破線の円で示されています。 a98 の原色はより高いクロマを持ち、 特に黄色、緑色、シアンで顕著です。

10.7. 事前定義されたProPhoto RGB色空間: prophoto-rgb キーワード

prophoto-rgb
prophoto-rgb 色空間は3つの数値パラメータを受け取り、 色の赤・緑・青成分を表します。 ガマット内色は3成分とも[0, 1]の範囲です。 伝達曲線は 1/1.8のガンマ関数で、黒付近には小さな線形部分があります。 ホワイトポイントはD50で、CIE Labと同じです。よって、 CIE Labへの変換にクロマティックアダプテーションは不要です。

ProPhoto RGB空間は、物理的に実現不可能な超高彩度の主色を使っています。 これは広い色域と、特にトーン操作時の色相シフトを最小にするために選ばれました。 デジタル写真でアーカイブ用の広色域色空間としてよく用いられます。prophoto-rgb色空間により、CSSで同じRGB値を持つ画像の色に一致する色を指定できます。

ProPhoto RGBは元々Kodakが開発し、 [Wolfe]に記載されています。 ISOで[ROMM],[ROMM-RGB]として標準化されました。

白輝度は範囲で示され、 視聴フレア(黒輝度)はその0.5%~1.0%です。

特徴は次の通りです:

x y
赤色度 0.734699 0.265301
緑色度 0.159597 0.840403
青色度 0.036598 0.000105
白色度 D50
伝達関数 下記参照
白輝度 160.0~640.0 cd/m2
黒輝度 本文参照
画像状態 display-referred(ディスプレイ基準)
パーセンテージ R, G, Bで使用可能
パーセント参照範囲 R,G,B: 0% = 0.0, 100% = 1.0
const E = 16/512;
let sign = c < 0? -1 : 1;
let abs = Math.abs(c);

if (abs <= E) {
  cl =  c / 16;
}
else {
  cl = sign * Math.pow(c, 1.8);
}
cはガンマエンコードされたR, G, B成分です。 clは対応する線形光成分です。
Oklch における prophoto の原色と二次色の図
Oklch における prophoto-rgb 色空間の視覚化。原色と二次色が 示されています (ただし、正しい色ではなく sRGB で表示されています)。 比較のため、sRGB の原色と二次色も 破線の円で示されています。 prophoto-rgb の原色と二次色ははるかに高いクロマを持ちますが、 この超広色域の大部分は 物理的に実現可能な色には対応していません。

10.8. 定義済みITU-R BT.2020-2色空間:rec2020 キーワード

rec2020
rec2020 [Rec.2020] 色空間は3つの数値パラメータを受け付けます。 それぞれ、色の赤・緑・青成分を表します。 ガマット内の色は3成分すべてが[0, 1]の範囲です (映像用語では「フルレンジ」)。 ITU Reference 2020は 超高精細(UHD)、4Kおよび8Kテレビに使われています。

主色点は物理的に実現可能ですが、 スペクトル軌跡付近に非常に近いため 実現は難しいです。

現時点のディスプレイではrec2020の全ガマットを再現することはできません。 ディスプレイの性能向上に伴い、カバレッジが徐々に広がっていくと予想されます。

特性は以下の通りです:

x y
赤の色度 0.708 0.292
緑の色度 0.170 0.797
青の色度 0.131 0.046
白の色度 D65
伝達関数 ガンマ2.40 ([REC_BT.1886]より)
画像状態 ディスプレイ参照
パーセンテージ R, G, B に対し許可
パーセント基準範囲 R, G, Bについて: 0% = 0.0, 100% = 1.0
Oklch における rec2020 の原色と二次色の図
Oklch における rec2020 色空間の視覚化。原色と二次色が 示されています (ただし、正しい色ではなく sRGB で表示されています)。 比較のため、sRGB の原色と二次色も 破線の円で示されています。 rec2020 の原色ははるかに高いクロマを持ちます。

10.9. 定義済みCIE XYZ色空間:xyz-d50、xyz-d65、 xyz キーワード

xyz-d50、xyz-d65、xyz
xyz 色空間は3つの数値パラメータを受け取り、 X,Y,Z値を表します。 これはCIE XYZ[COLORIMETRY]色空間を表し、 拡散白が輝度(Y)1.0となるようスケールされます。 必要に応じて、参照白に対してクロマティックアダプテーションされます。

xyz-d50の参照白はD50、 xyz-d65およびxyzの参照白はD65です。

1.0/100%を超える値も許容され、丸めてはなりません。 Yが1.0を超える色は拡散白より明るい色を表します。 0/0%未満の値はまれですが、クロマティックアダプテーションの結果として現れることがあり、同様に丸めてはなりません。

特徴は次の通りです:

パーセンテージ X,Y,Zで使用可能
パーセント参照範囲 X,Y,Z: 0% = 0.0, 100% = 1.0
これらは完全に同等です:
 #7654CD
 rgb(46.27% 32.94% 80.39%)
 lab(44.36% 36.05 -58.99)
 color(xyz-d50 0.2005 0.14089 0.4472)
 color(xyz-d65 0.21661 0.14602 0.59452)
これらの色は完全に同等で、白を表します:
 #FFFFFF
 color(xyz-d50 0.9643 1 0.8251)
 color(xyz-d65 0.9505 1 1.089)

10.10. 定義済み色空間からLabやOklabへの変換

すべての定義済みRGB色空間について、 Labへの変換には複数ステップが必要ですが、実際は最初以外のステップは線形計算でまとめられます。

  1. ガンマ符号化されたRGBから線形ライトRGBへ変換(ガンマ符号化を解除)
  2. 線形RGBからCIE XYZへ変換
  3. 必要があれば、D65ホワイトポイント (sRGB、display-p3、a98-rgb およびrec2020で使用) をLabに使われるD50ホワイトポイントに変換。 線形Bradford変換を用いる。prophoto-rgbは すでにD50ホワイトポイント。
  4. D50適応XYZからLabに変換

Oklabへの変換も似ていますが、 色順応ステップはprophoto-rgbでのみ必要です。

  1. ガンマ符号化されたRGBから線形ライトRGBへ変換(ガンマ符号化を解除)
  2. 線形RGBからCIE XYZへ変換
  3. 必要があれば、D50ホワイトポイント (prophoto-rgbで使用) をOklabで使われているD65ホワイトポイントに変換。 線形Bradford変換を用いる。
  4. D65適応XYZからOklabに変換

これら変換のサンプルJavaScriptコードは § 19 色変換のサンプルコードにあります。

10.11. LabやOklabから定義済みRGB色空間への変換

Labからdisplay-p3やrec2020などの定義済み空間への変換も 複数ステップが必要で、実際は最後以外のステップは線形計算でまとめられます。

  1. Labを(D50適応済み)XYZへ変換
  2. 必要ならLabが使うD50ホワイトポイントを D65ホワイトポイント(sRGBやほとんどのRGB空間で使用)に 線形Bradford変換で合わせる。prophoto-rgbは不要。
  3. (D65適応済み)CIE XYZから線形RGBへ変換
  4. 線形光RGBからRGBへ変換(ガンマエンコード)

Oklabからの変換も同様ですが、 クロマティックアダプテーションは prophoto-rgbのみ必要です。

  1. Oklabを(D65適応済み)XYZへ変換
  2. 必要ならOklabが使うD65ホワイトポイントを D50ホワイトポイント(prophoto-rgbで使用)に 線形Bradford変換で合わせる。
  3. (D65適応済み)CIE XYZから線形RGBへ変換
  4. 線形光RGBからRGBへ変換(ガンマエンコード)

これら変換のサンプルJavaScriptコードは § 19 色変換のサンプルコードにあります。

実装はこの手順以外の方法(ICCプロファイルの相対的色域レンダリングなど)でも、 ソース・宛先ガマット内の色で結果が一致する限り選択可能です。

10.12. 定義済みRGB色空間間の変換

定義済みRGB色空間間の変換も 複数ステップが必要で、 ホワイトポイントが異なる場合のみ必要なステップがあります。 srcからdestに変換する場合:

  1. ガンマエンコード済みsrcRGBから線形光srcRGBへ変換(ガンマ解除)
  2. 線形srcRGBからCIE XYZへ変換
  3. srcとdestでホワイトポイントが異なる場合、 XYZ値をsrcWhiteからdestWhiteへ 線形Bradford変換で合わせる。
  4. CIE XYZから線形destRGBへ変換
  5. 線形光destRGBからdestRGBへ変換(ガンマエンコード)

これら定義済みRGB色空間の変換サンプルJavaScriptコードは § 19 色変換のサンプルコードにあります。

10.13. シンプルなアルファ合成

描画時、実装は Compositing Level 1 §5.1 シンプルなアルファ合成([Compositing])の規則に従ってアルファを扱わなければなりません。

11. 色変換

11.1. 色の変換の概要

色は、 ある色空間から別の色空間へ変換でき、 色域マッピングが行われず、 かつ各色空間が色域外の色を表現できる場合、 (RGB 色空間では、これは伝達関数が拡張範囲全体にわたって定義されていることを意味する) (数値精度と丸め誤差の影響を受けるものの) 2 つの色は同じように見え、同じ色感覚を表す。

たとえば、以下の異なる構文形式はすべて同じ色である:

歴史的な理由により、解析時には、 一部の従来の色 構文による色はクランプされる。 しかし一般に、そのようなクランプは望ましくない。 これはラウンドトリップを妨げ、 複数回の色変換を通じて誤差が累積するためである。

したがって、色変換の結果はクランプされないため、 色域外の色や、 実際には存在しない色、 たとえばスペクトル軌跡の外側の色、 さらには明度が負の色や 明度が許容される最大値を超える色が生じる場合がある。

たとえば、以下はすべて同じ色だが、rec2020 の色域さえ外れている (表示のためスウォッチには sRGB への色域マッピングが行われているが、値自体には行われていない):
たとえば、色順応により、 この XYZ 色を D50 Lab に順応させた場合、 明度値は 100 よりわずかに大きくなる:

11.2. 色を変換するためのアルゴリズム

色 col1 を変換のために準備するには:
  1. src 内の無力な成分をすべて欠落成分に変更する
  2. src が円筒極座標色表現である場合、 col1 を 対応する直交直交座標色表現に変換し、 これを新しい col1 とする。
ソース色空間 src にある色 col1 を ホワイトポイント src-white とともに、 宛先色空間 dest にある色 col2 へ ホワイトポイント dest-white とともに色を変換するには、 src と dest が異なるものとする:
  1. col1 を変換のために準備する
  2. すべての欠落成分をゼロに置き換える。
  3. src が 線形光表現でない場合、 線形光に変換し(ガンマ符号化を元に戻し)、 これを新しい col1 とする。
  4. col1 を、指定された ホワイトポイント src-white を持つ CIE XYZ に変換し、 これを xyz とする。
  5. dest-white が src-white と同じでない場合、 線形 Bradford 色順応変換を使用して xyz を dest-white に色順応させ、 これを新しい xyz とする。
  6. dest が円筒極座標色表現である場合、 dest-rect を対応する直交 直交座標色表現とする。 そうでない場合、dest-rect を dest とする。
  7. xyz を dest に変換し、 続いて任意の伝達関数(ガンマ符号化)を適用して、 col2 を生成する。
  8. dest が ディスプレイなどの物理出力色空間である場合、 col2 はCSS 色域マッピングされなければならず、 それにより表示 可能になる。
  9. dest-rect が dest と同じでない場合、 言い換えると dest が円筒極座標色表現である場合、 dest-rect から dest に変換し、これを col2 とする。 これにより欠落成分が生じる場合がある。

12. <color>値の比較

二つの<color>値は、下記のアルゴリズムで等しいと判定された場合等価色とみなす。 この比較は例えば style()コンテナクエリ [CSS-CONDITIONAL-5] や CSS Transitions [CSS-TRANSITIONS-1] で色値の変化を判断するのに使われる。

二つの<color>値 C1 と C2 については、 下記アルゴリズムが true を返す場合に限り 等価色とする:

  1. C1 と C2 のそれぞれについて、 すべての無力な成分を欠落成分に変換します。
  2. C1 と C2 が同じ<color-space>を共有する場合:
    1. アルファチャンネルを含め、 それぞれの成分を1つずつ比較します。 欠落成分は、 別の欠落成分とのみ等しくなります。 2つの数値成分は、その差が小さな 実装定義の ε 以下である場合、 等しいとみなされます。
    2. すべての成分が等しいと比較された場合に限り、 true を返します。
  3. それ以外の場合、C1 と C2 は異なる<color-space>にあります。 いずれかの色に少なくとも1つの欠落成分がある場合、 false を返します。
  4. それ以外の場合、どちらの色にも欠落成分はありません。 C1 と C2 の両方をoklabに変換し、 変換された色のすべての成分(アルファを含む)が 等しいと比較された場合に限り true を返します。 標準化された Oklab の ε 0.00001 を使用します。

注: 異なる構文形式で表現され、 同じ <color-space> に属する2つの色が、 測色的に同一である場合—例えば、 red と color(srgb 1 0 0)—これらは、このアルゴリズムのステップ2により等価な色である。

注: 異なる <color-space> で表現された2つの色が、 測色的に同一である場合—例えば、 red と color(display-p3 0.91748756 0.20028681 0.13856059)—これらは、このアルゴリズムのステップ4により等価な色である。 これは、同じ oklab 値に変換されるためである。

この比較においてrgb(), rgba(), hsl(), hsla(), hwb(), hexカラー, 名前付き色, システム色は すべてsrgbの <color-space>とみなす。

red と rgb(255, 0, 0) は等価な色である。 両方とも srgb <color-space> に属するため、 ステップ2では、それらの赤、緑、青 およびアルファ成分を比較し、これらはすべて等しい。
red と color(srgb 1 0 0) は等価な色である。 名前付き色は、 srgb <color-space> に属するとみなされ、 これは、この color() 値の <color-space> でもあるため、 ステップ2で2つの色は成分ごとに比較される。
#ff000080 と rgb(255 0 0 / 50%) は、見分けるのが困難ではあるが、等しいものではなく、等価な色ではない。 アルファチャネルは他の成分と同様に比較され、 128 / 255 = 0.50196… であり、これは 0.5 とは 小さな ε を超えて異なる。
hsl(0 0% 50%) と hsl(200 0% 50%) は、2つの経路のいずれによっても等価な色である。 それらの彩度は 0% なので、ステップ1で それぞれの色相は欠落成分になり、 欠落成分は別の欠落成分と等しい。 これとは独立して、hsl() は srgb <color-space> に属するとみなされ、 そこでは色相は、比較される成分の1つではまったくない。
white と hwb(120 100% 0%) は等価な色である。 白色度と黒色度の合計は 100 なので、 色相は無力であり、ステップ1で欠落になる。 また、hwb() は srgb <color-space> に属するとみなされるため、 両方の色は 100% の R、G、B として比較される。
oklch(50% 0 40) と oklch(50% 0 200) は等価な色である。 彩度はゼロなので、それぞれの色相は無力であり、 ステップ1で欠落になり、 すべての成分が等しいと比較される2つの色が残る。
lch(50% 0.001 30) と lch(50% 0.001 200) は、彩度が正確にゼロではなく 色相が 170 度離れているにもかかわらず、等価な色である。 0.001 の彩度は、lch() が 無力な色相について定義する 0.0015 の ε の範囲内であるため、 ステップ1で両方の色相は欠落になり、 両方の彩度がゼロに設定される。
lch(50% 30 0) と lch(50% 30 360) は等価な 色であるが、 これは、このアルゴリズムが行う処理によるものではない。 <hue> は解析時に範囲 [0, 360) に正規化されるため、 2つが比較される時点では 両方の色相成分は 0 である。
rgb(none 128 0) と rgb(0 128 0) は、同じように描画されるものの、等しいものではなく、等価な色ではない。 これは、色が表示されるとき、欠落成分がゼロとして動作するためである。 この比較の目的では、欠落成分は 別の欠落成分とのみ等しく、 値がたまたまゼロである成分とは決して等しくない。
oklch(50% 0 none) と oklab(50% 0 0) は、測色的には同一であるにもかかわらず、等しいものではなく、等価な色ではない。 これらは異なる <color-space> に属し、 1つ目には欠落成分があるため、 ステップ3は false を返し、 成分値は一切比較されない。
red と color(srgb-linear 1 0 0) は等価な 色である。 これらは異なる <color-space> に属し、 どちらにも欠落成分がないため、 ステップ4では両方を oklab に変換し、 そこで同じ値になる。
color(display-p3 1 1 1) と white は等価な 色である。 ステップ4でそれぞれを oklab に変換すると、 成分差は 10-16 程度になる。 そのため、このステップでは完全な等値性ではなく ε を使用して比較する。
lab(50% 0 0) と oklab(0.5 0 0) は等価な色ではない。 両方とも明度 50% の無彩色であるが、 2つの明度尺度は同じではない。 ステップ4で oklab に変換すると、 それらの明度成分は 0.56897 と 0.5 であり、 標準化された ε をはるかに超えて異なる。

13. 色補間

色の補間は グラデーション、 合成、 フィルター、 トランジション、 アニメーション、 そして 色混合および色修正関数で発生します。

二つの<color>値の間の補間は、 以下の手順を実行することで行われます:

  1. 2つの色について対応する成分 および対応する集合を確認する。 これらは引き 継がれる
  2. (変換が必要な場合)無力な成分を欠落値に変更する
  3. (必要な場合)両方を所定の色空間に変換する。 この色空間は以下で補間色空間と呼ぶ。
  4. (必要な場合)変換された色に引き継がれた値を再挿入する
  5. 欠落している成分を、もう一方の色の成分値で埋める
  6. (必要な場合)選択された <hue-interpolation-method> に応じて色相を調整する
  7. 色成分を事前乗算済み形式に変更する
  8. 色の算出値の各成分を個別に線形補間する
  9. 事前乗算を元に戻す

currentcolor への、またはそこからの補間が可能です。 この目的で使用される数値は使用値です。

13.1. 成分ごとの線形補間

各色成分が最終結果にどの程度寄与するかを概念化する方法は2つあります。 色量と色進行度です。 どちらも同じ結果を与えます。単に異なる思考モデルです。

例えば、2つの色の明度成分 La と Lb を混合する場合、 自然な思考モデルは量の組です。 La を70%、Lb を30%使用したいと考えます。
例えば、色の明度成分を 開始値 La から 終了値 Lb までアニメーションする場合、 自然な思考モデルは単一の進行値です。 これはアニメーションの開始時に0%、 アニメーションの終了時に100%となります。 進行度が0%の場合、補間された成分は La の100%と Lb の0%に等しく、 進行度が100%の場合、補間された成分は La の0%と Lb の100%に等しくなります。 したがって、進行度が30%の場合、 補間された成分は La の70%と Lb の30%に等しくなります。
色量
合計が100%になるよう正規化された割合の組 Qa と Qb、 および色成分値の組 Ca と Cb が与えられた場合、 補間結果は (Ca × Qa) + ( Cb × Qb) です。
色進行度
割合の進行度 P および開始成分値と終了成分値 Cs と Ce が与えられた場合、 補間結果は (Cs × (1 - P) + Ce × P) です。

したがって、あるモデルから別のモデルへ変換する場合、進行度は2番目の色の量です。

13.2. 補間のための色空間

CSS のさまざまな機能は色の補間に依存しています。

例には次のものがあります。

補間するには、色が同じ色空間に存在する(または同じ色空間に変換される)必要があります。

色の混合やその他の方法による結合は、 使用する補間色空間に応じて異なる結果になります。 したがって、補間の用途ごとに異なる色空間がより適切な場合があります。

これらの機能を総称してホスト構文と呼びます。

ホスト構文が補間色空間を指定できるようにするため、 この仕様では color-interpolation-method 生成規則を公開します。 これはこの仕様自体では使用されず、 他の仕様が使用できるよう公開されているだけです。 例えば、CSS Images 4 § 3.1 線形 グラデーション:linear-gradient() 記法での使用を参照してください。

ホスト構文は、 各場合におけるデフォルトの補間色空間を定義するべきであり、 できれば作者がこのデフォルトを上書きするための構文も提供するべきです。 そのような構文がプロパティ値の一部である場合、 他の仕様から容易に参照できるよう以下で定義する color-interpolation-method 生成規則を使用するべきです。 これにより CSS 全体での一貫性が確保され、 色補間の実行方法に対する今後のカスタマイズも CSS 全体へ自動的に波及できるようになります。

<color-space> = <rectangular-color-space> | <polar-color-space>
<rectangular-color-space> = srgb | srgb-linear | display-p3 | display-p3-linear | a98-rgb | prophoto-rgb | rec2020 | lab | oklab | <xyz-space>
<polar-color-space> = hsl | hwb | lch | oklch
<hue-interpolation-method> = [ shorter | longer | increasing | decreasing ] hue
<color-interpolation-method> = in [ <rectangular-color-space> | <polar-color-space> <hue-interpolation-method>? ]

<rectangular-color-space> および<polar-color-space> の定義に含まれるキーワードは、 それぞれ対応する色空間を参照します。 CSS では、同じ名前の関数構文、 または(そのような関数が存在しない場合)、 color() 関数内の対応する<ident> によって 表されます。

ホスト構文が補間を どの色空間で行うかを定義していない場合、 デフォルトは Oklab です。

<polar-color-space> について、 <hue-interpolation-method> が指定されていない場合、 デフォルトはshorter です。

ただし、ユーザーエージェントは、 従来の sRGB 色形式 (16進色、名前付き色、 rgb()、hsl()、またはhwb() およびアルファを含む同等形式) 間の補間を、ガンマエンコードされた sRGB 空間で処理しなければなりません。 これにより Web 互換性が提供され、 従来の sRGB コンテンツはデフォルトで sRGB 空間内で補間されます。

これはまた、作者が、 sRGB 色同士であっても、 少なくとも一方の色に非従来形式の color(srgb r g b) を使用するか、 または補間色空間を明示的に指定することで、 より良い補間を選択できることも意味します。

補間する色が 補間色空間の色域外にある場合、 その空間に変換されると、 範囲外の値が含まれることになります。

これらはクリップされません。値はそのまま補間されなければなりません。

13.3. 欠落した成分を含む補間

2つの色を 補間色空間に変換する過程で、 欠落 成分は 値 0 に置き換えられる。

したがって、2つの色を補間する最初の段階は、 入力色内の欠落成分を分類し、 それらを 補間色空間の成分と比較することである。 欠落成分である対応する 成分が見つかった場合、 それらは引き継がれ、 変換された色に再挿入される。 これは事前乗算の前、かつ 線形補間が行われる前に行われる。

同様に、元の色における 対応する集合 (以下で定義)のすべての成分が 欠落 成分である場合、 それらはすべて引き 継がれ、 補間色空間の 対応する対応する集合に 再挿入される。

アルファはそれ自体が対応する成分であり (アルファはアルファに対応する)、 欠落アルファは、 他の欠落成分と まったく同じ方法で 引き継がれる。

対応する 成分は次のとおりである。

カテゴリ 成分
赤 r,x
緑 g,y
青 b,z
明度 L
色鮮やかさ C, S
色相 H
反対色 a a
反対色 b b
アルファ alpha

注: この分類の目的では、 XYZ 空間は超高彩度の RGB 空間とみなされる。 また、彩度は明度に依存するにもかかわらず、 ここではクロマと同じカテゴリに属する。 HWB の白色度および黒色度成分には、 他の色空間に対応するものはない。

さらに、任意の2つの色空間について、 すべての対応する成分を取り除いた後に 残る成分は、 成分の対応する集合を 形成する。

注: 個別の対応する成分が存在しない場合に 残る対応する集合は すべての色成分の完全な集合であるため、 すべての色成分が欠落している色は、 補間色空間でも すべての色成分が欠落する。

補間のために lab(50% none none) を LCH に変換する場合、 明度は個別に対応する。 残りの成分 (Lab の a および b、LCH の C および H)は 対応する集合を形成する。 a と b は両方とも欠落しているため、 C と H は両方とも欠落として引き継がれ、 lch(50% 0 0) ではなく lch(50% none none) となる。

同様に、 rgb(none none none / 50%) を補間のために OKLab に変換すると、 oklab(none none none / 50%) となる。 これは、3つの色成分が 対応する集合を形成するためである (sRGB と OKLab の間には個別の対応する成分は存在しない)。

例えば、これら2つの色を OkLCh で補間する場合、 CIE LCH 色の欠落している色相は OkLCh の色相成分に対応するため 引き継がれるが、 2番目の色で欠落している青成分は どの OkLCh 成分にも対応しないため 引き継がれない。
 lch(50% 0.02 none)
 color(display-p3 0.7 0.5 none)

これらを変換すると

 oklch(56.897% 0.0001 0)
 oklch(63.612% 0.1522 78.748)

となり、引き継がれた欠落成分を再挿入すると、 補間される2つの色は次のようになる。

 oklch(56.897% 0.0001 none)
 oklch(63.612% 0.1522 78.748)

引き継がれた欠落成分を持つ色を、 その成分が欠落していない 別の色と 補間する場合、 欠落成分は もう一方の色の成分値を 持つものとして扱われる。

したがって、 引き継がれる成分の特定は、 無力な 成分の処理よりも前に行わなければならない。 これは、その値がゼロに変換されることを防ぐためである。

例えば、次の2つの色を補間し、 そのうち2番目の色で色相が欠落している場合、
 oklch(78.3% 0.108 326.5)
 oklch(39.2% 0.4 none)

実際に補間される色は次のとおりとなる。

 oklch(78.3% 0.108 326.5)
 oklch(39.2% 0.4 326.5)

次のようにはならない。

 oklch(78.3% 0.108 326.5)
 oklch(39.2% 0.4 0)

引き継がれた欠落成分が アルファである場合、その色は、色変換によって得られるはずだった ゼロ値ではなく、この引き継がれた値を使用して事前乗算しなければならない。

例えば、次の2つの色を補間し、 そのうち2番目の色でアルファが欠落している場合、
 oklch(0.783 0.108 326.5 / 0.5)
 oklch(0.392 0.4 0 / none)

実際に補間される色は次のとおりとなる。

 oklch(78.3% 0.108 326.5 / 0.5)
 oklch(39.2% 0.4 0 / 0.5)

これにより、事前乗算済みの OkLCh 値 [0.3915, 0.054, 326] および [0.196, 0.2, 0] が得られる。

両方の色で所定の成分が欠落している場合、 補間された色でも その成分は欠落する。

13.4. アルファを含む補間

補間する色が完全に不透明でない場合、 最初に次のように事前乗算されます。

事前乗算された色値から色値を得るには、

事前乗算アルファはなぜ有用なのか?

事前乗算された表現を使用して色を補間すると、 事前乗算されていない表現よりも魅力的な遷移が得られる傾向があります。 特に、完全に不透明な色から完全に透明な色へ遷移する場合に顕著です。

透明度または色のいずれかが一定に保たれる遷移 (例えば、rgba(255, 0, 0, 100%) (不透明な赤) と rgba(0,0,255,100%) (不透明な青)の間の遷移、 または rgba(255,0,0,100%) (不透明な赤) と rgba(255,0,0,0%) (透明な赤)の間の遷移) では、色補間が事前乗算色空間で行われるか、事前乗算されていない 色空間で行われるかにかかわらず、同一の結果になります。 違いが生じるのは、2つの端点間で色と透明度の両方が異なる場合だけです。

次の例は、 事前乗算された値を介して遷移するグラデーション (この場合、関係するすべての色が従来色であるため sRGB) と、事前乗算されていない値を介して(誤って)遷移するグラデーションとの差を示しています。 これら両方の例で、 グラデーションは白い背景上に描画されます。 両方のグラデーションは、次の値で記述できます。
linear-gradient(90deg, red, transparent, blue)

事前乗算された色では、 "transparent" への、またはそこからの遷移は常に自然に見えます。

(画像には SVG が必要です)

一方、 グラデーションが誤って事前乗算されていない空間で遷移する場合、 グラデーションの中央は目立って灰色がかった色になります。 これは "transparent" が実際には rgba(0,0,0,0)、すなわち 透明な黒の省略形であり、 赤は不透明度を失うにつれて黒へ遷移し、 青についても同様に遷移するためです。

(画像には SVG が必要です)
例えば、sRGB 色空間で2つの sRGB 色 rgb(24% 12% 98% / 0.4) と rgb(62% 26% 64% / 0.6) を補間するには、補間の前にまず事前乗算形式 [9.6% 4.8% 39.2% ] と [37.2% 15.6% 38.4%] に変換します。

これらの色を線形補間した中点は [23.4% 10.2% 38.8%] となり、アルファ値 0.5 の場合、 事前乗算を解除すると rgb(46.8% 20.4% 77.6% / 0.5) となります。

Lab 色空間で2つの色 rgb(76% 62% 03% / 0.4) と color(display-p3 0.84 0.19 0.72 / 0.6) を補間するには、まずこれらを lab に変換します。 lab(66.927% 4.873 68.622 / 0.4) lab(53.503% 82.672 -33.901 / 0.6) 次に、補間の前に L、a、b 座標を事前乗算します。 [26.771% 1.949 27.449] と [32.102% 49.603 -20.341]。

これらを線形補間した中点は [29.4365% 25.776 3.554] となり、アルファ値 0.5 の場合、 事前乗算を解除すると lab(58.873% 51.552 7.108) / 0.5) となります。

クロマを保持する LCH 色空間で、同じ2つの色 rgb(76% 62% 03% / 0.4) と color(display-p3 0.84 0.19 0.72 / 0.6) を補間するには、まずこれらを LCH に変換します。 lch(66.93% 68.79 85.94 / 0.4) lch(53.5% 89.35 337.7 / 0.6) 次に、補間の前に L と C 座標(H は除く)を事前乗算します。 [26.771% 27.516 85.94] と [32.102% 53.61 337.7]。

shorter 色相弧(デフォルト)に沿って これらを線形補間した中点は [29.4365% 40.563 31.82] となり、アルファ値 0.5 の場合、 事前乗算を解除すると lch(58.873% 81.126 31.82) / 0.5) となります。

極座標色空間と直交座標色空間の両方について、 アルファの事前乗算および事前乗算解除を行うサンプル JavaScript コードが、 § 19 色変換のサンプルコードにあります。

13.5. 色相の補間

色相角を持つ色関数(LCH、HSL、HWB など)には、複数の補間方法があります。 360° を超える弧が望まれることはほとんどないため、 色相角は補間前に調整され、 成分ごとの補間が360°未満、多くの場合180°未満で行われるようにします。

ホスト構文は、色相補間について以下のいずれかのアルゴリズムを指定できます (以下の角度は度単位ですが、指定方法に関係なくロジックは同じです)。 色相補間戦略の指定は、すでに<color-interpolation-method> 構文の一部であり、 <hue-interpolation-method> トークンを介して行われます。

別途指定されない限り、ホスト構文によって特定の色相補間アルゴリズムが選択されていない場合、 デフォルトは shorter です。

注: 念のため、 補間される色が指定された補間色空間にすでに属していない場合、 それらを変換すると、すべての無力な成分が欠落成分になる。

13.5.1. shorter

色相角は、開始色相と終了色相の間にある2つの弧のうち 短い方を通るように補間されます。

例えば、OkLCh で赤 oklch(0.6 0.24 30) から黄色 oklch(0.8 0.15 90) まで補間する場合、中点の色相角は 30 + (90 - 30) * 0.5 = 60 度となり、 2つの色の間の短い方の弧に沿って、 濃いオレンジ oklch(0.7 0.195 60) になります。

角度は θ₂ - θ₁ ∈ [-180, 180] となるよう調整されます。擬似 JavaScript では次のようになります。

if (θ₂ - θ₁ > 180) {
  θ₁ += 360;
}
else if (θ₂ - θ₁ < -180) {
  θ₂ += 360;
}

13.5.2. longer

色相角は、開始色相と終了色相の間にある2つの弧のうち 長い方を通るように補間されます。

例えば、OkLCh で赤 oklch(0.6 0.24 30) から黄色 oklch(0.8 0.15 90) まで補間する場合、中点の色相角は (30 + 360 + 90) * 0.5 = 240 度となり、 2つの色の間の長い方の弧に沿って、 空色 oklch(0.7 0.195 240) になります。

角度は θ₂ - θ₁ ∈ {(-360, -180], [180, 360)} となるよう調整されます。擬似 JavaScript では次のようになります。

if (0 < θ₂ - θ₁ < 180) {
  θ₁ += 360;
}
else if (-180 < θ₂ - θ₁ <= 0) {
  θ₂ += 360;
}

13.5.3. increasing

色相角は、 最初の色から2番目の色へ進むにつれて、 角度が常に増加するように補間されます。 角度が360まで増加するとゼロにリセットされ、 その後も増加し続けます。

2つの角度の差に応じて、 これは shorter または longer と同じ見た目になります。 ただし、一方の色相角がアニメーションされ、 色相角の差が180度を通過しても、 補間がもう一方の弧へ切り替わることはありません。

例えば、OkLCh で濃い茶色 oklch(0.5 0.1 30) からターコイズ oklch(0.7 0.1 190) まで補間する場合、中点の色相角は (30 + 190) * 0.5 = 110 度となり、 カーキ色 oklch(0.6 0.1 110) になります。

ただし、2番目の色の色相が oklch(0.7 0.1 230) までアニメーションされる場合、 補間の中点は (30 + 230) * 0.5 = 130 度となり、 同じ増加方向に進み続け、 別の緑色 oklch(0.6 0.1 130) となり、アニメーションの途中で反対側の色の領域へ切り替わることはありません。

角度は θ₂ - θ₁ ∈ [0, 360) となるよう調整されます。擬似 JavaScript では次のようになります。

if (θ₂ < θ₁) {
  θ₂ += 360;
}

13.5.4. decreasing

色相角は、 最初の色から2番目の色へ進むにつれて、 角度が常に減少するように補間されます。 角度が0まで減少すると360にリセットされ、 その後も減少し続けます。

2つの角度の差に応じて、 これは shorter または longer と同じ見た目になります。 ただし、一方の色相角がアニメーションされ、 色相角の差が180度を通過しても、 補間がもう一方の弧へ切り替わることはありません。

例えば、OkLCh で濃い茶色 oklch(0.5 0.1 30) からターコイズ oklch(0.7 0.1 190) まで補間する場合、中点の色相角は (30 + 360 + 190) * 0.5 = 290 度となり、 紫色 oklch(0.6 0.1 290) になります。

ただし、2番目の色の色相が oklch(0.7 0.1 230) までアニメーションされる場合、 補間の中点は (30 + 360 + 230) * 0.5 = 310 度となり、 同じ減少方向に進み続け、 別の紫色 oklch(0.6 0.1 310) となり、アニメーションの途中で反対側の色の領域へ切り替わることはありません。

角度は θ₂ - θ₁ ∈ (-360, 0] となるよう調整されます。擬似 JavaScript では次のようになります。

if (θ₁ < θ₂) {
  θ₁ += 360;
}

14. ガマットマッピング

14.1. ガマットマッピング入門

注: このセクションは、 文書の他の箇所で説明されている 個別要件の重要な背景を提供します。

このセクションは規定的ではありません

元の色空間の色を 別の色空間(ガマットがより小さい)に変換すると、 一部の色は変換先のガマット外になります。

色の中間計算では、 このガマット外の値が保持されます。 しかし、変換先がディスプレイ機器 (スクリーンやプリンター等)の場合は ガマット外の値はガマット内の色へ変換しなければなりません。

ガマットマッピングは、 見た目の変化ができるだけ目立たないガマット内色を求める処理です。

ガマット外色の中には 現実世界で再現可能な色(物理的に再現できるもの)もありますが、 他は仮想的な色 (スペクトル軌跡の外に位置し、単一波長が100%以上必要となるため) であり、物理的に現実化することはできません。 そのような色は主に 「この色を100倍彩度高くしろ」などの計算から生じます。

たとえば理論上は制限されていませんが、 CIE Labの(a,b)平面は現実の実装で aおよびbが±127範囲に 制限されることが多いです。

その4隅のうち3つは スペクトル軌跡の外にあり、 仮想的な色に相当しています。

±127(a,b)平面の4隅を UCS色度図上に示したもの。 外側の線がスペクトル軌跡です。 大きな三角形がrec2020ガマット、 小さい三角形がsRGBガマットです。

14.1.1. クリッピング

最も簡単で受け入れ難い方法は、 要素値を単純に表示可能な範囲にクリップすることです。

この方法の動機は高速化であるため、 多くの場合、線形ライトへ変換せず ガンマ符号化された値のままクリッピングされます。

この結果、 3つの基本色(RGBディスプレイの場合)の 割合が変わり、 色相がずれます。

例えば、 色color(srgb-linear 0.5 1 3) を考えます。 これは線形ライト色空間なので、 3要素の強度を比較できます。 青色光の量は緑の3倍、 赤は緑の半分です。 赤に対し青色主成分は6倍です。 OkLChでこの色の色相角は265.1°です。

この色を sRGBのガマット内に収めるようクリップすると、 color(srgb-linear 0.5 1 1) になります。 青と緑の光の量は同じです。 OkLChでは色相角が196.1°、 つまり69°の大きな変化が生じます。

色がガマット外に大きく外れていなければ、 クリッピングでも許容できる結果となります。 特に暗い(または負の)値ではその傾向が強いです。

例えば 色color(rec2020 0.54 0.9 0) (oklch(80.72% 0.3296 141.6)です)

p3色空間に変換すると、青成分が負になり ガマット外であることが分かります: color(display-p3 0.3265 0.9165 -0.1262) 線形ライトでは color(display-p3-linear 0.0871 0.8205 -0.0146) です。

ガンマ符号化p3の色をp3のガマットにクリップすると color(display-p3 0.3265 0.9165 0) となり、 線形ライトでは color(display-p3-linear 0.0871 0.8205 0) となります。 比較のため、 oklch(80.79% 0.3221 142.3) です。

これは良い結果です; 色相角や明度の変化はわずかで クロマ(彩度)は予想通り少し減ります。

線形ライトの赤・緑・青の割合で見ると、 赤と緑は同じ値、 青は-1.46%多くなっています。

例えば color(prophoto-rgb 0.2 1.0 0.1) (oklch(85.07% 0.4873 151.4)です)

p3色空間に変換すると、 ガマット外への飛び出しが顕著です: color(display-p3 -0.5782 1.067 -0.2363) 線形ライトでは color(display-p3-linear -0.2937 1.158 -0.0456) です。

ガンマ符号化p3色をp3ガマットにクリップすると color(display-p3 0 1 0) 線形ライトでも color(display-p3-linear 0 1 0) となり (要素値が正確に0または1ならガンマ符号化の影響はありません) 比較のため oklch(84.88% 0.3685 145.6) です。

見た目では悪くなるものの まだ許容できる結果です。 色相の変化が5.8°とやや大きくなります。

線形ライト赤・緑・青の割合で見ると、 赤は57%多く、緑が6.7%少なく、青は23%多いです。

14.1.2. 最も近い色(MINDE)

より良い方法は、 知覚的均一色空間で ガマット内の最も近い色(最小ΔE、MINDE)を探すことです。 この手法の成否は ガマットマッピング色空間の均一性や deltaE関数の予測精度に左右されます。

しかしガマットマッピング時、 色相の変化は特に好ましくありません。 クロマの変化はまだ受け入れやすく、 明度の小さな変化も許容範囲です (クロマ減少が大きくなる場合は特に)。 MINDEは各次元の変化を均等に重み付けするため、 最適な結果にはなりません。

14.1.3. クロマ減少

MINDEを実装するには、 色を知覚的均一性を持つ極座標色空間で 色相を固定し、 クロマを減らしてガマット内に収めます。

これはアルゴリズム的に、 一定の明度・色相で引いた線と ガマット境界との幾何学的交点を見つける方法でも、 反復的にクロマを減らして ガマット内になるまで繰り返す方法でも実現可能です。

注: 性能向上のため、 反復処理は一般に二分探索で行われます。

この例ではDisplay P3の主黄色 (color(display-p3 1 1 0)) をsRGBディスプレイにマッピングしています。 ガマットマッピング色空間はOkLChです。
color(display-p3 1 1 0)
は
color(srgb 1 1 -0.3463)
であり、さらに
color(oklch 0.96476 0.24503 110.23)

となります。

クロマ成分を徐々に減らし sRGBガマット内(いずれの要素値も負でも1より大きくもない)になるまで 繰り返すことでガマットマッピングされた色が得られます。

   color(oklch 0.96476 0.21094 110.23)
これは
   color(srgb 0.99116 0.99733 0.00001)
OkLCh色空間における一定色相の断面。 垂直軸は明度、 水平軸はクロマです。 マッピング対象色(黄色の円)は 色相・明度を保ったままクロマを減らします。 図のえんじ色の線に沿い、 左側の中性軸方向へ動きます。 sRGBガマット境界は緑で示されています。

14.1.4. 過度なクロマ減少

さらに、この簡易なMINDE手法は、 特定の色、主に非常に明るい色(黄色やシアン等)においては ガマット境界の上端が浅かったり、わずかに凹状の場合、 最適とは言えない結果になります。 一定の明度の直線がガマット境界すれすれを通ることで そのようなケースではクロマが過度に低くなることがあります。

どの色空間を選ぶかによって、ガマットマッピング後の色の許容度が異なります。

この例では、Display P3の主黄色(color(display-p3 1 1 0) のクロマをCIE LCH色空間で順次減らします。
図の上部では、 sRGBのガマット内の色はそのまま表示されます。 Display P3のガマット内(sRGB外)の色はサーモン色です。 Display P3ガマット外の色は赤です。 図の下部ではDisplay P3赤・緑・青成分の 線形ライト強度を示しています。
CIE LCHのクロマを減らすと、赤の強度がカーブして Display P3ガマットを逸脱することが見て取れます。 再び強度が落ちる時点ではクロマが非常に低くなっています。 CIE LCHでの単純なガマットマッピングでは 満足できる結果になりません。
この例では、Display P3の主黄色(color(display-p3 1 1 0) のクロマを今回はOkLCh色空間で順次減らします。
図の上部では、 sRGBのガマット内の色はそのまま表示されます。 Display P3のガマット内(sRGB外)の色はサーモン色です。 Display P3ガマット外の色は赤です。 図の下部ではDisplay P3赤・緑・青成分の 線形ライト強度を示しています。
OkLChのクロマを減らす場合は、 より素直な挙動をします。 色がDisplay P3のガマット外にはみ出すことなく、 マッピングされた黄色も良好なクロマ値となります。 OK LCHでの単純なガマットマッピングなら 許容できる結果になります。

14.1.5. 局所クリップ付きクロマ減少

単純なクロマ減少アルゴリズムの改良として: 各ステップで、現在のマッピング色と そのクリップ版の色との差を計算します。 現在の色がガマット外でも、 クリップ版との色差が知覚できる差(JND)の閾値未満なら、 クリップ版色をマッピング結果として返します。 実質的には各段階でMINDEマッピングしますが、 色相・明度変化は極めて小さく、 知覚できません。

例:Display P3主黄色 (color(display-p3 1 1 0) をCIE LCH色空間でクロマ減少&局所クリップする場合。
上側ではsRGBガマット内色はそのまま表示。 Display P3ガマット内(sRGB外)はサーモン色。 Display P3ガマット外は赤。 下側はDisplay P3の赤・緑・青成分の線形光強度を表示。
CIE LCHクロマ減少でも赤成分強度がDisplay P3ガマット外に盛り上がりますが、 以前より少なく、sRGB境界まで速く到達します。 CIE LCH+局所クリップガマットマッピングは許容できる結果となります。
例:Display P3主黄色 (color(display-p3 1 1 0) を今回はOKLCh色空間&局所クリップでクロマ減少する場合。
上側ではsRGBガマット内色はそのまま表示。 Display P3ガマット内(sRGB外)はサーモン色。 Display P3ガマット外は赤。 下側はDisplay P3の赤・緑・青成分の線形光強度を表示。
OKLChクロマ減少は元々良好ですが、 局所クリップ修正でさらに改善されます。 CIE LCH+局所クリップの単純ガマットマッピングは極めて良好な結果となります。

14.1.6. 知覚的均一性からの逸脱:色相カーブ

CIE LCH色空間でガマットマッピングを行う場合、 deltaE2000距離指標を使用しても 色相範囲270°~330°の色では 適切でない(大きな色相ずれが生じる)ことが知られています。

色相角301.37°(sRGB主青に対応)の CIE LCH色空間における一定色相断面。 縦軸は明度、横軸はクロマ。 クロマ25~75では色相が明らかに紫に見え、 100~131ではより青くなります。 この現象は131より先でも続きますが、 sRGBディスプレイでは表示できません。

OkLCh色空間とdeltaEOK距離指標を使えば、 すべての色相角でこの問題が生じません。

色相角264.06°(sRGB主青に対応)の OkLCh色空間における一定色相断面。 縦軸は明度、横軸はクロマ。 この色相では、クロマの値全般で色相が同じに見えます。 (この色相でsRGBの上限値は0.315。) この点より先でも色相は一定に保たれますが、 sRGBの図では示せません。

14.2. CSSガマットマッピング(RGB宛先への)

3つのCSS 色域マッピングアルゴリズムは、 次の色域外にある 標準ダイナミックレンジ(SDR)の CSS 色に 適用されます:

したがって、それらはCSS 色域マッピングされる必要があります。

例えば、Display P3 画面が与えられた場合、 color(display-p3 1.1 0.4 0.2) という色を表示しようとすると、 色域マッピングが発生します。 これは、赤の座標が 0 から 1 の範囲外にあるためです。 色域マッピングにより、類似しているもののクロマがより低い 色、例えば color(display-p3 1 0.473 0.314) が生成されます。
例えば、colorSpace が "display-p3" に設定され、 colorType が "unorm8" に設定された 2d コンテキストが与えられた場合、 oklch(76% 0.27 60) という色を描画しようとすると、 色域マッピングが発生します。 これは、Display P3 に変換すると、 color(display-p3 1.062 0.4954 -0.3115) という値が 1 より大きい赤の座標と負の青の座標を持つためです。 色域マッピングにより、類似しているもののクロマがより低い 色、例えば color(display-p3 1 0.546 0) が生成されます。

実装は、品質と実行時効率のトレードオフに基づいて 3つのアルゴリズムのいずれかを選択してよく、 CSS が色域マッピングの実行を要求するすべての箇所で、 選択したアルゴリズムを使用しなければなりません。

これらはすべて相対測色インテントを実装するため、 出力先の色域内にある色は変更されません。

注: その他の状況、 特に最大黒レベルがゼロより大幅に高い プリンターの色域へのマッピングでは、 それぞれの黒点と白点を整合させる 異なるアルゴリズムが必要となり、 その結果、クロマが低減されるにつれて 非常に明るい色と非常に暗い色では 明度が変化します。

注: これらのアルゴリズムは個別に指定された 色を対象としており、 単独(ページ要素上)または組み合わせて(グラデーションなど)使用されます。 写真画像については、 隣接するピクセル間の関係が重要であり、 細部や質感を保持することが目的であるため、 知覚的レンダリングインテントの方がより適切であり、 その場合、 出力先の色域内にある色も 変更される可能性があります。

3つすべての CSS 色域マッピングアルゴリズムは、 OkLCh 色空間において 明度と色相を一定に保ったクロマ低減を目的としています。

明度軸上で範囲外にある色については、 明度が 1.0 以上の場合、 出力先の色空間における白が返され、 明度が 0.0 以下の場合、 出力先の色空間における黒が返されます。

14.2.1. ローカルMINDEによる二分探索ガマットマッピング

この二分探索アルゴリズムでは、 色差の式としてdeltaEOKを使用します。 local-MINDEの改良も利用されています。 検索の各ステップで、 現在のマッピング済み色と そのクリップ版とのdeltaEOKを計算します。

現在の色がガマット境界の外側であっても、 クリップ版との差が 知覚できる差(JND)の閾値未満であれば クリップ版をマッピング結果として返します。 これにより色相の変化がほとんど目立たず良好な結果が得られ、 凹状ガマット表面付近で過度なクロマの削減も防げますが、 計算負荷は高くなりやすいです。

OkLCh色空間では 1JNDはOkLCh差分で0.02となります。

注: CIE Lab色空間において 明度成分の範囲が0〜100の場合は deltaE2000を使うと 1JNDは2となります。 Oklab および OkLCh での明度範囲は0〜1のため deltaEOKでの1JNDはその100分の1の値となります。

注: 実験や実装比較のため、 ローカルMINDEを用いた二分探索アルゴリズムは Coloraideライブラリ(Python製)[Coloraide-MINDE] およびcolor.jsライブラリ(JavaScript製)[colorjs-MINDE]で利用可能です。

14.2.2. ローカルMINDEによる二分探索ガマットマッピングのサンプル疑似コード

ローカルMINDEによる二分探索ガマットマッピングで 色originを 色空間origin color spaceから 目的色空間destinationのガマット内に収める:
  1. destinationにガマット制限がなければ(XYZ-D65, XYZ-D50, Lab, LCH, Oklab, OkLCh)、 originをdestinationに変換して返す
  2. origin_OkLChをoriginから origin color space経由でOkLCh色空間に変換する
  3. origin_OkLChの明度が100%以上であれば `oklab(1 0 0 / origin.alpha)`をdestinationに変換し、マッピング色として返す
  4. origin_OkLChの明度が0%以下であれば `oklab(0 0 0 / origin.alpha)`をdestinationに変換し、マッピング色として返す
  5. inGamut(color)は、渡された色がdestinationガマット内ならtrueを返す関数。 HSLやHWBの場合は、sRGBガマット内でtrueを返す。
  6. inGamut(origin_OkLCh)がtrueなら origin_OkLChをdestinationに変換して返す
  7. そうでない場合は、delta(one, two)を 色oneとtwoのdeltaEOKを返す関数とする
  8. JNDを0.02とする
  9. epsilonを0.0001とする
  10. clip(color)はcolorをdestinationに変換し、 各成分を基準範囲内にクランプして返す関数
  11. currentにorigin_OkLChをセット
  12. clippedにclip(current)をセット
  13. Eにdelta(clipped, current)をセット
  14. E < JNDの場合
    1. clippedをガマットマッピング色として返す
  15. minを0にセット
  16. maxをorigin_OkLChのOkLChクロマにセット
  17. min_inGamutは「minがまだガマット内かどうか」を示すブールでtrueをセット
  18. max - minがepsilonより大きい間、以下を繰り返す
    1. chromaに(min + max) / 2をセット
    2. currentのクロマ成分をchromaにセット
    3. min_inGamutがtrueで、かつinGamut(current)もtrueなら、 minにchromaをセットし繰り返し継続
    4. それ以外なら以下を実行:
      1. clippedにclip(current)をセット
      2. Eにdelta(clipped, current)をセット
      3. E < JNDなら
        1. (JND - E < epsilon)なら clippedをガマットマッピング色として返す
        2. それ以外の場合
          1. min_inGamutをfalseにセット
          2. minにchromaをセット
      4. そうでなければmaxにchromaをセットし繰り返し継続
  19. clippedをガマットマッピング色として返す

14.2.3. EdgeSeeker ガマットマッピング

EdgeSeekerアルゴリズムは、幾何学的手法とルックアップテーブルベースのアプローチであり、 もともとはAlexey Ardovによって color.js ライブラリ向けに開発された [colorjs-EdgeSeeker]。

任意の色相について、ガマット境界スライスは 曲線の上部区間と直線の下部区間として表され、 その色相における最も高いクロマの点で接続される。

このアルゴリズムを初期化するには、 与えられた対象RGB空間に対して、 各色相スライス上の最も高いクロマのOklch色を含む ルックアップテーブル(LUT)を構築する。 その後、最も近いLUT値同士の線形補間を用いて、 ガマットマッピング対象となる各色の正確な色相に対する 最も高いクロマの色を推定する。

一定明度のレイと ガマット境界との交点を計算する。 これは境界の下部(線形)部分では高速であり、 上部(曲線)部分でもかなり高速である。

これにより良好な結果が得られるが、 その代償としてLUT用のメモリを消費する。

14.2.4. EdgeSeeker ガマットマッピングのサンプル疑似コード

EdgeSeeker アルゴリズムはルックアップテーブル(LUT)に依存し、 これは非虚数の原色を持つ所与の RGB 宛先色空間 (例えば ProPhoto RGB ではない)について一度構築され、 その後、その空間へマッピングされるすべての色の色域マッピングに再利用される。 以下では、LUT がどのように構築され、 その後、個々の色の色域マッピングにどのように使用されるかを説明する。

RGB 宛先色空間 destination について 非虚数の原色を持ち(例えば ProPhoto RGB ではない)、 領域ごとの色相サンプル数 N(例えば 400)が与えられたとき、 EdgeSeeker ルックアップテーブルを構築するには:
  1. cusps と curve をそれぞれ空のリストとする
  2. 6 つの 60deg 色相領域のそれぞれについて (0deg から 60deg、60deg から 120deg、以下同様に 300deg から 360deg まで):
    1. regionCusps と regionCurve をそれぞれ空のリストとする
    2. その領域に等間隔で配置された N 個の色相 h のそれぞれについて、 両端点を含め、昇順で:
      1. r、g、b を、 HSL 三つ組 (h, 100%, 50%) を RGB に変換した結果とする HSL から RGB への変換を使用する
      2. cusp を destination における座標 r、g、 b を持つ色とし、 OkLCh 色空間へ変換する
      3. {l: cusp の明度, c: cusp の彩度, h: cusp の色相} を regionCusps に追加する
      4. r2、g2、b2 を、 HSL 三つ組 (h, 100%, 75%) を RGB に変換した結果とする HSL から RGB への変換を使用する
      5. curvePoint を destination における座標 r2、 g2、b2 を持つ色とし、 OkLCh 色空間へ変換する
      6. {l: curvePoint の明度, c: curvePoint の彩度, h: curvePoint の色相} を regionCurve に追加する
    3. regionCusps および regionCurve から色相の 折り返しを除去する
    4. regionCusps の最後を除くすべてのエントリーを cusps に追加し、 regionCurve の最後を除くすべてのエントリーを curve に追加する
  3. cusps と curve をそれぞれ色相の昇順でソートする
  4. cusps と curve のそれぞれについて:
    1. last を最も色相の高いエントリーとし、 first を最も色相の低いエントリーの色相に 360deg を加えたものとする
    2. end を、その明度と彩度が 色相に基づき last と first の間を線形補間して 色相 360deg で得られるエントリーとする
    3. リストの先頭に、色相 0deg における end の明度と彩度を持つエントリーを追加し、 色相 360deg における end を末尾に追加する
  5. LUT を空のリストとする
  6. cusps 内の各エントリー cusp について:
    1. curvePoint を、その明度と彩度が 色相に基づき線形補間することで得られるエントリーとする。 補間対象は curve 内の 2 つのエントリーであり、 それらの色相が cusp の色相を最も近くから挟むものとする
    2. curvature を、 cusp と curvePoint について 曲率を計算した 結果とする
    3. {l: cusp の l, c: cusp の c, h: cusp の h, curvature: curvature} を LUT に追加する
  7. LUT を返す

注: 色相サンプルの数と、 隣接するエントリーから線形補間できるエントリーを どの程度除去するかは、 事前計算時間、メモリー、精度の間でトレードオフを行う 実装上の選択であり、 アルゴリズムの定義には影響しない。 このような手法の一例については、参照実装 [colorjs-EdgeSeeker] を参照。

サンプリングされた HSL 色相の昇順になっている OkLCh エントリーのリスト samples から 色相の折り返しを除去するには:

エントリーは OkLCh 色相をキーとしているため、 サンプリングされた HSL 色相が単調増加する列であっても、 必ずしも OkLCh 色相が単調増加する列になるとは限らない: 境界がそれ自体へ折り返すことがある。 色相が前進しない各エントリーを単純に破棄すると、 折り返し前のオーバーシュートが残り、その後の良好なエントリーが破棄されるため、 何もしない場合より悪くなる。 代わりにオーバーシュートを除去し、 境界を後退区間の末端から再開する。

ここで、色相 a から色相 b への色相ステップは、 (b − a) modulo 360deg であり、範囲 [0deg, 360deg) にあり、 180deg 以下である場合は前進である。

  1. kept を samples の最初のエントリーを含むリストとする
  2. i を 1 とする
  3. i が samples のエントリー数より小さい間:
    1. samples[i − 1] の色相から samples[i] の色相への色相ステップが前進なら、 samples[i] を kept に追加し、i を i + 1 に設定し、 次の反復へ進む
    2. j を i とする
    3. j が samples の最後のエントリーのインデックスより小さく、 かつ samples[j] の色相から samples[j + 1] の色相への色相ステップが前進でない間、 j を j + 1 に設定する
    4. resume を samples[j] とする
    5. first を、kept 内で最初に、 resume の色相への色相ステップが前進でないエントリーのインデックス、 すなわち resume の色相を越えた最初の保持済みエントリーとする
    6. 表明: そのようなエントリーが存在し、first は少なくとも 1 である
    7. bridge を、色相 resume の色相 − 0.0001deg にあるエントリーとし、 その明度と彩度は、 色相に基づき kept[first − 1] と kept[first] の間を線形補間して得られ、 補間係数は [0, 1] にクランプする
    8. kept[first] およびそれ以降のすべてのエントリーを kept から除去する
    9. kept の最後のエントリーの色相から bridge の色相への色相ステップが 前進かつ 0deg でない場合、bridge を kept に追加する
    10. resume を kept に追加する
    11. i を j + 1 に設定する
  4. samples の内容を kept で置き換える
色相に対して最も彩度が高い点の OkLCh 明度と彩度であるカスプ点 cusp および同じ色相の境界のより明るい部分にある 第 2 の点 curvePoint が与えられたとき、 色域境界区間の 曲率を計算するには:

境界区間を単位正方形に正規化する。 ここで (0, 0) は白であり、 (1, 1) はカスプである。 曲率は、 これら 2 点と、 正規化された curvePoint を通る円の曲率である。

  1. x を (100% − curvePoint の明度) / (100% − cusp の 明度) とする
  2. y を curvePoint の彩度 / cusp の彩度とする
  3. x が y に等しい場合、0 を返す
  4. p1 を点 (0, 0) とする
  5. p2 を点 (x, y) とする
  6. p3 を点 (1, 1) とする
  7. m1 を −1 / ((p2 の y − p1 の y) / (p2 の x − p1 の x))、 すなわち p1 から p2 までの線分の垂直二等分線の傾きとする
  8. m2 を −1 / ((p3 の y − p1 の y) / (p3 の x − p1 の x))、 すなわち p1 から p3 までの線分の垂直二等分線の傾きとする
  9. mid1 を p1 と p2 の中点とする
  10. mid2 を p1 と p3 の中点とする
  11. centerX を (m1 × mid1 の x − m2 × mid2 の x + mid2 の y − mid1 の y) / (m1 − m2) とする
  12. centerY を m1 × (centerX − mid1 の x) + mid1 の y とする
  13. radius を sqrt(centerX² + centerY²) とする
  14. curvature を 1 / radius とする
  15. centerX が centerY より小さい場合、−curvature を返す
  16. curvature を返す
色空間 origin color space 内の色 origin を、 非虚数の原色を持つ RGB 宛先色空間 destination (例えば ProPhoto RGB ではない)の色域内へマッピングするため、 destination 用に以前構築された EdgeSeeker ルックアップテーブル LUT が与えられたとき、 色 origin を EdgeSeeker 色域 マッピングするには:
  1. destination に色域制限がない場合(XYZ-D65、XYZ-D50、Lab、LCH、Oklab、OkLCh)、origin を destination に変換し、色域マッピングされた色として返す
  2. destination が HSL または HWB の場合、LUT を sRGB 用に構築されたルックアップテーブルとする
  3. clip(color) を、color を destination に変換し、 各成分をその成分の基準範囲の境界へクランプし、 その結果を返す関数とする
  4. origin が destination の色域内にある場合、clip(origin) を返す
  5. origin_OkLCh を、origin を origin color space から OkLCh 色空間へ変換したものとする
  6. origin_OkLCh の明度が 100% 以上の場合、 `oklab(1 0 0 / origin.alpha)` を destination に変換し、色域マッピングされた 色として返す
  7. origin_OkLCh の明度が 0% 以下の場合、 `oklab(0 0 0 / origin.alpha)` を destination に変換し、色域マッピングされた 色として返す
  8. l、c、h を、それぞれ origin_OkLCh の明度、彩度、色相とする
  9. h が欠落している場合、h を 0deg に設定する
  10. maxChroma を、 LUT を使用して l と h について最大 彩度を求めた結果とする
  11. c が maxChroma より大きい場合、c を maxChroma に設定する
  12. mapped を、明度 l、彩度 c、色相 h および origin と同じアルファを持つ OkLCh 色とする
  13. clipped を clip(mapped) に設定する
  14. clipped を色域マッピングされた色として返す
所与の OkLCh 明度 l および色相 h について、 EdgeSeeker ルックアップテーブル LUT (それぞれが明度、彩度、色相、曲率を持ち、 色相の昇順でソートされ、合わせて 0deg から 360deg までの色相範囲全体を両端を含めて覆うエントリーのリスト) を使用して、 最大 彩度を求めるには:
  1. l が 0% 以下、または l が 100% 以上の場合、 0 を返す
  2. h を h modulo 360deg に設定し、 結果が負の場合は 360deg を加え、 h が範囲 [0deg, 360deg) に収まるようにする
  3. lower と upper を、LUT 内で その色相が h を最も近くから挟む 2 つのエントリーとし、 lower の色相が h 以下、 upper の色相が h 以上となるようにする
  4. t を (h − lower の色相) / (upper の色相 − lower の色相) とし、 lower と upper が同じ色相を持つ場合は 0 とする
  5. cuspLightness を lower の明度 + t × (upper の明度 − lower の 明度) とする
  6. cuspChroma を lower の彩度 + t × (upper の彩度 − lower の彩度) とする
  7. curvature を lower の曲率 + t × (upper の曲率 − lower の 曲率) とする
  8. l が cuspLightness 以下の場合、 (l / cuspLightness) × cuspChroma を返す
  9. x を (100% − l) / (100% − cuspLightness) とする
  10. cuspChroma × x と curvature について上側色域境界弧上の正規化された 彩度を求めた 結果を返す
上側境界区間に沿った正規化位置 x (カスプで 1、白で 0) および絶対値が 1 未満の curvature が与えられ、 その位置での正規化された彩度を返すものとして、 上側色域境界弧上の正規化された彩度を 求めるには:

境界区間は、 与えられた符号付き曲率を持ち (0, 0) と (1, 1) を通る円弧である。 その円の中心を求める代わりに、 曲率が 0 に近いとき中心は非常に遠くなるため、 円の方程式全体に曲率を乗じ、 彩度について直接解くことで、 大きくほぼ等しい量どうしを減算することを回避する。

  1. t を sqrt(2 − curvature²) とする
  2. b を t − curvature とする
  3. d を x × (t + curvature × (1 − x)) とする
  4. disc を max(0, b² + 4 × curvature × d) とする
  5. 2 × d / (b + sqrt(disc)) を返す

注: 曲率の絶対値が 1 以上の場合、 円弧は x = 0 または x = 1 を越えて張り出し、 彩度はもはや x の一価関数ではなくなる。 一般的な RGB ディスプレイ色空間用のルックアップテーブルでは、 曲率はこの制限内に十分収まっている。

14.2.5. レイトレース ガマットマッピング

Ray Traceアルゴリズムは、 RGBガマットマッピングのための幾何学的アプローチであり、 一定の明度を保ったままクロマを高速に削減する。 もともとはIsaac Museによって Coloraide Pythonライブラリ向けに開発された [Coloraide-Ray-Trace]。

マッピング対象の色はまずOklchに変換され、 次にその色の無彩色版が生成される。 これがニュートラル軸のアンカーとなる。 この二つの色はその後、 対象RGB空間の線形光版へ変換される。

ガマット境界は軸に整列した立方体になるため、 交点の探索はより高速になる。

RGB立方体の内部から、 アンカーポイントから現在の色へ向けてレイを飛ばす。 その経路上でRGBガマット表面との交点を求める。 これがガマットマップ後の色の第一近似となる。

RGB空間は知覚的に均一ではないため、 一定色相・一定明度のレイは 実際にはRGB空間内で曲線経路になる。

第一近似をOklchへ戻して、 点をクロマ削減経路上へ再投影しながら 知覚色空間で色を補正し、 色相と明度を補正する。 補正後の色が新しい現在色となり、 クロマを下げた線上の、より近い色になるはずである。

この処理は(最大でさらに3回)繰り返され、 毎回より良く、より近い経路上の色が見つかる。 最後に、浮動小数点演算誤差に対処するため 単純クリッピングを用いる。

結果は、低いJNDを用いた局所MINDEによる二分探索と 同程度であるが、 それよりはるかに高速で、 より予測しやすく一貫した時間で収束する。

Ray Trace による sRGBガマットへの ガマットマッピング。 最大4回の反復で近似される クロマ削減の曲線経路を示す。
画像著作権 Isaac Muse.

注: 実験および実装比較のために、 Ray Trace の実装は Coloriadeライブラリ(Python) [Coloraide-Ray-Trace] および color.js ライブラリ(JavaScript) [colorjs-RayTrace] で利用できる。

14.2.6. レイトレースガマットマッピングのサンプル疑似コード

レイトレースガンマットマッピング で 色空間 origin color space の色 origin を、RGB行先色空間 destination のガンマットに収めるには:
  1. destination に色域制限がない場合(XYZ-D65、XYZ-D50、Lab、LCH、Oklab、OkLCh)、 origin を destination に変換し、色域マッピングされた色として返す
  2. origin_OkLCh を、origin color space から OkLCh 色空間へ変換した origin とする
  3. origin_OkLCh の明度が100%以上の場合、 `oklab(1 0 0 / origin.alpha)` を destination に変換し、色域マッピングされた 色として返す
  4. origin_OkLCh の明度が0%以下の場合、 `oklab(0 0 0 / origin.alpha)` を destination に変換し、色域マッピングされた 色として返す
  5. l_origin を origin_OkLCh の OkLCh 明度成分とする
  6. h_origin を origin_OkLCh の OkLCh 色相成分とする
  7. anchor を、明度に l_origin、彩度に0、色相に h_origin を使用して形成した無彩色の OkLCh 色を、 destination の線形光形式に変換したものとする
  8. origin_rgb を、origin_OkLCh を destination の線形光形式に変換したものとする
  9. origin_rgb が色域内にない場合
    • low を 0.0 + 1E-12 とする 1
    • high を 1.0 - 1E-12 とする 2
    • last を origin_rgb とする
    • for (i=0; i<4; i++)
      • if (i > 0)
        • current_OkLCh を origin_rgb を OkLCh に変換したものとする
        • current_OkLCh の明度を l_origin とする
        • current_OkLCh の色相を h_origin とする 3
        • origin_rgb を current_OkLCh を destination の線形光形式に変換したものとする
      • start = anchor から end = origin_rgb までレイをキャストし、 intersection を、このレイと 色域境界との交点とする
      • 交点が見つからなかった場合、 origin_rgb を last とし、ループを終了する 5
      • (i >0) AND(origin_rgb の各成分が low と high の間にある)の場合、 anchor を origin_rgb とする 4
      • origin_rgb を intersection とする
      • last を intersection とする
  10. clip(color) を、color を destination に変換し、 各成分をその成分の基準範囲の境界内にクランプして、 結果を返す関数とする
  11. clipped を clip(origin_rgb) に設定する
  12. clipped を色域マッピングされた色として返す
線形光 RGB 空間を通して、 start から end まで レイをキャストするには (色域マッピングでは、 start は RGB 色域内のアンカーであり、 end は立方体の色域表面上にある色域マッピングされた色である):
  1. bmin および bmax を、それぞれ 色域の下限と上限を持つ3要素の配列とする 6
  2. tfar を無限大(または非常に大きな数)とする
  3. tnear を負の無限大(または非常に大きな負の数)とする
  4. direction を3要素の配列とする
  5. for (i = 0; i < 3; i++):
    • a を start [i] とする
    • b を end [i] とする
    • d を b - a とする
    • direction [i] を d とする
    • if abs(d) > 1E-12 7
      • inv_d を 1 / d とする
      • t1 を (bmin [i] - a ) * inv_d とする
      • t2 を (bmax [i] - a ) * inv_d とする
      • tnear を max(min(t1, t2), tnear ) とする
      • tfar を min(max(t1, t2), tfar ) とする
    • else if (a < bmin[i] or a > bmax[i])
      • 交点が見つからなかったことを返す
  6. if (tnear > tfar or tfar < 0)
    • 交点が見つからなかったことを返す
  7. if tnear < 0
    • tnear を tfar とする 8
  8. tnear が無限大である(または初期の非常に大きな値と一致する)場合
    • 交点が見つからなかったことを返す
  9. for (i =0; i < 3; i++):
    • result [i] を start [i] + direction [i] * tnear とする
  10. result を返す
14.2.6.1. レイトレースアルゴリズムの脚注
  1. 最小値は0であり、 すべてのチャネルが同じ最小値を持つものと仮定します。 この値は、単位型に対して十分に小さくする必要があります。 指定された値1e-12は64ビット用ですが、32ビットでは1e-6を使用する必要があります。
  2. 1.0は色域内のチャネル値の最大値を表し、 すべてのチャネルが同じ最大値を持つものと仮定します。
  3. これにより、現在の色がずれている場合、 彩度低減曲線上に戻されます。
  4. これは、origin_rgb が色域表面より下にあることを意味するため、 色域表面により近いアンカーとして使用します。
  5. これは、特定の知覚的マッピング空間が、 極端に広い色(可視スペクトル外)によって 完全に破綻するような壊滅的な障害に備えて 提供されています。 CSS内の非虚数色がこれを引き起こすことは決してないと想定されています。
  6. 各成分の色域境界が0と1である 一般的なRGB空間では、 これは3要素の配列ではなく、 単一の定数に簡略化されます。
  7. この値は、単位型に対して十分に小さくする必要があります。 指定された値1e-12は64ビット用ですが、32ビットでは1e-6を使用する必要があります。
  8. start -> end の方向にある最初の交点を優先します。

15. <color>値の解決

特定のプロパティに別途指定がない限り、指定された色は、算出色に解決され、さらに使用 色へと下記のように解決されます。

解決値は、<color>の使用値です。

15.1. sRGB値の解決

これは以下に適用される:

これは次のものには適用されない。

sRGB 色が作者によって名前付き色として明示的に指定されていた場合、 宣言値は、その名前付き色を ASCII 小文字に変換したものである。 算出値および使用値は、 対応する sRGB 色と、 指定されたアルファ成分 ([0, 1] にクランプした後) を組み合わせたものであり、指定されていない場合は不透明が既定となる。

作者が指定した下記の混在大文字小文字形式は、宣言値がすべて小文字になる。

 pUrPlE

       purple

それ以外の場合、宣言値・計算値・使用値は 対応するsRGB色であり、 指定されたアルファ成分 ([0, 1] にクランプした後) を組み合わせたものとなる (指定がない場合は不透明を既定とする)。

歴史的な理由により、 sRGB色のcalc()が 単一の値に解決されるとき、 宣言値は "calc(" ")" の外側のラッパーなしでシリアライズされる。

例えば、色が rgb(calc(64 * 2) 127 255) のように与えられた場合、 宣言値は rgb(128 127 255) となり、 rgb(calc(128) 127 255) にはならない。
例えば、色が hsl(38.82 calc(2 * 50%) 50%) のように与えられた場合、 宣言値は rgb(255 165.2 0) となる。 それは、HSLからRGBへの変換中にcalc()が失われるためである。

また歴史的な理由により、 calc() が単一の値まで簡約された場合、 色値は [0.0, 255.0] にクランプされる。

例えば、色が rgb(calc(100 * 4) 127 calc(20 - 35)) のように与えられた場合、 宣言値は rgb(255 127 0) となり、 rgb(calc(400) 127 calc(-15)) にはならない。

このクランプは Infinity、-Infinity、および NaN のような値にも 対応し、それぞれ 255、0、0 にクランプされる。

例えば、次の計算値は

 hsl(38.824 100% 50%)

であり、

 rgb(255, 165, 0)

15.2. LabとLCH値の解決

これはlab()およびlch()値に適用されます。

宣言値・算出値・使用値は 対応するCIE LabまたはLCH色 (L, C, Hの丸め後) と指定アルファ成分の組み合わせ (<number>型。<percentage>型ではない。不指定なら不透明がデフォルト)。

例:

 lch(52.2345% 72.2 56.2 / 1)

の算出値は

 lch(52.2345% 72.2 56.2)

a・b・C の値は理論上は無限に広がり得ますが、 無限に近づく値に対する実装依存の上限 が設けられることがあります。

15.3. OklabおよびOkLCh値の解決

これは oklab() および oklch() の値に適用されます。

宣言値・計算値・使用値は (L・C・H のクランプ後の) 対応するOklabまたはOkLCh色となり、 指定アルファ成分( <number> 型、<percentage>型ではない; 未指定時は不透明が既定値) と組み合わせて扱われます。

例:次の値の計算値は

 oklch(42.1% 0.192 328.6 / 1)

次になります。

 oklch(42.1% 0.192 328.6)

a・b・C の値は理論的には無限に広がり得ますが、 無限に近づく値に対して実装依存の上限 が設けられる場合があります。

15.4. color()関数値の解決

宣言値・算出値・使用値は 指定色空間の色 と指定アルファ成分の組み合わせ (<number>型。<percentage>型ではない。不指定なら不透明がデフォルト)。

例:

 color(display-p3 0.823 0.6554 0.2537 /1)

の算出値は

 color(display-p3 0.823 0.6554 0.2537)

xyz 色空間で指定された色の場合、 これはxyz-d65 色空間のエイリアスなので、 算出値・使用値はxyz-d65 色空間で表されます。

例:

 color(xyz 0.472 0.372 0.131)

の算出値は

 color(xyz-d65 0.472 0.372 0.131)

r, g, b, x, y, z の値は理論上は無限に広がり得ますが、 無限に近づく値に対する実装依存の上限 が設けられる場合があります。

15.5. その他の色の解決

これは以下に適用される。

色が作者によって明示的に システムカラー または非推奨のシステムカラーとして指定された場合、 宣言値は、その値自体を ASCII小文字に変換したものである。

例えば、次のHTMLでは:
<mark style="color:  MarkText; background:  Mark">example</mark>

background-colorの宣言値は「mark」である。

システムカラーの場合、 計算値および使用値は、 その色空間における対応する色と、 指定されたアルファ成分 ([0, 1]にクランプした後)との組である。

非推奨のシステムカラーの場合、 計算値および使用値は、 対応するシステムカラーの色 (付録A:非推奨のCSSシステムカラーに記載されているもの) をその色空間で表したものと、 指定されたアルファ成分 ([0, 1]にクランプした後)との組である。

例えば、次のCSSがあるとする:
.foo {
      color:  InfoText;
    }

InfoTextに対応するシステムカラーは、CanvasTextである。 CanvasTextが#333であると仮定すると、 InfoTextの計算値も #333になる。

例えば、次のHTMLでは:
<button style="color:  ButtonText; background:  ButtonFace"></button>

colorプロパティの宣言値は「buttontext」であるが、 計算値は、例えば rgb(0, 0, 0) となる可能性がある。

ただし、システムカラーおよび非推奨のシステムカラーは、 強制カラーモードによって 変更されてはならない。

transparentの宣言値は「transparent」であり、 計算値および使用値は透明な黒である。

currentcolorキーワードの計算値は、それ自体である。

colorプロパティでは、 currentcolorの使用値は、 解決された継承値である。 その他のプロパティでは、 その使用値は、同じ要素のcolor プロパティの使用値である。

注:これは、currentcolor値が継承される場合、 colorプロパティの値としてではなく、 キーワードとして継承されることを意味する。 したがって、子孫はそれを解決するために、自身のcolorプロパティ を使用する。

例えば、次のHTMLがあるとする:
<div>
  <p>Assume this example text is long enough
    to wrap on multiple lines.
  </p>
</div>

さらに、次のCSSがあるとする:

div {
  color:  forestgreen;
  text-shadow: currentColor;
}
p {
  color:  mediumseagreen;
}
p::firstline {
  color:  yellowgreen;
}

最初の行フラグメントにおける、継承されたtext-shadowプロパティの使用値は、 yellowgreenになる。

16. <color>値のシリアル化

この節は CSS Object Model の当該部分、すなわち CSS Values のシリアライズ 節を更新し、 <color>値のシリアライズに関する部分を置き換える。

この節では、仕様中で用いられる文字列と対応する文字は次のとおりである。

文字列 文字
" " U+0020 SPACE
"#" U+0023 NUMBER SIGN
"," U+002C COMMA
"-" U+002D HYPHEN-MINUS
"." U+002E FULL STOP
"/" U+002F SOLIDUS
"none" U+006E LATIN SMALL LETTER N
U+006F LATIN SMALL LETTER O
U+006E LATIN SMALL LETTER N
U+0065 LATIN SMALL LETTER E

文字列 "." は、ロケールに関係なく小数点区切りとして使用し、 桁区切り記号は存在しないものとする。

欠損色成分をサポートする構文形式では、 値 none(NONE、nOnE なども同等)は、 すべて小文字で 文字列 "none" としてシリアライズされるものとする。

16.1. アルファ値のシリアル化

これは、オプションのアルファ値を取ることができる任意の <color> 値に適用されます。 opacity プロパティには適用されません。

[0, 1] の範囲にクランプした後、アルファが1である場合、 シリアル化では省略されます。 暗黙の値1(完全に不透明)が既定値です。

アルファが1以外の値である場合、 以下で説明するように、シリアル化に明示的に含まれます。

歴史的な理由により、 アルファのシリアル化は、 色が従来の色 構文 または現代の色 構文のどちらを使用して指定されたかによって異なります。

16.1.1. 従来のアルファ値のシリアル化

値が0以上255以下の整数 (すなわち、8ビット符号なし整数)として内部的に表現されている場合、 次の手順に従います。

  1. alpha を指定された整数とする。
  2. 0以上100以下の整数で、 2.55を乗算して最も近い整数に丸めたとき (2つの値が同じ近さである場合は切り上げる)、alpha と等しくなるものが存在する場合、 rounded をその整数を100で除算した値とする。
  3. それ以外の場合、rounded を alpha を0.255で除算して最も近い整数に丸め (2つの値が同じ近さである場合は切り上げる)、 さらに1000で除算した値とする。
  4. rounded を <number> としてシリアル化した結果を返す。

それ以外の場合、指定された値を (<number> としてであり、 <percentage> としてではない)、 現代のアルファのシリアル化と同じ方法でシリアル化した結果を返します。

たとえば、 アルファが8ビット符号なし整数237として格納されている場合、 Math.round(93 * 2.55) は237であるため、 整数93が条件を満たし、 アルファは "0.93" としてシリアル化されます。

ただし、 アルファが8ビット符号なし整数236として格納されている場合、 そのような整数は存在せず (92は235に対応し、94は240に対応する)、 236 ÷ 0.255 = 925.490196078 であるため、 アルファは "0.92549" としてシリアル化されます (6桁以下で、末尾のゼロは省略される)。

従来の色 構文では、 アルファ値を保持する精度、 したがってシリアル化された値の小数点以下の桁数は、 少なくとも整数パーセント値を ラウンドトリップするのに十分でなければなりません。 したがって、シリアル化された値には、 少なくとも小数点以下2桁が含まれなければなりません (末尾のゼロが削除されている場合を除く)。 値は切り捨てるのではなく、 +∞方向に丸めなければなりません。

たとえば、12.3456789%のアルファ値は、 文字列 "0.12"、"0.123"、"0.1234"、または "0.12346" (後続の桁が6であるため、 値5を+∞方向に 丸める)、 あるいは同じ形式でさらに長く丸めたシリアル化として表すことができます。

16.1.2. 現代のアルファ値のシリアル化

指定された値を (<number> としてであり、 <percentage> としてではない) シリアル化した結果を返します。

<number> 値は10進数で表し、 "." 文字を小数点区切りとして使用します。 先頭のゼロを省略してはなりません。 末尾のゼロは省略しなければなりません。

たとえば、70%のアルファ値は、 文字列 "0.7" としてシリアル化されます。これには小数点区切りの前に先頭のゼロがあり、 "." が小数点区切りとして使用され (現在のロケールで "," などの別の文字が使用される場合でも)、 "7" より後のすべての桁は "0" になるため省略されます。

現代の色 構文では、 <alpha-value>を保持する精度、 したがってシリアル化された値の小数点以下の桁数は、 16ビットの10進値をラウンドトリップするのに十分であることが 要求されます。

シリアル化された値には、 小数点以下6桁が含まれなければなりません (末尾のゼロが削除されている場合を除く)。

値は切り捨てるのではなく、 +∞方向に丸めなければなりません。

たとえば、12.3456789%のアルファ値は、 文字列 "0.123457" としてシリアル化されます (値を +∞方向に丸める)。

たとえば、 色 color(srgb 1 0 0 / 0.5) が指定された場合、 アルファ値は 文字列 "0.5" としてシリアル化されます。 10ビット精度のみで格納されていた場合、 内部値は512/1023となり、 これは0.50048875855、 または有効数字6桁では "0.500489" となり、 目的の値に近いものの、正確ではありません。 12ビットでは、 2048/4095となり、 これは0.50012210012、 有効数字6桁では0.500122となり、 それでも正確ではありません。

また、これを 128/255 として格納することも正しくありません。 これは 0.50196078431、 または 有効数字6桁では0.501960となります。

累積的な丸め誤差を避けるため、 アルファ成分ごとの内部ストレージには、 16ビット、半精度浮動小数点数、または浮動小数点数が推奨されます。

有効範囲外で指定された <alpha-value>は 構文解析時にクランプされるため、宣言値もクランプされます。 ただし、CSS Values 4 § 10.12 範囲検査に従い、calc()を使用して指定された <alpha-value>は、 指定された形式がシリアル化されるときにはクランプされませんが、 計算値はクランプされます。

たとえば、120%として直接指定されたアルファ値は、 文字列 "1" としてシリアル化されます。 ただし、calc(2*60%)として指定された場合、 宣言値は文字列 "calc(1.2)" としてシリアル化されます。

16.2. sRGB値のシリアル化

次の sRGB 値のシリアル化形式は、

宣言値から導出される。

作者によって CSS の名前付き色、 システム色、 非推奨色、 または transparent に設定されたプロパティの値をシリアル化する場合、 したがって、宣言値については、 ASCII 小文字の キーワード値が保持される。 算出値および使用値については、 対応する sRGB 値が使用される。

したがって、transparent のシリアル化された宣言値は文字列 "transparent" であり、 一方、transparent のシリアル化された算出値は文字列 "rgba(0, 0, 0, 0)" である。

その他すべての sRGB 値については、 宣言値、算出値、および使用値は 対応する sRGB 値である。

シリアライズ中、 欠落した値はすべて、 選択されたシリアライズ形式が (カンマ区切りを使用する従来の 色構文や、 sRGB 値の HTML 互換シリアライズ など) none キーワードを表現できない場合、 0 に変換される。 少なくとも 1 つの成分が欠落しており、 値を none をサポートする形式でシリアライズできる場合、 その形式は § 16.2.2 sRGB 値の CSS シリアライズ に記載されたとおりに選択され、 欠落した色成分が none として保持される。

16.2.1. HTML互換sRGB値のシリアル化

以下の条件がすべて真である場合:

  1. 色空間が sRGB である
  2. アルファが 1 である
  3. RGB成分値が内部的に 0 から 255 までの整数(すなわち 8ビット 符号なし整数)として表現されている
  4. HTML互換シリアライズが 要求されている

その場合、対応する sRGB 値は以下の形式で6桁のhexカラー表記としてシリアライズされる:

7文字の文字列であり、文字 "#" に続けて、赤成分・緑成分・青成分をこの順で それぞれ2桁の16進表現にしたものを並べる。 ASCII小文字の16進数字を使用する。 空白は許されない。

例えば、fill style は マゼンタに設定される:
context.fillStyle = "rgb(255, 0, 255)"
console.log(context.fillStyle); // "#ff00ff"

色空間は sRGB であり、表現は成分ごとに8ビット、 データ形式はnone値を生成せず、拡張範囲値もサポートせず、 さらにアルファは 1 である。

HTML互換シリアライズは文字列 "#ff00ff" となる("#FF00FF" ではない)。

それ以外の場合、sRGB についてはsRGB値のCSSシリアライズが使用される。 その他の色空間については、<color>値の該当するシリアライズが用いられる。

例えば、fill style は CIE Labの 暗い茶色に設定される:
context.fillStyle = "lab(29% 39 20)";
console.log(context.fillStyle);
 // "lab(29 39 20)"

CSSシリアライズは文字列 "lab(29 39 20)" となる。

例えば、fill style は 半透明の マゼンタに設定される:
context.fillStyle = "#ff00ffed";
console.log(context.fillStyle);
 // "rgba(255, 0, 255, 0.93)"

アルファは 1 ではないため、CSSシリアライズは文字列 "rgba(255, 0, 255, 0.93)" となる。

16.2.2. sRGB値のCSSシリアル化

値に欠落した色成分がない場合、 対応する sRGB 値には rgb() または rgba() 形式を使用し、 (クランプされたアルファが正確に 1 かどうかに応じて)、 関数名のすべての文字には ASCII 小文字 を使用する。

互換性のため、sRGB 成分値は <number> 形式でシリアライズされ、 <percentage> 形式ではない。 また、互換性のため、 成分値は 10 進数でシリアライズされ、 格納時のビット深度にかかわらず、 範囲は [0-255] となる。

前述のとおり、 1 に等しいアルファ値は明示的にシリアライズされない。 また、互換性のため、アルファが正確に 1 の場合、 rgb() 形式が 使用され、 アルファは暗黙的となる。 それ以外の場合、rgba() 形式が使用され、 アルファ値は明示される。

互換性のため、 カンマ区切りの従来形式が使用され、 各カンマの直後には正確に 1 つの ASCII スペースが続く。 これには、rgba() の青成分と アルファ値を区切るために使用するカンマ(スラッシュではない) も含まれる。

ただし、カンマ区切りの従来の 色構文では、 none を表現できない。 値に少なくとも 1 つの欠落した色成分がある場合、 シリアライズ形式は、 それらの成分を none キーワードとして保持するように、 宣言 値の色関数に基づいて選択される。

注: これは、hsl() または hwb() の値に none が含まれる場合、 シリアライズを経ても元の色関数の形式が維持され、 rgba()(従来形式では none を表現できない) に変換されないことを意味する。一方、 rgb() の値に none が含まれる場合は、 color(srgb …) を使用してシリアライズされる。 rgb() の現代的なスペース区切り形式自体も none を表現できるが、 sRGB の CSS シリアライズでは、代わりに color(srgb …) を使用する。 これは、他のすべての色空間が 従来形式ではない形式でシリアライズされる方法との一貫性を保つためである。 これは、CSS Color 5 § 11.2 元の色のシリアライズで定義された 相対色構文の動作と対応している。

例えば、次の値をシリアライズすると、

 rgb(29 164 192 / 95%)

文字列 "rgba(29, 164, 192, 0.95)" となる。

例えば、作者が指定した値:
 hwb(740deg 20% 30% / 50%)

まず次のように正規化され、

 hwb(20 20% 30% / 50%)

その後 sRGB に変換され、次のようにシリアライズされる。

 rgba(178.5, 93.5, 51, 0.5)

返される結果の精度については 後述する。

例えば、作者が指定した値
hwb(20 none 30% / none)

には欠落した色成分が含まれる (白色度とアルファの両方が none である)ため、 rgba() を介してシリアライズされない。 代わりに、現代的な hwb() 構文を使用し、次のようにシリアライズされる。

hwb(20 none 30% / none)

各 none 値が保持される。

同様に、作者が指定した値
rgb(none 0 0)

は次のようにシリアライズされる。

color(srgb none 0 0)

これは、rgb() (シリアライズされた従来のカンマ区切り形式では) none を表現できないためである。

注: CSS Color 3 とは異なり、 rgb() 関数のパラメーターは <number> 型であり、 <integer> 型ではない。 したがって、8 ビットを超える精度は 小数部分で表される。

sRGB 成分値を保持する精度、 したがってシリアライズされた値の有効桁数は、 この仕様では定義されていないが、 少なくとも 8 ビット値を往復変換できるだけの 精度が必要である。 値は切り捨てるのではなく、 +∞ 方向に丸める必要がある。

注: getComputedStyle から返される色値の成分が <integer> 値であることを期待するスクリプトの作者には、 <number> にも対応できるように 更新することを推奨する。

例えば、

 rgb(146.064 107.457 131.223)

は現在有効であり、次の値と等しい。

 rgb(57.28% 42.14% 51.46%)

両方に適合するシリアライズ形式は、 文字列 "rgb(146.06, 107.46, 131.2)" である。

成分値の小数部分の末尾にあるゼロは省略しなければならない。 小数部分がすべてゼロの場合、 小数点も省略しなければならない。 これは、整数の成分値で指定された sRGB 色が、 後方互換性のある整数値としてシリアライズされることを意味する。

次の値のシリアライズされた算出値は、

 ''goldenrod''

文字列 "rgb(218, 165, 32)" であり、 文字列 "rgb(218.000, 165.000, 32.000)" ではない。

16.3. LabとLCH値のシリアル化

lch()およびlab()値のシリアル化形式は 算出値に基づき、 関数名はlab()またはlch() でASCII小文字です。

成分値は10進数でシリアル化し、 L・a・b・C成分値は<number>型、 Labパーセンテージ参照範囲やLCHパーセンテージ参照範囲に従い パーセント→数値変換を行う(0%L→0、100%L→100)。 成分間の区切りはASCIIスペース1個。

以下のシリアル化値

 lab(56.200% 0.000 83.600)

は "lab(56.2 0 83.6)"

以下のシリアル化値

 lab(56.200% 0.000 66.88%)

は "lab(56.2 0 83.6)"

成分値の小数部のゼロは末尾省略し、 小数部がすべてゼロなら小数点も省略します。

以下のシリアル化値

 lch(37% 105.0 305.00)

は "lch(37 105 305)"、 "lch(37 105.0 305.00)" ではありません。

lab()成分値の保持精度(シリアル化時の有効桁数)は本仕様で定義されませんが、 広いガマットゆえL値は0~100、a・b値は±127間でラウンドトリップ可能な精度(最低16ビット精度)が必要です。 これにより少なくとも小数点以下3桁(末尾ゼロ省略可)が得られます。 (内部表現はhalf floatやfloat推奨)。 値は+∞方向へ丸め、切り捨てしません。

注: a・b値は±125を超えることも可能です。 例えばprophoto-rgb主・二次色はこの範囲を超えますが、±200内に収まります。

前述の通り、 アルファ値が1なら明示的シリアル化しません。 1以外は明示的シリアル化し、 " / " (スペース+スラッシュ+スペース)でb成分値とアルファ値を区切ります。

以下のシリアル化値

 lch(56.2% 83.6 357.4 /93%)

は "lch(56.2 83.6 357.4 / 0.93)"、 "lch(56.2% 83.6 357.4 / 0.93)" ではありません

16.4. OklabおよびOkLCh値のシリアライズ

oklch()およびoklab()値のシリアル化形式は 算出値に基づき、 関数名はoklab()またはoklch()でASCII小文字です。

成分値は10進数でシリアル化し、 L・a・b・C成分値は<number>型、 Oklabパーセンテージ参照範囲やOKLChパーセンテージ参照範囲に従い パーセント→数値変換を行う(0%L→0、100%L→1.0)。 成分間の区切りはASCIIスペース1個。

以下のシリアル化値

 oklab(54.0% -0.10 -0.02)

は "oklab(0.54 -0.1 -0.02)"、 "oklab(54 -0.1 -0.02)" や "oklab(54% -0.1 -0.02)" ではありません

以下のシリアル化値

 oklab(54.0 -25% -5%)

は "oklab(0.54 -0.1 -0.02)"、 "oklab(54 -0.25 -0.05)" ではありません

成分値の小数部のゼロは末尾省略し、 小数部がすべてゼロなら小数点も省略します。

以下のシリアル化値

 oklch(56.43% 0.0900 123.40)

は "oklch(0.5643 0.09 123.4)"、 "oklch(0.5643 0.0900 123.40)" ではありません。

oklab()成分値の保持精度(シリアル化時の有効桁数)は本仕様で定義されませんが、 広いガマットゆえL値は0~1(0%~100%)、a・b・C値は±0.5間でラウンドトリップ可能な精度(最低16ビット精度)が必要です。 これにより少なくとも小数点以下5桁(末尾ゼロ省略可)が得られます。 (内部表現はhalf floatやfloat推奨)。 値は+∞方向へ丸め、切り捨てしません。

注: a・b・C値は±0.5を超えることも可能です。 例えばprophoto-rgbの緑・青主色はこの範囲を超え、 Cはそれぞれ0.526と1.413となります。

前述の通り、 アルファ値が1なら明示的シリアル化しません。 1以外は明示的シリアル化し、 " / " (スペース+スラッシュ+スペース)で最終成分値(bまたはC)とアルファ値を区切ります。

以下のシリアル化値

 oklch(53.85% 0.1725 320.67 / 70%)

は "oklch(0.5385 0.1725 320.67 / 0.7)"

16.5. color()関数値のシリアル化

color() 値のシリアル化形式は、 算出値から導出され、 color() 形式を使用し、 関数名 および色空間名には ASCII 小文字 を使用する。

成分値は10進数で、 <number> としてシリアル化される。 単一の ASCII スペース文字 " " を区切りとして、 成分値の間、 および色空間名と最初の色成分の間にも使用しなければならない。

次の値をシリアル化すると、

 color(dIsPlAy-P3  0.964  0.763  0.787)

小数点以下2桁を保持する場合、文字列 "color(display-p3 0.96 0.76 0.79)" となる。 0.787 は 0.78 に切り捨てられるのではなく、 0.79 に丸められていることに注意。

成分値の末尾にある小数部のゼロは省略しなければならない。 小数部分がすべてゼロで構成されている場合、 小数点も省略しなければならない。

次の値をシリアル化すると、

 color(rec2020 0.400 0.660 0.340)

文字列 "color(rec2020 0.4 0.66 0.34)" となり、 "color(rec2020 0.400 0.660 0.340)" とはならない。

色空間が sRGB の場合でも、シリアル化された結果では色空間を明示的に指定する必要がある。

定義済みの色空間について、 往復変換に必要な最小精度は次のとおりである。

色空間 最小ビット数
srgb 10
srgb-linear 12
display-p3 10
display-p3-linear 12
a98-rgb 10
prophoto-rgb 12
rec2020 12
xyz, xyz-d50, xyz-d65 16

(内部ストレージには成分ごとに16ビット、半精度浮動小数点数、または浮動小数点数 を使用することが推奨される)。 値は切り捨てるのではなく、+∞ 方向に丸めなければならない。

注: rgb()、hsl() などの従来形式と比較すると、 color(srgb) にはより高い最小精度が要求される。 したがって、より高い精度を望むスタイルシート作者には、 color(srgb) 形式を使用することが推奨される。

前述のとおり、 1 のアルファ値は明示的にシリアル化されない。 1 ではないアルファ値は明示的にシリアル化しなければならず、 文字列 " / " (ASCII スペース、続いてスラッシュ、さらにもう1つのスペース) を使用して、 最後の色成分値と アルファ値を区切らなければならない。

次の値をシリアル化すると、

 color(prophoto-rgb 0.2804 0.40283 0.42259/85%)

小数点以下3桁を保持する場合、文字列 "color(prophoto-rgb 0.28 0.403 0.423 / 0.85)" となる。

16.6. その他の色のシリアル化

これはcurrentcolorに適用されます。

この値のシリアル化形式は 算出値に基づき、 色名はASCII小文字で表記されます。

currentColorのシリアル化値は文字列"currentcolor"です。

17. <opacity-value>値のシリアル化

これは opacity プロパティ、 および値に <opacity-value> を含むプロパティに適用されます。 たとえば shape-image-threshold などです。

opacity値に指定された値が リテラルな<percentage-token> と一致する場合(つまり calc() を使わない場合)、 それは等価な <number>(0%は0、100%は1に対応)値として 直列化されるべきです。 それ以外の場合、 opacity値への指定値は 文法標準の直列化を使って 直列化すべきです。

この<number> 値は10進法で表され、 小数点記号として「.」が使われます。 先頭の0は省略してはいけません。 末尾の0は省略しなければなりません。

opacity値が[0,1]範囲外であっても シリアライズされた指定値ではクランプせず保持されます。

opacity値の保持精度――すなわち直列化値の小数点以下の桁数――は この仕様では定義されていませんが、 少なくとも整数パーセント値のラウンドトリップが可能な精度である必要があります。 したがって直列化値には 少なくとも2桁以上の小数部を含める必要があり (ただし末尾の0は削除された場合は除く) 値は +∞方向への四捨五入でなければならず 切り捨ててはなりません。

18. デフォルトスタイル規則

以下のスタイルシートは参考用で規範的ではありません。実装がHTML文書のデフォルトスタイルの一部として利用することができます。

/* 従来のデスクトップユーザーエージェントのハイパーリンク色 */
:link { color: LinkText; }
:visited { color: VisitedText; }
:active { color: ActiveText; }

19. 色変換のサンプルコード

この節は規範的なものではありません。

分かりやすさのため、ライブラリを行列の積に使用しています。 (全てを掛け算や加算でインラインするよりも可読性が高いです)。 行列はカラムメジャー順です。

// 色変換のサンプルコード
// 変換はICCプロファイルやカラーマネジメントシステムでも実行できます
// 明瞭にするため、行列積にはライブラリ(multiply-matrices.js)を使用しています

// 4桁のCIE x,y色度で定義された標準白色点
const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
const D65 = [0.3127 / 0.3290, 1.00000, (1.0 - 0.3127 - 0.3290) / 0.3290];

// sRGB 関連の関数

function lin_sRGB(RGB) {
	// sRGB 値の配列を変換します
	// ガマット内の値は [0 - 1] の範囲です
	// 線形光(非コンパンド)形式へ変換します。
	// https://en.wikipedia.org/wiki/SRGB
	// 拡張伝達関数:
	// 負の値に対しては、軸を反転して線形部分を延長し、
	// その後反転したべき乗関数を使用します。
	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);

		if (abs <= 0.04045) {
			return val / 12.92;
		}

		return sign * (Math.pow((abs + 0.055) / 1.055, 2.4));
	});
}

function gam_sRGB(RGB) {
	// 0.0-1.0 範囲の線形光 sRGB 値配列をガンマ補正形式に変換します
	// https://en.wikipedia.org/wiki/SRGB
	// 拡張伝達関数:
	// 負の値に対しては軸を反転して線形部分を延長し、
	// その下で反転した pow を使用します
	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);

		if (abs > 0.0031308) {
			return sign * (1.055 * Math.pow(abs, 1/2.4) - 0.055);
		}

		return 12.92 * val;
	});
}

function lin_sRGB_to_XYZ(rgb) {
	// 線形光 sRGB 値配列を CIE XYZ に変換します
	// sRGB の白色点 D65 を使用(色順応は行いません)

	var M = [
		[ 506752 / 1228815,  87881 / 245763,   12673 /   70218 ],
		[  87098 /  409605, 175762 / 245763,   12673 /  175545 ],
		[   7918 /  409605,  87881 / 737289, 1001167 / 1053270 ],
	];
	return multiplyMatrices(M, rgb);
}

function XYZ_to_lin_sRGB(XYZ) {
	// XYZ を線形光 sRGB に変換します

	var M = [
		[   12831 /   3959,    -329 /    214, -1974 /   3959 ],
		[ -851781 / 878810, 1648619 / 878810, 36519 / 878810 ],
		[     705 /  12673,   -2585 /  12673,   705 /    667 ],
	];

	return multiplyMatrices(M, XYZ);
}

// display-p3 関連の関数


function lin_P3(RGB) {
	// 0.0 - 1.0 範囲の display-p3 RGB 値配列を線形光(非コンパンド)形式に変換します。

	return lin_sRGB(RGB);	// sRGB と同じ
}

function gam_P3(RGB) {
	// 0.0-1.0 範囲の線形光 display-p3 RGB をガンマ補正形式に変換します

	return gam_sRGB(RGB);	// sRGB と同じ
}

function lin_P3_to_XYZ(rgb) {
	// 線形光 display-p3 値配列を CIE XYZ に変換します
	// D65 を使用(色順応なし)
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	var M = [
		[ 608311 / 1250200, 189793 / 714400,  198249 / 1000160 ],
		[  35783 /  156275, 247089 / 357200,  198249 / 2500400 ],
		[      0 /       1,  32229 / 714400, 5220557 / 5000800 ],
	];

	return multiplyMatrices(M, rgb);
}

function XYZ_to_lin_P3(XYZ) {
	// XYZ を線形光 P3 に変換します
	var M = [
		[ 446124 / 178915, -333277 / 357830, -72051 / 178915 ],
		[ -14852 /  17905,   63121 /  35810,    423 /  17905 ],
		[  11844 / 330415,  -50337 / 660830, 316169 / 330415 ],
	];

	return multiplyMatrices(M, XYZ);
}

// prophoto-rgb 関数群

function lin_ProPhoto(RGB) {
	// prophoto-rgb 値の配列を変換します
	// ガマット内の色は [0.0 - 1.0] 範囲です
	// 線形光(非コンパンド)形式へ変換します。
	// 転送曲線はガンマ1.8で、小さな線形部分があります
	// 拡張伝達関数
	const Et2 = 16/512;
	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);

		if (abs <= Et2) {
			return val / 16;
		}

		return sign * Math.pow(abs, 1.8);
	});
}

function gam_ProPhoto(RGB) {
	// 0.0-1.0 範囲の線形光 prophoto-rgb をガンマ補正形式に変換します
	// 転送曲線はガンマ1.8で小さな線形部分があります
	// TODO: 負の値に対しては軸を反転させて線形部分を延長し、その後に pow を適用する
	const Et = 1/512;
	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);

		if (abs >= Et) {
			return sign * Math.pow(abs, 1/1.8);
		}

		return 16 * val;
	});
}

function lin_ProPhoto_to_XYZ(rgb) {
	// 線形光 prophoto-rgb 値配列を CIE D50 XYZ に変換します
	// 行列は有理形式では表現できませんが、64ビット精度で計算されています
	// 詳細は https://github.com/w3c/csswg-drafts/issues/7675 を参照してください
	var M = [
		[ 0.79776664490064230,  0.13518129740053308,  0.03134773412839220 ],
		[ 0.28807482881940130,  0.71183523424187300,  0.00008993693872564 ],
		[ 0.00000000000000000,  0.00000000000000000,  0.82510460251046020 ]
	];

	return multiplyMatrices(M, rgb);
}

function XYZ_to_lin_ProPhoto(XYZ) {
	// D50 XYZ を線形光 prophoto-rgb に変換します
	var M = [
		[  1.34578688164715830, -0.25557208737979464, -0.05110186497554526 ],
        [ -0.54463070512490190,  1.50824774284514680,  0.02052744743642139 ],
        [  0.00000000000000000,  0.00000000000000000,  1.21196754563894520 ]
	];

	return multiplyMatrices(M, XYZ);
}

// a98-rgb 関数群

function lin_a98rgb(RGB) {
	// 0.0 - 1.0 範囲の a98-rgb 値配列を線形光(非コンパンド)形式に変換します
	// 現在は負の値も許容します
	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);

	  	return sign * Math.pow(abs, 563/256);
	});
}

function gam_a98rgb(RGB) {
	// 0.0-1.0 範囲の線形光 a98-rgb をガンマ補正形式に変換します
	// 負の値も許容されます
	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);

		return sign * Math.pow(abs, 256/563);
	});
}

function lin_a98rgb_to_XYZ(rgb) {
	// 線形光 a98-rgb 値配列を CIE XYZ に変換します
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	// 数値精度は AdobeRGB1998 の仕様より高く、
	// 下記の値は R G B W の色度座標から一義的に計算されています
	// matrixmaker.html を参照
	var M = [
		[ 573536 /  994567,  263643 / 1420810,  187206 /  994567 ],
		[ 591459 / 1989134, 6239551 / 9945670,  374412 / 4972835 ],
		[  53769 / 1989134,  351524 / 4972835, 4929758 / 4972835 ],
	];

	return multiplyMatrices(M, rgb);
}

function XYZ_to_lin_a98rgb(XYZ) {
	// XYZ を線形光 a98-rgb に変換します
	var M = [
		[ 1829569 /  896150, -506331 /  896150, -308931 /  896150 ],
		[ -851781 /  878810, 1648619 /  878810,   36519 /  878810 ],
		[   16779 / 1248040, -147721 / 1248040, 1266979 / 1248040 ],
	];

	return multiplyMatrices(M, XYZ);
}

// Rec.2020 関連の関数

function lin_2020(RGB) {
	// rec2020 RGB 値配列を 0.0 - 1.0 範囲で線形光(非コンパンド)形式へ変換します
	// Rec. ITU-R BT.1886 附属書1 の参照電気光学伝達関数に基づきます
	// b(ブラックリフト)= 0、a(ユーザーゲイン)= 1
	// 拡張範囲に対して定義され、クランプは行いません

	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);
		return sign * Math.pow(abs, 2.4);
	});
}

function gam_2020(RGB) {
	// 0.0-1.0 範囲の線形光 rec2020 RGB をガンマ補正形式に変換します
	// Rec. ITU-R BT.1886 附属書1 に基づく参照伝達関数(b = 0, a = 1)
	// 拡張範囲に対して定義され、クランプは行いません

	return RGB.map(function (val) {
		let sign = val < 0? -1 : 1;
		let abs = Math.abs(val);
		return sign * Math.pow(abs, 1 / 2.4);
	});
}

function lin_2020_to_XYZ(rgb) {
	// 線形光 rec2020 値配列を CIE XYZ に変換します
	// D65 を使用(色順応なし)
	var M = [
		[ 63426534 / 99577255,  20160776 / 139408157,  47086771 / 278816314 ],
		[ 26158966 / 99577255, 472592308 / 697040785,   8267143 / 139408157 ],
		[        0 /        1,  19567812 / 697040785, 295819943 / 278816314 ],
	];
	// 実際には 0 は 4.994106574466076e-17 のように計算されます

	return multiplyMatrices(M, rgb);
}

function XYZ_to_lin_2020(XYZ) {
	// XYZ を線形光 rec2020 に変換します
	var M = [
		[  30757411 / 17917100, -6372589 / 17917100, -4539589 / 17917100 ],
		[ -19765991 / 29648200, 47925759 / 29648200,   467509 / 29648200 ],
		[    792561 / 44930125, -1921689 / 44930125, 42328811 / 44930125 ],
	];

	return multiplyMatrices(M, XYZ);
}

// 色順応(Chromatic adaptation)

function D65_to_D50(XYZ) {
	// D65 から D50 への Bradford 色順応
	// 以下の行列は次の3操作の結果です:
	// - XYZ を網膜錐体ドメインに変換
	// - 参照白を別の参照白に合わせるために各成分をスケーリング
	// - 再び XYZ に戻す
	// 詳細は https://github.com/LeaVerou/color.js/pull/354/files を参照

	var M =  [
		[  1.0479297925449969,    0.022946870601609652,  -0.05019226628920524  ],
		[  0.02962780877005599,   0.9904344267538799,    -0.017073799063418826 ],
		[ -0.009243040646204504,  0.015055191490298152,   0.7518742814281371   ]
	];

	return multiplyMatrices(M, XYZ);
}

function D50_to_D65(XYZ) {
	// D50 から D65 への Bradford 色順応
	// 詳細は https://github.com/LeaVerou/color.js/pull/360/files を参照
	var M = [
		[  0.955473421488075,    -0.02309845494876471,   0.06325924320057072  ],
		[ -0.0283697093338637,    1.0099953980813041,    0.021041441191917323 ],
		[  0.012314014864481998, -0.020507649298898964,  1.330365926242124    ]
	];

	return multiplyMatrices(M, XYZ);
}

// CIE Lab と LCH

function XYZ_to_Lab(XYZ) {
	// XYZ が D50 相対であると仮定して CIE Lab に変換します
	// CIE の標準に基づき、これらは現在有理分数として定義されています
	var ε = 216/24389;  // 6^3/29^3
	var κ = 24389/27;   // 29^3/3^3

	// 参照白に対してスケーリングされた xyz(XYZ のスケール版)を計算します
	var xyz = XYZ.map((value, i) => value / D50[i]);

	// 次に f を計算します
	var f = xyz.map(value => value > ε ? Math.cbrt(value) : (κ * value + 16)/116);

	return [
		(116 * f[1]) - 16, 	 // L
		500 * (f[0] - f[1]), // a
		200 * (f[1] - f[2])  // b
	];
	// L の範囲は [0,100]。CSS で使う場合はパーセント表記を追加してください
}

function Lab_to_XYZ(Lab) {
	// Lab を D50 に適合させた XYZ に変換します
	// http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
	var κ = 24389/27;   // 29^3/3^3
	var ε = 216/24389;  // 6^3/29^3
	var f = [];

	// 明度関連の項目から f を計算開始します
	f[1] = (Lab[0] + 16)/116;
	f[0] = Lab[1]/500 + f[1];
	f[2] = f[1] - Lab[2]/200;

	// xyz を計算します
	var xyz = [
		Math.pow(f[0],3) > ε ?   Math.pow(f[0],3)            : (116*f[0]-16)/κ,
		Lab[0] > κ * ε ?         Math.pow((Lab[0]+16)/116,3) : Lab[0]/κ,
		Math.pow(f[2],3)  > ε ?  Math.pow(f[2],3)            : (116*f[2]-16)/κ
	];

	// xyz を参照白でスケーリングして XYZ を得ます
	return xyz.map((value, i) => value * D50[i]);
}

function Lab_to_LCH(Lab) {
	var epsilon = 0.0015;
	var chroma = Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)); // クロマ
	var hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI;
	if (hue < 0) {
		hue = hue + 360;
	}
	if (chroma <= epsilon) {
		hue = NaN;
	}
	return [
		Lab[0], // L はそのまま L
		chroma, // クロマ
		hue // 色相(度単位)、[0〜360) の範囲
	];
}

function LCH_to_Lab(LCH) {
	// 極座標形式から変換します
	return [
		LCH[0], // L はそのまま L
		LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a
		LCH[1] * Math.sin(LCH[2] * Math.PI / 180) // b
	];
}

// OKLab と OKLCH
// https://bottosson.github.io/posts/oklab/

// 一貫した参照白のために再計算された XYZ <-> LMS 行列
// 詳細は https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 を参照
// 64bit 精度で再計算されています
// see https://github.com/color-js/color.js/pull/357

function XYZ_to_OKLab(XYZ) {
	// D65 相対の XYZ を受け取り OKLab に変換します
	var XYZtoLMS = [
		[ 0.8190224379967030, 0.3619062600528904, -0.1288737815209879 ],
		[ 0.0329836539323885, 0.9292868615863434,  0.0361446663506424 ],
		[ 0.0481771893596242, 0.2642395317527308,  0.6335478284694309 ]
	];
	var LMStoOKLab = [
		[ 0.2104542683093140,  0.7936177747023054, -0.0040720430116193 ],
		[ 1.9779985324311684, -2.4285922420485799,  0.4505937096174110 ],
		[ 0.0259040424655478,  0.7827717124575296, -0.8086757549230774 ]
	];

	var LMS = multiplyMatrices(XYZtoLMS, XYZ);
	// JavaScript の Math.cbrt は符号に合わせた立方根を返します
	// 他言語へ移植する際は注意してください
	// 特に一般的なべき乗関数を使おうとする場合は要注意です
	return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c)));
	// L は [0,1] の範囲。CSS で使う場合は 100 倍してパーセントを付けてください
}

function OKLab_to_XYZ(OKLab) {
	// OKLab を受け取り D65 相対の XYZ に変換します
	var LMStoXYZ =  [
		[  1.2268798758459243, -0.5578149944602171,  0.2813910456659647 ],
		[ -0.0405757452148008,  1.1122868032803170, -0.0717110580655164 ],
		[ -0.0763729366746601, -0.4214933324022432,  1.5869240198367816 ]
	];
	var OKLabtoLMS = [
		[ 1.0000000000000000,  0.3963377773761749,  0.2158037573099136 ],
		[ 1.0000000000000000, -0.1055613458156586, -0.0638541728258133 ],
		[ 1.0000000000000000, -0.0894841775298119, -1.2914855480194092 ]
    ];

	var LMSnl = multiplyMatrices(OKLabtoLMS, OKLab);
	return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3));
}

function OKLab_to_OKLCH(OKLab) {
	var epsilon = 0.000004;
	var hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI;
	var chroma = Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2);
	if (hue < 0) {
		hue = hue + 360;
	}
	if (chroma <= epsilon) {
		hue = NaN;
	}
	return [
		OKLab[0], // L はそのまま L
		chroma,
		hue
	];
}

function OKLCH_to_OKLab(OKLCH) {
	return [
		OKLCH[0], // L はそのまま L
		OKLCH[1] * Math.cos(OKLCH[2] * Math.PI / 180), // a
		OKLCH[1] * Math.sin(OKLCH[2] * Math.PI / 180)  // b
	];
}

// 前乗算アルファ変換(Premultiplied alpha conversions)

function rectangular_premultiply(color, alpha) {
// 直交矩形(直交座標)色空間の色とアルファ値が与えられた場合、
// 前乗算形式を返します
	return color.map((c) => c * alpha)
}

function rectangular_un_premultiply(color, alpha) {
// 前乗算済みの直交色空間の色とアルファ値が与えられた場合、
// 実際の色を返します
	if (alpha === 0) {
		return color; // ゼロ除算を避けるため
	}
	return color.map((c) => c / alpha)
}

function polar_premultiply(color, alpha, hueIndex) {
	// 円筒/極座標(cylindrical/polar)色空間の色とアルファ値が与えられた場合、
	// 前乗算形式を返します。
	// hueIndex は色配列内で色相角に対応するインデックスを示します
	// 例えば OKLCH では 2、HSL では 0 になります
	return color.map((c, i) => c * (hueIndex === i? 1 : alpha))
}

function polar_un_premultiply(color, alpha, hueIndex) {
	// 円筒/極座標色空間の色とアルファ値が与えられた場合、
	// 実際の色を返します。
	// hueIndex は色配列内で色相角に対応するインデックスを示します
	// 例えば OKLCH では 2、HSL では 0 になります
	if (alpha === 0) {
		return color; // ゼロ除算を避けるため
	}
	return color.map((c, i) => c / (hueIndex === i? 1 : alpha))
}

// 利便性のための関数は簡単に定義できます。例えば
function hsl_premultiply(color, alpha) {
	return polar_premultiply(color, alpha, 0);
}

20. 色差公式

この節は規範的ではありません。

20.1. 色差指標の紹介。

色差公式は、2つの色がどの程度異なって見えるかを推定します。 これは品質保証 (再現された色が正しいかどうかの測定) や、一部の種類の色域マッピングに使用でき、 そこでは色域外の色と色域内の色との 色差が最小化されます。

歴史的に、色差公式の一般的な分類は ΔE(デルタE)と呼ばれています。 ここで E は Empfindung の略であり、 「感覚」を意味するドイツ語です。

最も単純な色差指標である ΔE76 は、 単に CIE Lab 色空間におけるユークリッド距離であり、 1976年に初めて国際標準となりました。

ΔE76 は最初の近似としては優れていますが、 印刷や布地染色など色が重要な産業では、 CIE Lab の限界が明らかになるにつれて、 すぐに改良された公式が開発されました。

公式がより複雑になるにつれて、 実用的な実装では、 予測精度と 計算の複雑さ(したがって速度)との間で バランスを取る必要がありました。

20.2. ΔE2000

現在、標準ダイナミックレンジの色に対して 最も広く使用されている公式は ΔE2000 です。 これは ΔE76 と比較して、 既知のさまざまな非対称性や非線形性を補正します。 この公式は複雑であり、 さまざまな中間計算の符号に きわめて強く依存するため、 実装にはしばしば誤りがあります [Sharma]。

以下のサンプルコードは、 検証済みであり、 [Sharma] により公開された Lab 値の組と期待される ΔE2000 のテストスイートに対して、 有効数字5桁まで 正しいことが確認されています。

// deltaE2000 は統計的に有意な改善です
// deltaE76 および deltaE94 と比較して、
// CIE および Idealliance によって推奨されています
// 特に色差が 10 deltaE76 未満の場合に
// ただし、非常に複雑です
// また、多くの実装には小さな誤りがあります!

/**
 * @param {number[]} reference - CIE Lab 値の配列:L は 0..100、a と b はおよそ -150..150
 * @param {number[]} sample - CIE Lab 値の配列:L は 0..100、a と b はおよそ -150..150
 * @return {number} 色サンプルが参照色とどの程度異なるか
 */

function deltaE2000 (reference, sample) {

    // 参照色とサンプル色を指定すると、
    // どちらも CIE Lab であり、
    // deltaE 2000 を計算します。

    // この実装では、パラメトリックな
    // 重み係数 kL、kC、kH
    // (観察条件の影響に対するもの)は
    // 一般的であるように、すべて 1 と仮定します。

    let [L1, a1, b1] = reference;
    let [L2, a2, b2] = sample;
    let C1 = Math.sqrt(a1 ** 2 + b1 ** 2);
    let C2 = Math.sqrt(a2 ** 2 + b2 ** 2);

	let Cbar = (C1 + C2)/2; // 平均彩度

	// 平均彩度から a 軸の非対称係数を計算します
	// これにより、中性色に近い色の JND 楕円が円に戻ります
	let C7 = Math.pow(Cbar, 7);
	const Gfactor = Math.pow(25, 7);
	let G = 0.5 * (1 - Math.sqrt(C7/(C7+Gfactor)));

	// 非対称係数によって a 軸をスケーリングします
	// ちなみに、これが Lab2000 色空間が存在しない理由です
	let adash1 = (1 + G) * a1;
	let adash2 = (1 + G) * a2;

	// スケーリングした a 軸と元の b 軸から新しい彩度を計算します
	let Cdash1 = Math.sqrt(adash1 ** 2 + b1 ** 2);
	let Cdash2 = Math.sqrt(adash2 ** 2 + b2 ** 2);

	// 真の中性色では色相をゼロとして、新しい色相を計算します
	// また、ラジアンではなく度単位にします
	const π = Math.PI;
	const r2d = 180 / π;
	const d2r = π / 180;
	let h1 = (adash1 === 0 && b1 === 0)? 0: Math.atan2(b1, adash1);
	let h2 = (adash2 === 0 && b2 === 0)? 0: Math.atan2(b2, adash2);

	if (h1 < 0) {
		h1 += 2 * π;
	}
	if (h2 < 0) {
		h2 += 2 * π;
	}

	h1 *= r2d;
	h2 *= r2d;

	// 明度と彩度の差。符号が重要です
	let ΔL = L2 - L1;
	let ΔC = Cdash2 - Cdash1;

	// 色相差。符号が正しくなるよう注意します
	let hdiff = h2 - h1;
	let hsum = h1 + h2;
	let habs = Math.abs(hdiff);
	let Δh;

	if (Cdash1 * Cdash2 === 0) {
		Δh = 0;
	}
	else if (habs <= 180) {
		Δh = hdiff;
	}
	else if (hdiff > 180) {
		Δh = hdiff - 360;
	}
	else if (hdiff < -180) {
		Δh = hdiff + 360;
	}
	else {
		console.log("the unthinkable has happened");
	}

	// 重み付けした色相差。彩度が大きいほど重みも大きくします
	let ΔH = 2 * Math.sqrt(Cdash2 * Cdash1) * Math.sin(Δh * d2r / 2);

	// 平均明度と平均彩度を計算します
	let Ldash = (L1 + L2)/2;
	let Cdash = (Cdash1 + Cdash2)/2;
	let Cdash7 = Math.pow(Cdash, 7);

	// Lab の青色領域における非線形性を補正します。
	// 色相の重み係数には4つの可能性があり、
	// 角度に応じて正しい符号が得られるようにします
	let hdash;
	if (Cdash1 * Cdash2 === 0) {
		hdash = hsum;
	}
	else if (habs <= 180) {
		hdash = hsum / 2;
	}
	else if (hsum < 360) {
		hdash = (hsum + 360) / 2;
	}
	else {
		hdash = (hsum - 360) / 2;
	}

	// CIELAB の不均一性に対する位置補正
	// これらはすべて JND 楕円体をより球に近づけようとするものです

	// SL 明度の鮮鋭化係数
	// L=50 の背景を仮定します
	let lsq = (Ldash - 50) ** 2;
	let SL = 1 + ((0.015 * lsq) / Math.sqrt(20 + lsq));

	// SC 彩度係数。CMC および deltaE 94 の公式にあるものと同様です
	let SC = 1 + 0.045 * Cdash;

	// 青色の非線形性に対する交差項 T
	let T = 1;
	T -= (0.17 * Math.cos((     hdash - 30)  * d2r));
	T += (0.24 * Math.cos(  2 * hdash        * d2r));
	T += (0.32 * Math.cos(((3 * hdash) + 6)  * d2r));
	T -= (0.20 * Math.cos(((4 * hdash) - 63) * d2r));

	// SH 色相係数は彩度に依存し、
	// deltaE94 と同様に調整済みの色相角にも依存します。
	let SH = 1 + 0.015 * Cdash * T;

	// RT 色相回転項は JND 楕円の回転を補正します
	// またマンセルの等色相線も補正します
	// 中~高彩度の青色領域において
	// (色相 225~315)
	let Δθ = 30 * Math.exp(-1 * (((hdash - 275)/25) ** 2));
	let RC = 2 * Math.sqrt(Cdash7/(Cdash7 + Gfactor));
	let RT = -1 * Math.sin(2 * Δθ * d2r) * RC;

	// 最後に、二乗和平方根として項ごとに deltaE を計算します
	let dE = (ΔL / SL) ** 2;
	dE += (ΔC / SC) ** 2;
	dE += (ΔH / SH) ** 2;
	dE += RT * (ΔC / SC) * (ΔH / SH);
	return Math.sqrt(dE);
	// やった!!!
};

20.3. ΔEOK

Oklab は CIE Lab の 色相の線形性、色相の均一性、 および彩度の非線形性に関する問題を持たないため、 色差指標でそれらを補正する必要はなく、 したがって ΔEOK は 単に Oklab 色空間におけるユークリッド距離です。

// deltaE OK を計算します
// 単純な二乗和平方根
/**
 * @param {number[]} reference - OKLab 値の配列:L は 0..1、a と b は -1..1
 * @param {number[]} sample - OKLab 値の配列:L は 0..1、a と b は -1..1
 * @return {number} 色サンプルが参照色とどの程度異なるか
 */
function deltaEOK (reference, sample) {
    let [L1, a1, b1] = reference;
	let [L2, a2, b2] = sample;
	let ΔL = L1 - L2;
	let Δa = a1 - a2;
	let Δb = b1 - b2;
	return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2);
}

20.4. ΔEOK2

色差指標として、ΔEOK は 明度の差と比較すると、 色鮮やかさの差を過小評価します。 実験により、 スケーリングとして a と b を係数 2 でスケーリングすると、 ΔE2000 と比較した場合に、Oklab ベースの ΔE の 予測精度が大幅に 向上することが明らかになりました。 現在広く採用されている Oklab の定義を変更する代わりに、 これにより別の距離指標 ΔEOK2 が得られます。

// deltaE OK2 を計算します
// 二乗和平方根。a と b を 2 倍にスケーリングします
/**
 * @param {number[]} reference - OKLab 値の配列:L は 0..1、a と b は -1..1
 * @param {number[]} sample - OKLab 値の配列:L は 0..1、a と b は -1..1
 * @return {number} 色サンプルが参照色とどの程度異なるか
 */
function deltaEOK2 (reference, sample) {
    let [L1, a1, b1] = reference;
	let [L2, a2, b2] = sample;
	let ΔL = L1 - L2;
	let Δa = 2 * (a1 - a2);
	let Δb = 2 * (b1 - b2);
	return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2);
}

20.5. ΔEOKr2

明度軸を変更して 「トー」を 追加することで、さらに改善できます。 これは、白色の順応刺激が 大きい場合に特に有効です (たとえば、白い背景を持つライトモードのウェブページ)。 また、明度曲線が CIE Lab のものにより近くなります。

Oklab と比較した Oklrab および CIE Lab の明度関数。

色差指標では、 これは a と b のスケーリングと組み合わせて使用されます。

これは元の ΔEOK よりいくらか複雑ですが、 ΔE2000 とは大幅によく一致し、 それでも ΔE2000 よりはるかに単純です。

性能が重視される実装では、 色差指標として ΔEOKr2 を使用することが推奨されます。

// deltaE OKr2 を計算します
// 二乗和平方根。明度のトーを適用し、a と b を 2 倍にスケーリングします
/**
 * @param {number[]} reference - OKLab 値の配列:L は 0..1、a と b は -1..1
 * @param {number[]} sample - OKLab 値の配列:L は 0..1、a と b は -1..1
 * @return {number} 色サンプルが参照色とどの程度異なるか
 */
function deltaEOKr2 (reference, sample) {
    let [L1, a1, b1] = reference;
	let [L2, a2, b2] = sample;
	L1 = toe(L1);
	L2 = toe(L2);
	let ΔL = L1 - L2;
	let Δa = 2 * (a1 - a2);
	let Δb = 2 * (b1 - b2);
	return Math.sqrt(ΔL ** 2 + Δa ** 2 + Δb ** 2);
}

// 明度のトーを追加します
// https://bottosson.github.io/posts/colorpicker/#intermission---a-new-lightness-estimate-for-oklab
/**
 * @param {number} x - Oklab の明度
 * @return {number} トーを適用した明度
 */
function toe (x) {
	const K1 = 0.206;
	const K2 = 0.03;
	const K3 = (1.0 + K1) / (1.0 + K2);
	return 0.5 * (K3 * x - K1 + Math.sqrt((K3 * x - K1) * (K3 * x - K1) + 4 * K2 * K3 * x));
}

付録A: 廃止されたCSSシステムカラー

以前のバージョンのCSSでは、いくつかの追加のシステム色が定義されていました。 しかし、これらの色キーワードは、 本来の目的 (ウェブサイトの要素をネイティブOSの対応要素のように見せること)には不十分であり、 ウェブページがネイティブOSのダイアログを「偽装」しやすくすることで セキュリティ上のリスクをもたらし、 フィンガープリンティングの対象範囲を拡大してユーザーのプライバシーを損なうため、 非推奨となっています。

ユーザーエージェントはこれらのキーワードをサポートしなければならず、 フィンガープリンティングを軽減するため、 以下に示すように、これらを(非推奨ではない)システム色へ マッピングしなければなりません。 作者はこれらのキーワードを使用してはなりません。

非推奨のシステム色は、 <deprecated-color> サブタイプとして表され、 次のように定義されます。

ActiveBorder
アクティブウィンドウの境界線。ButtonBorderの色に算出される。
ActiveCaption
アクティブウィンドウのキャプション。Canvasの色に算出される。
AppWorkspace
マルチドキュメントインターフェイスの背景色。Canvasの色に算出される。
Background
デスクトップの背景。Canvasの色に算出される。
ButtonHighlight
周囲の1層の境界線によって立体的に見える3D要素について、 光源に面する側の境界線の色。ButtonFaceの色に算出される。
ButtonShadow
周囲の1層の境界線によって立体的に見える3D要素について、 光源から離れた側の境界線の色。ButtonFaceの色に算出される。
CaptionText
キャプション、サイズ変更ボックス、およびスクロールバーの矢印ボックス内のテキスト。CanvasTextの色に算出される。
InactiveBorder
非アクティブウィンドウの境界線。ButtonBorderの色に算出される。
InactiveCaption
非アクティブウィンドウのキャプション。Canvasの色に算出される。
InactiveCaptionText
非アクティブなキャプション内のテキストの色。GrayTextの色に算出される。
InfoBackground
ツールチップコントロールの背景色。Canvasの色に算出される。
InfoText
ツールチップコントロールのテキスト色。CanvasTextの色に算出される。
Menu
メニューの背景。Canvasの色に算出される。
MenuText
メニュー内のテキスト。CanvasTextの色に算出される。
Scrollbar
スクロールバーの灰色の領域。Canvasの色に算出される。
ThreeDDarkShadow
周囲の2層の同心境界線によって立体的に見える3D要素について、 光源から離れた側にある2つの境界線のうち、より暗い方(通常は外側)の色。ButtonBorderの色に算出される。
ThreeDFace
周囲の2層の同心境界線によって立体的に見える3D要素の 表面の背景色。ButtonFaceの色に算出される。
ThreeDHighlight
周囲の2層の同心境界線によって立体的に見える3D要素について、 光源に面する側にある2つの境界線のうち、より明るい方(通常は外側)の色。ButtonBorderの色に算出される。
ThreeDLightShadow
周囲の2層の同心境界線によって立体的に見える3D要素について、 光源に面する側にある2つの境界線のうち、より暗い方(通常は内側)の色。ButtonBorderの色に算出される。
ThreeDShadow
周囲の2層の同心境界線によって立体的に見える3D要素について、 光源から離れた側にある2つの境界線のうち、より明るい方(通常は内側)の色。ButtonBorderの色に算出される。
Window
ウィンドウの背景。Canvasの色に算出される。
WindowFrame
ウィンドウの枠。ButtonBorderの色に算出される。
WindowText
ウィンドウ内のテキスト。CanvasTextの色に算出される。

付録B: 廃止されたクァーキー16進カラー

CSS が quirks mode で解析されるとき、 <quirky-color> は <color> の一種であり、 特定のプロパティでのみ有効である:

これらのプロパティを含む、または参照するプロパティ、 例えば background ショートハンドや、 関数表記の内側 (例えば color-mix()) では有効ではない。

さらに、<quirky-color> は、 <color> として影響を受けるプロパティを解析する際、 @supports ルール内では有効でなければならないが、 CSS.supports() メソッドで使う場合は、 それらのプロパティに対して有効ではない。

<quirky-color> は、 以下の規則に従って <number-token>、<dimension-token>、または <ident-token> として表現できる:

(言い換えると、Quirks Mode では先頭の "#" なしで hex カラーを書けるが、 そのパース規則は奇妙である。)

謝辞

CSS Color 3に貢献した方々に加え、編集者は Emilio Cobos Álvarez、Alexey Ardov、Chris Bai、Amelia Bellamy-Royds、Lars Borg、Mike Bremford、Andreu Botella、Dan Burzo、Max Derhak、fantasai、Simon Fraser、Devon Govett、Phil Green、Dean Jackson、Andreas Kraushaar、Pierre-Anthony Lemieux、Tiaan Louw、Cameron McCormack、Romain Menke、Chris Murphy、Isaac Muse、 Jonathan Neal、Chris Needham、Björn Ottosson、Christoph Päper、Brad Pettit、Xidorn Quan、Craig Revie、 Melanie Richards、Florian Rivoal、Jacob Rus、Joseph Salowey、Simon Sapin、Igor Snitkin、Lea Verou、Mark Watson、James Stuckey Weber、Sam Weinig、Natalie Weizenbaumに感謝します。

変更点

2025年4月24日の候補勧告草案から の変更点

2024年2月13日の勧告案ドラフト以降の変更点

2022年11月1日の勧告案ドラフト以降の変更点

2022年7月5日の勧告案以降の変更点

2022年6月28日の草案以降の変更点

2022年4月28日の草案以降の変更点

2021年12月15日の草案以降の変更点

2021年6月1日の草案以降の変更点

2020年11月12日の草案以降の変更点

2019年11月5日の草案以降の変更点

2016年7月5日の草案以降の変更点

Colors 3からの主な変更点

CSS Color 3 と比較した主な変更点は、 CSS の色がもはや sRGB の狭い色域に制限されないことである。

これをサポートするため、いくつかのまったく新しい機能が追加された。

  1. 定義済みの広色域 RGB 色空間
  2. デバイス非依存色のための lab()、lch()、oklab() および oklch() 関数

その他の技術的変更:

  1. <color> のシリアル化は、CSS Object Model ではなく、ここで規定されるようになった
  2. HWB 表記で sRGB 色を指定するための hwb() 関数。
  3. 名前付き色 rebeccapurple を追加。

さらに、いくつかの構文上の変更も行われた。

  1. rgb() および rgba() 関数は、<integer> ではなく、<number> を受け入れるようになった。
  2. hsl() および hsla() 関数は、色相について <number> に加えて <angle> も 受け入れるようになった。
  3. rgb() と rgba()、および hsl() と hsla() は、 それぞれ相互のエイリアスとなった (すべてでアルファが省略可能である)。
  4. rgb()、rgba()、hsl()、および hsla() は すべて、空白で区切られた引数と 省略可能なスラッシュ区切りの不透明度からなる 新しい構文を使用できるようになった。 すべての色関数は現在、この構文形式を使用しており、 CSS の 関数記法の設計原則に従っている。
  5. <alpha-value> のすべての使用箇所で、<number> に加えて <percentage> も受け入れるようになった。
  6. 透明度を指定するため、4桁および8桁の16進数色が追加された。
  7. 無力な成分を表すため、none 値が追加された。

21. セキュリティ上の考慮事項

システムカラーは、 実際にユーザーのシステムカラーに対応している場合、 セキュリティリスクとなります。 これは悪意のあるサイトが システムのUIのようなインターフェースを作りやすくなるためです。 ただし、現行のシステムカラーは「汎用的」に定義されているため、 このリスクは軽減されていると考えられます。

22. プライバシー上の考慮事項

本仕様は「システム」カラーを定義しており、 理論上ユーザーのOS設定の詳細を露出させる可能性があり、 これはフィンガープリントリスクとなります。

23. アクセシビリティ上の考慮事項

本仕様は、区別のために色だけを使わないことを作者に推奨しています。

本仕様は、特定のシステムカラーの前景/背景ペアで十分なコントラストを確保するようブラウザに推奨しています。 AAやAAAのコントラスト比などの厳格な要件も検討されましたが、 ブラウザはしばしばOSやユーザーが選択した色をそのまま使うため、 (片頭痛やてんかんなどのため低コントラストを求めるケースも含め)CSSWGとしては特定のコントラスト水準を義務付けられませんでした。

適合性

文書の慣例

適合性要件は、記述的な断定とRFC 2119用語の組み合わせで表現されます。規範部分で使われる「MUST」「MUST NOT」「REQUIRED」「SHALL」「SHALL NOT」「SHOULD」「SHOULD NOT」「RECOMMENDED」「MAY」「OPTIONAL」のキーワードはRFC 2119の説明通りに解釈されます。 ただし、可読性のため、この仕様書ではこれらの言葉をすべて大文字にはしていません。

この仕様書の本文は、明示的に非規範と示された部分、例、注記以外はすべて規範的です。[RFC2119]

この仕様書の例は「例えば」で始まるか、class="example"で規範的テキストと区別されます。例:

これは情報提供的な例です。

情報提供的な注記は「Note」で始まり、class="note"で規範的テキストと区別されます。例:

Note、これは情報提供的な注記です。

助言事項は特に注意喚起するための規範セクションで、<strong class="advisement">で他の規範テキストと区別されます。例: UAは必ずアクセシブルな代替手段を提供しなければなりません。

適合クラス

この仕様への適合性は、3つの適合クラスで定義されます:

スタイルシート
CSSスタイルシート。
レンダラー
UA(ユーザーエージェント)。スタイルシートの意味を解釈し、それを用いた文書をレンダリングするもの。
オーサリングツール
UA(ユーザーエージェント)。スタイルシートを書くツール。

スタイルシートが本仕様に準拠するには、このモジュールで定義された構文を用いたすべての記述が、汎用CSS文法および各機能の個別文法に従い有効である必要があります。

レンダラーが本仕様に準拠するには、スタイルシートを関連仕様通りに解釈することに加え、本仕様で定義された全機能を正しくパースし、文書をそれに従ってレンダリングする必要があります。ただし、デバイスの制約によって文書を正しくレンダリングできない場合でもUAが非適合になるわけではありません(例:モノクロモニターで色のレンダリングは必須ではない)。

オーサリングツールが本仕様に準拠するには、スタイルシートを汎用CSS文法および本モジュール各機能の個別文法に従い構文的に正しく記述し、かつ本モジュールで記載されるスタイルシートの他の適合要件も満たす必要があります。

部分的な実装

作者が将来互換のパース規則を利用してフォールバック値を指定できるよう、CSSレンダラーは、使えるレベルのサポートがない@規則・プロパティ・値・キーワードその他構文要素を必ず無効として(適切に無視)扱わなければなりません。特に、ユーザーエージェントは、単一の複数値プロパティ宣言でサポートされない構成値のみを選択的に無視してサポートされる値のみを適用してはなりません:いずれかの値が無効(サポートされない値なら必ず無効扱い)と判断された場合、CSSでは宣言全体を無視する必要があります。

不安定・独自機能の実装

将来の安定CSS機能との衝突を避けるため、CSSWGはベストプラクティスに従って、不安定な機能や独自拡張の実装を推奨します。

非実験的な実装

仕様がCandidate Recommendation段階に達すると、非実験的な実装が可能となり、実装者は仕様通りに正しく実装できているCRレベルの機能については、プレフィックス無しで公開すべきです。

CSSの互換性維持のため、CSSワーキンググループは非実験的なCSSレンダラーに対し、プレフィックス無しの実装をリリースする前にW3Cへ実装報告書(必要ならテストケースも)を提出するよう要請しています。W3Cに提出されたテストケースはCSSWGによりレビュー・訂正される場合があります。

テストケースや実装報告書の提出方法については、CSSワーキンググループのhttps://www.w3.org/Style/CSS/Test/に記載されています。 質問はpublic-css-testsuite@w3.orgのメーリングリストまで。

CR終了基準

本仕様をProposed Recommendationへ進めるには、各機能について少なくとも2つの独立かつ相互運用可能な実装が必要です。各機能は異なる製品セットで実装されてもよく、すべての機能が単一製品で実装される要件はありません。以下の用語について定義します:

独立
各実装は異なる組織が開発し、他の適格実装のコードを共有・再利用・派生してはならない。仕様実装に無関係なコード部分は除外されます。
相互運用可能
公式CSSテストスイートの該当テストケースに合格する、またはWebブラウザでない場合は同等のテストに合格すること。同等のテストを使うUAは他にも同じ方法でそのテストに合格できるUAが必要。等価テストはピアレビューのため公開されていなければならない。
実装
ユーザーエージェントであり、以下を満たす:
  1. 仕様を実装している。
  2. 一般公開されている。リリース製品・ベータ版・プレビュー・ナイトリービルドいずれでもよい。非リリース製品は少なくとも1ヶ月間機能を実装して安定性を示す必要あり。
  3. 実験的でない(テスト合格専用設計のバージョンでなく、今後も通常利用されるもの)。

仕様は少なくとも6ヶ月間Candidate Recommendationとして維持されます。

索引

本仕様で定義される用語

参照定義用語

参考文献

規範的参考文献

[Bradford-CAT]
Ming R. Luo; R. W. G. Hunt. 色順応変換と色非恒常性指数。色彩 研究と応用 23(3) 154-158. 1998年6月.
[CIELAB]
ISO/CIE 11664-4:2019(E): 測色 — 第4部:CIE 1976 L*a*b* 色空間. 2019年. 公開済み. URL: http://cie.co.at/publications/colorimetry-part-4-cie-1976-lab-colour-space-1
[COLORIMETRY]
測色、第4版。CIE 015:2018. 2018年. URL: http://www.cie.co.at/publications/colorimetry-4th-edition
[Compositing]
Chris Harrelson. 合成と混合 レベル 1. 2024年3月21日. CRD. URL: https://www.w3.org/TR/compositing-1/
[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper. CSS 背景と 境界線モジュール レベル 3. 2024年3月11日. CRD. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS カスケードと継承 レベル 5. 2022年1月13日. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-COLOR-5]
Chris Lilley; Una Kravets; Lea Verou. CSS カラーモジュール レベル 5. 2026年9月13日. WD. URL: https://www.w3.org/TR/css-color-5/
[CSS-COLOR-ADJUST-1]
Elika Etemad; et al. CSS 色調整モジュール レベル 1. 2025年12月16日. CR. URL: https://www.w3.org/TR/css-color-adjust-1/
[CSS-CONDITIONAL-3]
Chris Lilley; David Baron; Elika Etemad. CSS 条件付き規則モジュール レベル 3. 2024年8月15日. CRD. URL: https://www.w3.org/TR/css-conditional-3/
[CSS-SHAPES-1]
Alan Stearns; Rossen Atanassov; Noam Rosenthal. CSS シェイプモジュール レベル 1. 2025年6月12日. CRD. URL: https://www.w3.org/TR/css-shapes-1/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS 構文モジュール レベル 3. 2026年10月1日. CRD. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-TEXT-DECOR-4]
Elika Etemad; Koji Ishii. CSS テキスト装飾モジュール レベル 4. 2022年5月4日. WD. URL: https://www.w3.org/TR/css-text-decor-4/
[CSS-UI-4]
Tab Atkins Jr.; Florian Rivoal. CSS 基本ユーザーインターフェイス モジュール レベル 4. 2026年1月20日. WD. URL: https://www.w3.org/TR/css-ui-4/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS 値と単位 モジュール レベル 3. 2024年3月22日. CRD. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 値と単位 モジュール レベル 4. 2024年3月12日. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS2]
Bert Bos; et al. カスケーディングスタイルシート レベル 2 改訂 1 (CSS 2.1) 仕様. 2011年6月7日. REC. URL: https://www.w3.org/TR/CSS2/
[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS オブジェクトモデル (CSSOM). 2021年8月26日. WD. URL: https://www.w3.org/TR/cssom-1/
[Display-P3]
Apple, Inc. Display P3. 2022-02. URL: https://www.color.org/chardata/rgb/DisplayP3.xalter
[DOM]
Anne van Kesteren. DOM 標準. 現行標準. URL: https://dom.spec.whatwg.org/
[HSL]
George H. Joblove, Donald Greenberg. コンピューターグラフィックスのための 色空間. 1978年8月. URL: https://doi.org/10.1145/965139.807362
[HTML]
Anne van Kesteren; et al. HTML 標準. 現行標準. URL: https://html.spec.whatwg.org/multipage/
[HWB]
Alvy Ray Smith. HWB — より直感的な 色相ベースのカラーモデル. 1996年. URL: http://alvyray.com/Papers/CG/HWB_JGTv208.pdf
[ICC]
ICC.1:2022 (プロファイルバージョン 4.4.0.0). 2022年5月. URL: http://www.color.org/specification/ICC.1-2022-05.pdf
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 標準. 現行標準. URL: https://infra.spec.whatwg.org/
[ITU-R-BT.601]
ITU-R BT.601 勧告. URL: https://www.itu.int/rec/R-REC-BT.601/en
[ITU-R-BT.709]
ITU-R BT.709 勧告. URL: https://www.itu.int/rec/R-REC-BT.709/en
[MEDIAQUERIES-5]
Tab Atkins Jr.; et al. メディアクエリー レベル 5. 2026年2月19日. WD. URL: https://www.w3.org/TR/mediaqueries-5/
[Oklab]
Björn Ottosson. 画像 処理のための知覚的色空間. 2020年12月. URL: https://bottosson.github.io/posts/oklab/
[Rec.2020]
ITU-R BT.2020-2 勧告:超高精細テレビシステムの 制作および国際番組交換のためのパラメーター 値. 2015年10月. URL: http://www.itu.int/rec/R-REC-BT.2020/en
[RFC2119]
S. Bradner. RFC で要求レベルを 示すために使用するキーワード. 1997年3月. 現行のベストプラクティス. URL: https://datatracker.ietf.org/doc/html/rfc2119
[ROMM]
ISO 22028-2:2013 写真およびグラフィック技術 — デジタル画像の保存、操作、交換のための拡張色符号化 — 第2部: 基準出力媒体測色 RGB カラー画像符号化 (ROMM RGB). 2013-04. URL: https://www.iso.org/standard/56591.html
[SMPTE296]
ST 296:2012, 1280 × 720 プログレッシブ画像 4:2:2 および 4:4:4 サンプル構造 — アナログおよびデジタル表現とアナログインターフェイス. 5月17日 2012年. 標準. URL: https://doi.org/10.5594/SMPTE.ST296.2012
[SRGB]
マルチメディアシステムおよび機器 - 色の 測定と管理 - 第2-1部:カラーマネジメント - デフォルト RGB 色空間 - sRGB. URL: https://webstore.iec.ch/publication/6169
[SVG11]
Erik Dahlström; et al. スケーラブルベクターグラフィックス (SVG) 1.1 (第2版). 2011年8月16日. REC. URL: https://www.w3.org/TR/SVG11/

情報提供的参考文献

[Abney]
アブニー効果。URL: https://en.wikipedia.org/wiki/Abney_effect
[Coloraide-MINDE]
Isaac Muse. OkLCh クロマ.2024年.URL: https://facelessuser.github.io/coloraide/gamut/#oklch-chroma
[Coloraide-Ray-Trace]
Isaac Muse. Ray Tracing クロマ削減.2024年.URL: https://facelessuser.github.io/coloraide/gamut/#ray-tracing-chroma-reduction
[colorjs-EdgeSeeker]
Alexey Ardov. EdgeSeeker 色域マッピングアルゴリズム. 2023年. URL: https://github.com/color-js/apps/tree/main/gamut-mapping/methods/edge-seeker
[colorjs-MINDE]
Chris Lilley. ガマットマッピング.2022年.URL: https://colorjs.io/docs/gamut-mapping
[colorjs-RayTrace]
Isaac Muse. レイトレース・ガマットマッピング.2023年.URL: https://github.com/color-js/apps/blob/2c7346dd00855f7b82eb4c7527355a09b84beeb3/gamut-mapping/methods.js#L273
[CSS-ANIMATIONS-1]
David Baron ほか. CSS Animations Level 1.2023年3月2日.WD.URL: https://www.w3.org/TR/css-animations-1/
[CSS-CONDITIONAL-5]
Chris Lilley ほか.CSS Conditional Rules Module Level 5.2025年10月30日.WD.URL: https://www.w3.org/TR/css-conditional-5/
[CSS-IMAGES-4]
Elika Etemad; Tab Atkins Jr.; Lea Verou. CSS Images Module Level 4.2025年9月30日.WD.URL: https://www.w3.org/TR/css-images-4/
[CSS-TRANSITIONS-1]
Chris Marrin ほか. CSS Transitions Module Level 1.2026年1月8日.WD.URL: https://www.w3.org/TR/css-transitions-1/
[CSS3-TEXT-DECOR]
Elika Etemad; Koji Ishii. CSS Text Decoration Module Level 3.2022年5月5日.CRD.URL: https://www.w3.org/TR/css-text-decor-3/
[DCI-P3]
SMPTE 推奨規格 - D-Cinema 品質 — 参照用プロジェクターおよび環境.2011年.URL: http://ieeexplore.ieee.org/document/7290729/
[FILTER-EFFECTS-1]
Dirk Schulze; Dean Jackson. Filter Effects Module Level 1.2018年12月18日.WD.URL: https://www.w3.org/TR/filter-effects-1/
[JPEG]
Eric Hamilton. JPEG ファイルインターチェンジ フォーマット.1992年9月.URL: https://www.w3.org/Graphics/JPEG/jfif3.pdf
[PNG]
Chris Lilley ほか. Portable Network Graphics (PNG) 仕様(第3版).2025年6月24日.REC.URL: https://www.w3.org/TR/png-3/
[REC_BT.1886]
ITU-R BT.1886 リファレンス電気-光転送関数 HDTVスタジオ制作に使用されるフラットパネルディスプレイのための.2011-03.URL: https://www.itu.int/rec/R-REC-BT.1886/en
[ROMM-RGB]
ROMM RGB.URL: https://www.color.org/chardata/rgb/rommrgb.xalter
[Sharma]
G. Sharma; W. Wu; E. N. Dalal. CIEDE2000 色差 数式:解説ノート、補足テストデータ、および数理的考察.2005年2月.URL: https://www.hajim.rochester.edu/ece/sites/gsharma/ciede2000/
[TIFF]
TIFF 改訂 6.0.1992年6月3日.URL: https://www.loc.gov/preservation/digital/formats/fdd/fdd000022.shtml
[Understanding_CCT]
CCTとは?あなたの照明に最適な相関色温度を選ぶためのガイド.2024年8月14日.URL: https://litomatic.com/blog/what-is-cct-in-lighting/
[WCAG21]
Michael Cooper ほか. ウェブコンテンツ アクセシビリティ ガイドライン (WCAG) 2.1.2025年5月6日.REC.URL: https://www.w3.org/TR/WCAG21/
[Wolfe]
Geoff Wolfe. ProPhoto RGB カラー符号化の設計と最適化.2011年12月21日.URL: http://www.realtimerendering.com/blog/2011-color-and-imaging-conference-part-vi-special-session/

プロパティ索引

名前 値 初期値 適用対象 継承 %値 アニメーションタイプ 正規順序 算出値
color <color> CanvasText すべての要素とテキスト はい N/A 算出値の型による 文法による 算出色(色値の解決を参照)
opacity <opacity-value> 1 すべての要素 いいえ [0,1]範囲にマッピング 算出値の型による 文法による 指定数値([0,1]範囲にクランプ)