CSS Color Module Level 4

Editor’s Draft,

Specification Metadata
This version:
https://drafts.csswg.org/css-color/
Latest published version:
https://www.w3.org/TR/css-color-4/
Previous Versions:
Test Suite:
http://test.csswg.org/suites/css-color-4_dev/nightly-unstable/
Issue Tracking:
Inline In Spec
GitHub Issues
Editors:
Tab Atkins Jr. (Google)
(W3C)
Former Editor:
L. David Baron (Mozilla)
Suggest an Edit for this Spec:
GitHub Editor

Abstract

This specification describes CSS <color> values and properties for foreground color and group opacity.

CSS is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, etc.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

GitHub Issues are preferred for discussion of this specification. When filing an issue, please put the text “css-color” in the title, preferably like this: “[css-color] …summary of comment…”. All issues and comments are archived, and there is also a historical archive.

This document was produced by the CSS Working Group.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 March 2019 W3C Process Document.

1. Introduction

This section is not normative.

This module describes CSS properties which allow authors to specify the foreground color and opacity of the text content of an element. This module also describes in detail the CSS <color> value type.

It not only defines the color-related properties and values that already exist in CSS1, CSS2, and CSS Color 3, but also defines new properties and values.

In particular, it allows specifying colors in other colorspaces than sRGB; previously, the more saturated colors ouside the sRGB gamut could not be used in CSS even if the display device supported them. In addition to the family of RGB colorspaces, colorspaces with other primaries such as CMYK or CMYGOVK are supported.

1.1. Value Definitions

This specification follows the CSS property definition conventions from [CSS2] using the value definition syntax from [CSS-VALUES-3]. Value types not defined in this specification are defined in CSS Values & Units [CSS-VALUES-3]. Combination with other CSS modules may expand the definitions of these value types.

In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the CSS-wide keywords keywords as their property value. For readability they have not been repeated explicitly.

2. Color terminology

A color is a definition (numeric or textual) of the human visual perception of a light or a physical object illuminated with light. The objective study of human color perception is termed colorimetry. If two objects have different spectra, but produce the same physical sensation, we say they have the same color.

For example a green leaf, a photograph of that leaf displayed on a computer screen, and a print of that photograph, are all producing a green sensation by different means. If the screen and the printer are calibrated, the green in the leaf, and the photo, and the print will look the same.

A colorspace is an organization of colors with respect to an underlying colorimetric model, such that there is a clear, objectively-measurable meaning for any color in that colorspace. This also means that the same color can be expressed in multiple colorspaces, or transformed from one colorspace to another, while looking the same.

A leaf is measured with a spectrophotometer and found to have the color lch(51.2345% 21.2 130) which is lab(51.2345% -13.6271 16.2401).

This same color could be expressed in various colorspaces:

 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);

When the measured physical characteristics (such as the chromaticities of the primary colors it uses, or the colors produced in response to a given set of inputs) of a colorspace or a color-producing device are known, it is said to be characterized. This characterization information is stored in a profile. The most common type of color profile is defined by the International Color Consortium (ICC) [ICC].

If in addition adjustments have been made so that a device meets calibration targets such as white point, neutrality of greys, predictability and consistency of tone response, then it is said to be calibrated.

Real physical devices cannot yet produce every possible color that the human eye can see. The range of colors that a given device can produce is termed the gamut (not to be confused with gamma). Devices with a limited gamut cannot produce very saturated colors, like those found in a rainbow.

The gamuts of different colorspaces may be compared by looking at the volume (in cubic LAB units) of colors that can be expressed. The following table examines the predefined colorspaces available in CSS.

Colorspace Volume (million Lab units)
sRGB 0.820
display-p3 1.233
a98-rgb 1.310
prophoto-rgb 2.896
rec2020 2.042
lab 6.578

3. Foreground Color: the color property

Name: color
Value: <color>
Initial: CanvasText
Applies to: all elements
Inherited: yes
Percentages: N/A
Computed value: computed color, see resolving color values
Canonical order: per grammar
Animation type: by computed value type

This property describes the foreground fill color of an element’s text content. In addition, it provides the value that currentcolor resolves to.

There are several different ways to syntactically specify a given color.

For example, to specify lime green:
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% */
<color>
The <color> type is defined in a later section.

Note: In general, this property, including its alpha component, has no effect on "color glyphs", such as emoji in some fonts, which are colored by a built-in palette. Some colored fonts are able to refer to the foreground color, such as palette entry 0xFFFF in COLR table of OpenType, and context-fill value in SVG-in-OpenType. In that case, the foreground color is set by this property, identical to how currentcolor value works.

4. Representing Colors: the <color> type

CSS has several syntaxes for specifying color values. Some directly specify an sRGB color by its channels, such as the hex color notation or rgb() function. Others are more human-friendly to write and understand, such as the hsl() and lch() functions, or the long list of named colors.

Colors are represented as a list of components, also sometimes called “channels”, representing axises in the color space. Each channel has a minimum and maximum value, and can take any value between those two. Additionally, every color is accompanied by an alpha component, indicating how transparent it is, and thus how much of the backdrop one can see behind the color.

Colors in CSS are represented by the <color> type:

<color> = <hex-color> | <named-color> | currentcolor | transparent
          <rgb()> | <rgba()> | <hsl()> | <hsla()> | <hwb()> |
          <lab()> | <lch()> |
          <color()> | <device-cmyk()> |
          <system-color>

The color-functions are , ,

, , , , , , and .

For easy reference in other specifications, opaque black is defined as the color rgb(0 0 0 / 100%); transparent black is the same color, but fully transparent—i.e. rgb(0 0 0 / 0%).

4.1. Accessibility and Conveying Information By Color

Although colors can add significant information to documents and make them more readable, color by itself should not be the sole means to convey important information. Authors should consider the W3C Web Content Accessibility Guidelines [WCAG20] when using color in their documents.

1.4.1 Use of Color: Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element

4.2. Color Spaces of Untagged Colors

Colors specified in HTML and untagged images are in the sRGB color space ([SRGB]) unless otherwise specified.

An untagged image is an image that is not explicitly assigned a color profile, as defined by the image format.

Note that this rule does not apply to videos, since untagged video should be presumed to be in ITU.

4.3. Resolving <color> Values

Unless otherwise specified for a particular property, specified colors are resolved to computed colors and then further to used colors as follows:

transparent

The computed and used value is transparent black.

hex colors
rgb() and rgba() values
hsl() and hsla() values
hwb() values
named colors

The computed and used value is the corresponding sRGB color paired with the specified alpha channel (defaulting to opaque if unspecified).

lab() and lch() values

The computed and used value is the corresponding CIE Lab color paired with the specified alpha channel (defaulting to opaque if unspecified).

Does working color space affect these values? <https://github.com/w3c/csswg-drafts/issues/3844>

color() values

The computed and used value is the color in the specified colorspace, paired with the specified alpha channel (defaulting to opaque if unspecified).

device-cmyk() values

The computed and used value is the specified device-specific CMYK color, paired with the specified alpha channel (defaulting to opaque if unspecified).

The actual value can vary based on the operation; for rendering to a CMYK-capable device, it may be rendered as a CMYK color; for blending with non-CMYK colors or rendering to a non-CMYK device, it must be converted as specified in § 12 Device-dependent CMYK Colors: the device-cmyk() function.

system colors

Each <system-color> keyword computes to itself. Its used value is the corresponding color in its color space.

Define something for <deprecated-system-color>? <https://github.com/w3c/csswg-drafts/issues/3873>

currentcolor

The currentcolor keyword computes to itself.

In the color property, its used value is the inherited value. In any other property, its used value is the used value of the color property on the same element.

Note: This means that if the currentcolor value is inherited, it’s inherited as a keyword, not as the value of the color property, so descendants will use their own color property to resolve it.

The resolved value of a <color> is its used value.

When should channel-clamping occur? <https://github.com/w3c/csswg-drafts/issues/3845>

5. sRGB Colors

CSS colors in the sRGB color space are represented by a triplet of values—red, green, and blue—identifying a point in the sRGB color space [SRGB]. This is an internationally-recognized, device-independent color space, and so is useful for specifying colors that will be displayed on a computer screen, but is also useful for specifying colors on other types of devices, like printers.

CSS also allows the use of non-sRGB colorspaces, as described in § 10.2 Predefined colorspaces: srgb, display-p3, a98-rgb, prophoto-rgb and rec2020..

CSS provides several methods of directly specifying an sRGB color: hex colors, rgb()/rgba() color-functions, hsl()/hsla() color-functions, hwb() color-function, named colors, and the transparent keyword.

5.1. The RGB functions: rgb() and rgba()

The rgb() function defines an sRGB color by specifying the red, green, and blue channels directly. Its syntax is:

rgb() = rgb( <percentage>{3} [ / <alpha-value> ]? ) |
        rgb( <number>{3} [ / <alpha-value> ]? )
<alpha-value> = <number> | <percentage>

The first three arguments specify the red, green, and blue channels of the color, respectively. 0% represents the minimum value for that color channel in the sRGB gamut, and 100% represents the maximum value. A <number> is equivalent to a <percentage>, but with a different range: 0 again represents the minimum value for the color channel, but 255 represents the maximum. These values come from the fact that many graphics engines store the color channels internally as a single byte, which can hold integers between 0 and 255. Implementations should honor the precision of the channel as authored or calculated wherever possible. If this is not possible, the channel should be rounded to the closest value at the highest precision used, rounding up if two values are equally close.

The final argument, the <alpha-value>, specifies the alpha of the color. If given as a <number>, the useful range of the value is 0 (representing a fully transparent color) to 1 (representing a fully opaque color). If given as a <percentage>, 0% represents a fully transparent color, while 100% represents a fully opaque color. If omitted, it defaults to 100%.

Values outside these ranges are not invalid, but are clamped to the ranges defined here at computed-value time.

For legacy reasons, rgb() also supports an alternate syntax that separates all of its arguments with commas:

rgb() = rgb( <percentage>#{3} , <alpha-value>? ) |
        rgb( <number>#{3} , <alpha-value>? )

Also for legacy reasons, an rgba() function also exists, with an identical grammar and behavior to rgb().

5.2. The RGB hexadecimal notations: #RRGGBB

The CSS hex color notation allows an sRGB color to be specified by giving the channels as hexadecimal numbers, which is similar to how colors are often written directly in computer code. It’s also shorter than writing the same color out in rgb() notation.

The syntax of a <hex-color> is a <hash-token> token whose value consists of 3, 4, 6, or 8 hexadecimal digits. In other words, a hex color is written as a hash character, "#", followed by some number of digits 0-9 or letters a-f (the case of the letters doesn’t matter - #00ff00 is identical to #00FF00).

The number of hex digits given determines how to decode the hex notation into an RGB color:

6 digits
The first pair of digits, interpreted as a hexadecimal number, specifies the red channel of the color, where 00 represents the minimum value and ff (255 in decimal) represents the maximum. The next pair of digits, interpreted in the same way, specifies the green channel, and the last pair specifies the blue. The alpha channel of the color is fully opaque.
In other words, #00ff00 represents the same color as rgb(0 255 0) (a lime green).
8 digits
The first 6 digits are interpreted identically to the 6-digit notation. The last pair of digits, interpreted as a hexadecimal number, specifies the alpha channel of the color, where 00 represents a fully transparent color and ff represent a fully opaque color.
In other words, #0000ffcc represents the same color as rgb(0 0 100% / 80%) (a slightly-transparent blue).
3 digits
This is a shorter variant of the 6-digit notation. The first digit, interpreted as a hexadecimal number, specifies the red channel of the color, where 0 represents the minimum value and f represents the maximum. The next two digits represent the green and blue channels, respectively, in the same way. The alpha channel of the color is fully opaque.
This syntax is often explained by saying that it’s identical to a 6-digit notation obtained by "duplicating" all of the digits. For example, the notation #123 specifies the same color as the notation #112233. This method of specifying a color has lower "resolution" than the 6-digit notation; there are only 4096 possible colors expressible in the 3-digit hex syntax, as opposed to approximately 17 million in 6-digit hex syntax.
4 digits
This is a shorter variant of the 8-digit notation, "expanded" in the same way as the 3-digit notation is. The first digit, interpreted as a hexadecimal number, specifies the red channel of the color, where 0 represents the minimum value and f represents the maximum. The next three digits represent the green, blue, and alpha channels, respectively.

6. Color Keywords

In addition to the various numeric syntaxes for <color>s, CSS defines several sets of color keywords that can be used instead—each with their own advantages or use cases.

6.1. Named Colors

CSS defines a large set of named colors, so that common colors can be written and read more easily. A <named-color> is written as an <ident>, accepted anywhere a <color> is. As usual for CSS-defined <ident>s, all of these keywords are case-insensitive.

The names resolve to colors in sRGB.

16 of CSS’s named colors come from HTML originally: aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, and yellow. Most of the rest come from one version of the X11 color system, used in Unix-derived systems to specify colors for the console. (Two special color values, transparent and currentcolor, are specially defined in their own sections.)

The following table defines all of the opaque named colors, by giving equivalent numeric specifications in the other color syntaxes.

Named Numeric Color name Hex rgb Decimal
  aliceblue#f0f8ff240 248 255
  antiquewhite#faebd7250 235 215
  aqua#00ffff0 255 255
  aquamarine#7fffd4127 255 212
  azure#f0ffff240 255 255
  beige#f5f5dc245 245 220
  bisque#ffe4c4255 228 196
  black#0000000 0 0
  blanchedalmond#ffebcd255 235 205
  blue#0000ff0 0 255
  blueviolet#8a2be2138 43 226
  brown#a52a2a165 42 42
  burlywood#deb887222 184 135
  cadetblue#5f9ea095 158 160
  chartreuse#7fff00127 255 0
  chocolate#d2691e210 105 30
  coral#ff7f50255 127 80
  cornflowerblue#6495ed100 149 237
  cornsilk#fff8dc255 248 220
  crimson#dc143c220 20 60
  cyan#00ffff0 255 255
  darkblue#00008b0 0 139
  darkcyan#008b8b0 139 139
  darkgoldenrod#b8860b184 134 11
  darkgray#a9a9a9169 169 169
  darkgreen#0064000 100 0
  darkgrey#a9a9a9169 169 169
  darkkhaki#bdb76b189 183 107
  darkmagenta#8b008b139 0 139
  darkolivegreen#556b2f85 107 47
  darkorange#ff8c00255 140 0
  darkorchid#9932cc153 50 204
  darkred#8b0000139 0 0
  darksalmon#e9967a233 150 122
  darkseagreen#8fbc8f143 188 143
  darkslateblue#483d8b72 61 139
  darkslategray#2f4f4f47 79 79
  darkslategrey#2f4f4f47 79 79
  darkturquoise#00ced10 206 209
  darkviolet#9400d3148 0 211
  deeppink#ff1493255 20 147
  deepskyblue#00bfff0 191 255
  dimgray#696969105 105 105
  dimgrey#696969105 105 105
  dodgerblue#1e90ff30 144 255
  firebrick#b22222178 34 34
  floralwhite#fffaf0255 250 240
  forestgreen#228b2234 139 34
  fuchsia#ff00ff255 0 255
  gainsboro#dcdcdc220 220 220
  ghostwhite#f8f8ff248 248 255
  gold#ffd700255 215 0
  goldenrod#daa520218 165 32
  gray#808080128 128 128
  green#0080000 128 0
  greenyellow#adff2f173 255 47
  grey#808080128 128 128
  honeydew#f0fff0240 255 240
  hotpink#ff69b4255 105 180
  indianred#cd5c5c205 92 92
  indigo#4b008275 0 130
  ivory#fffff0255 255 240
  khaki#f0e68c240 230 140
  lavender#e6e6fa230 230 250
  lavenderblush#fff0f5255 240 245
  lawngreen#7cfc00124 252 0
  lemonchiffon#fffacd255 250 205
  lightblue#add8e6173 216 230
  lightcoral#f08080240 128 128
  lightcyan#e0ffff224 255 255
  lightgoldenrodyellow#fafad2250 250 210
  lightgray#d3d3d3211 211 211
  lightgreen#90ee90144 238 144
  lightgrey#d3d3d3211 211 211
  lightpink#ffb6c1255 182 193
  lightsalmon#ffa07a255 160 122
  lightseagreen#20b2aa32 178 170
  lightskyblue#87cefa135 206 250
  lightslategray#778899119 136 153
  lightslategrey#778899119 136 153
  lightsteelblue#b0c4de176 196 222
  lightyellow#ffffe0255 255 224
  lime#00ff000 255 0
  limegreen#32cd3250 205 50
  linen#faf0e6250 240 230
  magenta#ff00ff255 0 255
  maroon#800000128 0 0
  mediumaquamarine#66cdaa102 205 170
  mediumblue#0000cd0 0 205
  mediumorchid#ba55d3186 85 211
  mediumpurple#9370db147 112 219
  mediumseagreen#3cb37160 179 113
  mediumslateblue#7b68ee123 104 238
  mediumspringgreen#00fa9a0 250 154
  mediumturquoise#48d1cc72 209 204
  mediumvioletred#c71585199 21 133
  midnightblue#19197025 25 112
  mintcream#f5fffa245 255 250
  mistyrose#ffe4e1255 228 225
  moccasin#ffe4b5255 228 181
  navajowhite#ffdead255 222 173
  navy#0000800 0 128
  oldlace#fdf5e6253 245 230
  olive#808000128 128 0
  olivedrab#6b8e23107 142 35
  orange#ffa500255 165 0
  orangered#ff4500255 69 0
  orchid#da70d6218 112 214
  palegoldenrod#eee8aa238 232 170
  palegreen#98fb98152 251 152
  paleturquoise#afeeee175 238 238
  palevioletred#db7093219 112 147
  papayawhip#ffefd5255 239 213
  peachpuff#ffdab9255 218 185
  peru#cd853f205 133 63
  pink#ffc0cb255 192 203
  plum#dda0dd221 160 221
  powderblue#b0e0e6176 224 230
  purple#800080128 0 128
  rebeccapurple#663399102 51 153
  red#ff0000255 0 0
  rosybrown#bc8f8f188 143 143
  royalblue#4169e165 105 225
  saddlebrown#8b4513139 69 19
  salmon#fa8072250 128 114
  sandybrown#f4a460244 164 96
  seagreen#2e8b5746 139 87
  seashell#fff5ee255 245 238
  sienna#a0522d160 82 45
  silver#c0c0c0192 192 192
  skyblue#87ceeb135 206 235
  slateblue#6a5acd106 90 205
  slategray#708090112 128 144
  slategrey#708090112 128 144
  snow#fffafa255 250 250
  springgreen#00ff7f0 255 127
  steelblue#4682b470 130 180
  tan#d2b48c210 180 140
  teal#0080800 128 128
  thistle#d8bfd8216 191 216
  tomato#ff6347255 99 71
  turquoise#40e0d064 224 208
  violet#ee82ee238 130 238
  wheat#f5deb3245 222 179
  white#ffffff255 255 255
  whitesmoke#f5f5f5245 245 245
  yellow#ffff00255 255 0
  yellowgreen#9acd32154 205 50

Note: this list of colors and their definitions is a superset of the list of named colors defined by SVG 1.1.

For historical reasons, this is also referred to as the X11 color set.

Note: The history of the X11 color system is interesting, and was excellently summarized by Alex Sexton in his talk “Peachpuffs and Lemonchiffons”.

6.2. System Colors

In forced colors mode, most colors on the page are forced into a restricted, user-chosen palette. The <system-color> keywords expose these user-chosen colors so that the rest of the page can integrate with this restricted palette.

When the forced-colors media feature is active, authors should use the <system-color> keywords as color values in properties other than those listed in CSS Color Adjust §3.1 Properties Affected by Forced Colors Mode, to ensure legibility and consistency across the page and avoid an uncoordinated mishmash of user-forced and page-chosen colors.

Authors may also use these keywords at any time, but should be careful to use the colors in matching background-foreground pairs to ensure appropriate contrast, as any particular contrast relationship across non-matching pairs (e.g. Canvas and ButtonText) is not guaranteed.

The <system-color> keywords are defined as follows:

Canvas
Background of application content or documents.
CanvasText
Text in application content or documents.
LinkText
Text in non-active, non-visited links.
VisitedText
Text in visited links.
ActiveText
Text in active links.
ButtonFace
The face background color for push buttons.
ButtonText
Text on push buttons.
Field
Background of input fields.
FieldText
Text in input fields.
Highlight
Background of item(s) selected in a control.
HighlightText
Text of item(s) selected in a control.
GrayText
Disabled text. (Often, but not necessarily, gray.)

Note: As with all other keywords, these names are case-insensitive. They are shown here with mixed capitalization for legibility.

For systems that do not have a particular system UI concept, the specified value should be mapped to the most closely related system color value that exists. The following pairings are expected to form legible background-foreground colors:

Additionally, GrayText is expected to be readable, though possibly at a lower contrast rating, over any of the backgrounds.

Earlier versions of CSS defined additional <system-color>s, which have since been deprecated. These are documented in Appendix A: Deprecated CSS System Colors.

Note: The <system-color>s incur some privacy and security risk, as detailed in § 16 Security and Privacy Considerations.

6.3. The transparent keyword

The keyword transparent specifies a transparent black. It is a type of <named-color>.

6.4. The currentcolor keyword

The keyword currentcolor represents value of the color property on the same element. Its used values is determined by resolving color values.

Here’s a simple example showing how to use the currentcolor keyword:
.foo {
  color: red;
  background-color: currentcolor;
}

This is equivalent to writing:

.foo {
  color: red;
  background-color: red;
}
For example, the text-emphasis-color property [CSS3-TEXT-DECOR], whose initial value is currentcolor, by default matches the text color even as the color property changes across elements.
<p><em>Some <strong>really</strong> emphasized text.</em>
<style>
p { color: black; }
em { text-emphasis: dot; }
strong { color: red; }
</style>

In the above example, the emphasis marks would be black over the text "Some" and "emphasized text", but red over the text "really".

Note: Multi-word keywords in CSS usually separate their component words with hyphens. currentcolor doesn’t, because it was originally introduced in SVG as a special attribute value spelled "currentColor", rather than a CSS value. Only later did CSS pick it up, at which point the capitalization stopped mattering, as CSS keywords are case-insensitive.

7. HSL Colors: hsl() and hsla() functions

The RGB system for specifying colors, while convenient for machines and graphic libraries, is often regarded as very difficult for humans to gain an intuitive grasp on. It’s not easy to tell, for example, how to alter an RGB color to produce a lighter variant of the same hue.

There are several other color schemes possible. One such is the HSL color scheme, which is much more intuitive to use, but still maps easily back to RGB colors.

HSL colors are specified as a triplet of hue, saturation, and lightness. The syntax of the hsl() function is:

hsl() = hsl( <hue> <percentage> <percentage> [ / <alpha-value> ]? )
<hue> = <number> | <angle>

The first argument specifies the hue. Hue is represented as an angle of the color circle (the rainbow, twisted around into a circle). The angle 0deg represents red (as does 360deg, 720deg, etc.), and the rest of the hues are spread around the circle, so 120deg represents green, 240deg represents blue, etc. Because this value is so often given in degrees, the argument can also be given as a number, which is interpreted as a number of degrees.

The next two arguments are the saturation and lightness, respectively. For saturation, 100% is a fully-saturated, bright color, and 0% is a fully-unsaturated gray. For lightness, 50% represents the "normal" color, while 100% is white and 0% is black. If the saturation or lightness are less than 0% or greater than 100%, they are clamped to those values before being converted to an RGB color.

The final argument specifies the alpha channel of the color. It’s interpreted identically to the fourth argument of the rgb() function. If omitted, it defaults to 100%.

For example, an ordinary red, the same color you would see from the keyword red or the hex notation #f00, is represented in HSL as hsl(0deg 100% 50%).

The advantage of HSL over RGB is that it is far more intuitive: one can guess at the colors they want, and then tweak. It is also easier to create sets of matching colors (by keeping the hue the same and varying the saturation and lightness).

HSL colors resolve to sRGB.

For example, the following colors can all be generated off of the basic "green" hue, just by varying the other two arguments:
hsl(120deg 100% 50%) lime green
hsl(120deg 100% 25%) dark green
hsl(120deg 100% 75%) light green
hsl(120deg 75% 85%)  pastel green

For legacy reasons, hsl() also supports an alternate syntax that separates all of its arguments with commas:

hsl() = hsl( <hue>, <percentage>, <percentage>, <alpha-value>? )

Also for legacy reasons, an hsla() function also exists, with an identical grammar and behavior to hsl().

7.1. Converting HSL colors to sRGB colors

Converting an HSL color to sRGB is straightforward mathematically. Here’s a simple implementation of the conversion algorithm in JavaScript. For simplicity, this algorithm assumes that the hue has been normalized to a number in the half-open range [0, 6), and the saturation and lightness have been normalized to the range [0, 1]. It returns an array of three numbers representing the red, green, and blue channels of the colors, normalized to the range [0, 1].

function hslToRgb(hue, sat, light) {
  if( light <= .5 ) {
    var t2 = light * (sat + 1);
  } else {
    var t2 = light + sat - (light * sat);
  }
  var t1 = light * 2 - t2;
  var r = hueToRgb(t1, t2, hue + 2);
  var g = hueToRgb(t1, t2, hue);
  var b = hueToRgb(t1, t2, hue - 2);
  return [r,g,b];
}

function hueToRgb(t1, t2, hue) {
  if(hue < 0) hue += 6;
  if(hue >= 6) hue -= 6;

  if(hue < 1) return (t2 - t1) * hue + t1;
  else if(hue < 3) return t2;
  else if(hue < 4) return (t2 - t1) * (4 - hue) + t1;
  else return t1;
}

7.2. Examples of HSL colors

The tables below illustrate a wide range of possible HSL colors. Each table represents one hue, selected at 30° intervals, to illustrate the common "core" hues: red, yellow, green, cyan, blue, magenta, and the six intermediary colors between these.

In each table, the X axis represents the saturation while the Y axis represents the lightness.

<https://github.com/w3c/csswg-drafts/issues/3088>

The conversions in the table below are known to contain errors. They are copied from CSS Color 3, which also had the same errors. Those colors were supposedly computed by a program in ABC. A future spec will correctly compute those colors. Meanwhile, please note that these conversions are non-normative examples.
0° Reds
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
30° Red-Yellows (=Oranges)
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
60° Yellows
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
90° Yellow-Greens
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
120° Greens
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
150° Green-Cyans
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
180° Cyans
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
210° Cyan-Blues
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
240° Blues
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
270° Blue-Magentas
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
300° Magentas
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%
330° Magenta-Reds
Saturation
100%75%50%25%0%
100%
88%
75%
63%
50%
38%
25%
13%
0%

8. HWB Colors: hwb() function

HWB (short for Hue-Whiteness-Blackness) is another method of specifying colors, similar to HSL, but often even easier for humans to work with. It describes colors with a starting hue, then a degree of whiteness and blackness to mix into that base hue.

Many color-pickers are based on the HWB color system, due to its intuitiveness.

HWB colors resolve to sRGB.

This is a screenshot of Chrome’s color picker, shown when a user activates an <input type="color">. The outer wheel is used to select the hue, then the relative amounts of white and black are selected by clicking on the inner triangle.

The syntax of the hwb() function is:

hwb() = hwb( <hue> <percentage> <percentage> [ / <alpha-value> ]? )

The first argument specifies the hue, and is interpreted identically to hsl().

The second argument specifies the amount of white to mix in, as a percentage from 0% (no whiteness) to 100% (full whiteness). Similarly, the third argument specifies the amount of black to mix in, also from 0% (no blackness) to 100% (full blackness). Values outside of these ranges make the function invalid. If the sum of these two arguments is greater than 100%, then at computed-value time they are normalized to add up to 100%, with the same relative ratio.

The fourth argument specifies the alpha channel of the color. It’s interpreted identically to the fourth argument of the rgb() function. If omitted, it defaults to 100%.

The resulting color can be thought of conceptually as a mixture of paint in the chosen hue, white paint, and black paint, with the relative amounts of each determined by the percentages. If white+black is equal to 100% (after normalization), it defines an achromatic color, i.e. some shade of gray, without any hint of the chosen hue.

8.1. Converting HWB colors to sRGB colors

Converting an HWB color to sRGB is straightforward, and related to how one converts HSL to RGB. The following Javascript implementation of the algorithm assumes that the white and black components have already been normalized, so their sum is no larger than 100%, and have been converted into numbers in the range [0,1].

function hwbToRgb(hue, white, black) {
  var rgb = hslToRgb(hue, 1, .5);
  for(var i = 0; i < 3; i++) {
    rgb[i] *= (1 - white - black);
    rgb[i] += white;
  }
  return rgb;
}

8.2. Examples of HWB Colors

0° Reds
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
30° Red-Yellows (Oranges)
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
60° Yellows
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
90° Yellow-Greens
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
120° Greens
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
150° Green-Cyans
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
180° Cyans
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
210° Cyan-Blues
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
240° Blues
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
270° Blue-Magentas
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
300° Magentas
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%
330° Magenta-Reds
W\B 0%20%40%60%80%100%
0%
20%
40%
60%
80%
100%

9. Device-independent Colors: Lab and LCH

Physical measurements of a color are typically expressed as the Lab color space, created in 1976 by the CIE. Color conversions from one device to another also use Lab as an intermediate step. Derived from human vision experiments, Lab represents the entire range of color that humans can see.

Lab is a rectangular coordinate system with a central Lightness axis. This value is usually written as a unitless number; for compatibility with the rest of CSS, it is written as a percentage. 100% means an L value of 100, not 1.0. L=0% is deep black (no light at all) while L=100% is a diffuse white (the illuminant is D50 white, a standardized daylight spectrum with a color temperature of 5000K, as reflected by a perfect diffuse reflector). Values greater than 100 would correspond to specular highlights, but their precise color is undefined in this specification. Usefully, L=50% is mid gray, by design, and equal increments in L are evenly spaced visually: the Lab color space is intended to be perceptually uniform. The a and b axes convey hue; positive values along the a axis are a purplish red while negative values are the complementary color, a green. Similarly, positive values along the b axis are yellow and negative are the complementary blue/violet. Desaturated colors have small values of a and b and are close to the L axis; saturated colors lie far from the L axis.

D50 is also the whitepoint used for the profile connection space in ICC color interconversion, the values used in image editors which offer Lab editing, and the value used by physical measurement devices such as spectrometers, when they report measured colors in Lab. Conversion from colors specified using other white points is called a chromatic adaptation transform, which models the changes in the human visual system as we adapt to a new lighting condition. The Bradford algorithm [Bradford-CAT] is the industry standard chromatic adaptation transform, and is easy to calculate as it is a simple matrix multiplication.

LCH has the same L axis as Lab, but uses polar coordinates C (chroma) and H (hue). C is the geometric distance from the L axis and H is the angle from the positive a axis, with positive angles being more clockwise.

In Lab and LCH, if two colors have the same L value, they appear to have the same visual lightness—regardless of how different their hues are.

Note: The Lightness axis in Lab and LCH should not be confused with the L axis in HSL. For example, in HSL, the sRGB colors blue (#00F) and yellow (#FF0) have the same value of L (50%) even though visually, blue is much darker. This is much clearer in Lab: sRGB blue is lab(29.567% 68.298,-112.0294) while sRGB yellow is lab(97.607% -15.753 93.388). In Lab, if two colors have the same measured L value, they have identical visual lightness. HSL and related polar RGB models were developed in an attempt to give similar usability benefits for RGB that LCH gave to Lab, but are significantly less accurate.

9.1. Specifying Lab and LCH: the lab() and lch() functional notations

CSS allows colors to be directly expressed in Lab and LCH.

lab() = lab( <percentage> <number> <number> [ / <alpha-value> ]? )

The first argument specifies the CIE Lightness. This is typically a number between 0% (representing black) and 100% (representing white), However, CIE Lightness can exceed this range on some systems, with extra-bright whites using a lightness up to 400. Values less than 0% must be clamped to 0% at computed-value time; values greater than 100% are permitted (for forwards compatibility with High Dynamic Range (HDR), and must not be clamped.

The second and third arguments are the distances along the "a" and "b" axises in the Lab colorspace, as described in the previous section. These values are signed (allow both positive and negative values) and theoretically unbounded (but in practice do not exceed ±160).

There is an optional fourth alpha value, separated by a slash, and interpreted identically to the <alpha-value> in rgb().

 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);
lch() = lch( <percentage> <number> <hue> [ / <alpha-value> ]? )

The first argument specifies the CIE Lightness, interpreted identically to the Lightness argument of lab().

The second argument is the chroma (roughly representing the "amount of color"). Its minimum useful value is 0, while its maximum is theoretically unbounded (but in practice does not exceed 230). If the provided value is negative, it is clamped to 0 at computed-value time.

The third argument is the hue angle. It’s interpreted similarly to the <hue> argument of hsl(), but doesn’t map hues to angles in the same way because they are evenly spaced perceptually. Instead, 0deg points along the positive "a" axis (toward purplish red), 90deg points along the positive "b" axis (toward mustard yellow), 180deg points along the negative "a" axis (toward greenish cyan), and 270deg points along the negative "b" axis (toward sky blue). If the provided value is negative, or is greater than or equal to 360deg, it is set to the value modulo 360.

There is an optional fourth alpha value, separated by a slash, and interpreted identically to the <alpha-value> in rgb().

 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);

9.2. Converting sRGB colors to Lab colors

Conversion from sRGB to Lab requires several steps, although in practice all but the first step are linear calculations and can be combined.

  1. Convert from sRGB to linear-light sRGB (undo gamma encoding). This has the same gamut as sRGB, but is now additive, so that arithmetic operations on the values give the correct results.
  2. Convert from linear sRGB to CIE XYZ
  3. Convert from a D65 whitepoint (used by sRGB) to the D50 whitepoint used in Lab, with the Bradford transform [Bradford-CAT]
  4. Convert D50-adapted XYZ to Lab

There is sample JavaScript code for this conversion in § 15 Sample code for color conversions.

9.3. Converting Lab colors to sRGB colors

Conversion from Lab to sRGB also requires multiple steps, and again in practice all but the last step are linear calculations and can be combined.

  1. Convert Lab to (D50-adapted) XYZ
  2. Convert from a D50 whitepoint (used by Lab) to the D65 whitepoint used in sRGB, with the Bradford transform
  3. Convert from (D65-adapted) CIE XYZ to linear sRGB
  4. Convert from linear-light sRGB to sRGB (do gamma encoding)

9.4. Converting Lab colors to LCH colors

Conversion to LCH is trivial:

  1. H = atan2(b, a)
  2. C = sqrt(a^2 + b^2)
  3. L is the same

9.5. Converting LCH colors to Lab colors

Conversion to Lab is trivial:

  1. a = C cos(H)
  2. b = C sin(H)
  3. L is the same

10. Profiled, Device-dependent Colors

CSS allows colors to be specified by reference to a color profile. This could be for example a calibrated CMYK printer, or an RGB colorspace, or any other color or monochrome output device which has been characterized.

In addition, for convenience, CSS provides several predefined RGB color spaces including display-p3' [DCI-P3], which is a wide gamut space typical of current wide-gamut monitors, prophoto-rgb', widely used by photographers and rec2020' [Rec.2020], which is a broadcast industry standard, ultra-wide gamut space capable of representing almost all visible real-world colors.

These can be used without supplying a separate profile.

This example specifies four profiled colors: for a standard SWOP-coated CMYK press, for a wide-gamut seven-ink printer, for ProPhoto RGB, and for the display-p3 standard RGB space. In each case, the numerical parameters are in the range 0.0 to 1.0 (rather than, for example, 0 to 255).
color: color(swopc 0.0134 0.8078 0.7451 0.3019);
color: color(indigo 0.0941 0.6274 0.3372 0.1647 0 0.0706 0.1216);
color: color(prophoto-rgb 0.9137 0.5882 0.4784);
color: color(display-p3 0.3804 0.9921 0.1412);

The colors not using a predefined colorspace also need a matching @color-profile at-rule somewhere in the stylesheet, to connect the name with the profile data.

@color-profile swopc {
  src: url('http://example.org/swop-coated.icc');}
@color-profile indigo {
  src: url('http://example.org/indigo-seven.icc');}

10.1. Specifying profiled colors: the color() function

The color() function allows a color to be specified in a particular colorspace (rather than the implicit sRGB colorspace that the other color functions operate in). Its syntax is:

color() = color( [ <ident>? [ <number-percentage>+ | <string> ] [ / <alpha-value> ]? ]# , <color>? )

The color function takes one or more comma-separated arguments, with each argument specifying a color, and later colors acting as "fallback" if an earlier color can’t be displayed (for example, if the colorspace it specifies hasn’t been loaded yet).

Each argument has the following form:

  • An optional <ident> denoting the colorspace. This can be one of the predefined colorspaces (such as display-p3), or one defined by a @color-profile rule. If omitted, it defaults to the predefined srgb color profile.

    If the <ident> names a non-existent colorspace, this argument represents an invalid color.

  • Either one or more <number>s or <percentage>s providing the parameter values that the colorspace takes, or a <string> giving the name of a color defined by the colorspace.

    If the colorspace takes numeric parameters
    If more <number>s or <percentage>s are provided than parameters that the colorspace takes, the excess <number>s at the end are ignored.

    If less <number>s or <percentage>s are provided than parameters that the colorspace takes, the missing parameters default to 0. (This is particularly convenient for multichannel printers where the additional inks are spot colors or varnishes that most colors on the page won’t use.)

    If a <string> is provided, this argument represents an invalid color.

    If the colorspace defines named colors
    If <number>s or <percentage>s are provided, or a <string> is provided that doesn’t match any of the color names defined by the colorspace, this argument represents an invalid color.
  • An optional slash-separated <alpha-value>. This is interpreted the same way as the <alpha-value> in rgb(), and if omitted it defaults to 100%.

After one or more arguments of the above form, a final <color> argument using any CSS color syntax can be provided.

The color() function represents the color specified by the first of its arguments that represent a valid color (that is, the first argument that isn’t an invalid color). If all of its arguments represent invalid colors, color() represents opaque black.

10.2. Predefined colorspaces: srgb, display-p3, a98-rgb, prophoto-rgb and rec2020.

The following colorspaces are predefined for use in the color() function. They can be used without any @color-profile rule.

srgb
The srgb [SRGB] colorspace accepts three numeric parameters, representing the red, green, and blue channels of the color, with each having a valid range of [0, 1]. The whitepoint is D65 (a daylight white, with a correlated color temperature of 6504°K).

[SRGB] specifies two viewing conditions, encoding and typical. The [ICC] recommends using the encoding conditions for color conversion and for optimal viewing, which are the values in the table below.

sRGB is the default colorspace for CSS, identical to specifying a color with the rgb() function.

It has the following characteristics:

xy
Red chromaticity0.6400.330
Green chromaticity0.3000.600
Blue chromaticity0.1500.060
White chromaticity0.31270.3290
Transfer functionsee below
White luminance80.0 cd/m2
Black luminance0.80 cd/m2
var Cl;
if (C <= 0.04045)
  Cl = C / 12.92;
else
  Cl = Math.pow((C + 0.055) / 1.055, 2.4);

C is the red, green or blue component.

display-p3
The display-p3 colorspace accepts three numeric parameters, representing the red, green, and blue channels of the color, with each having a valid range of [0, 1]. It uses the same primary chromaticities as [DCI-P3], but with a D65 whitepoint and the same transfer curve as sRGB.

It has the following characteristics:

xy
Red chromaticity0.6800.320
Green chromaticity0.2650.690
Blue chromaticity0.1500.060
White chromaticity0.31270.3290
Transfer functionsame as srgb
White luminance80.0 cd/m2
Black luminance0.80 cd/m2
a98-rgb
The a98-rgb colorspace accepts three numeric parameters, representing the red, green, and blue channels of the color, with each having a valid range of [0, 1]. The transfer curve is a gamma function, close to but not exactly 1/2.2.

a98-rgb is compatible with Adobe® RGB (1998) [AdobeRGB].

Adobe® RGB (1998) uses primaries originally derived from the SMPTE 240M standard; errors in the original conversion turned out to produce a colorspace that was useful for digital photography, so Adobe® RGB (1998) is a common wider-gamut colorspace for photographic images. The a98-rgb colorspace allows CSS to specify colors that will match colors in such images having the same RGB values.

It has the following characteristics:

xy
Red chromaticity0.64000.3300
Green chromaticity0.21000.7100
Blue chromaticity0.15000.0600
White chromaticity0.31270.3290
Transfer function256/563
White luminance160.0 cd/m2
Black luminance0.5557 cd/m2
prophoto-rgb
The prophoto-rgb colorspace accepts three numeric parameters, representing the red, green, and blue channels of the color, with each having a valid range of [0, 1]. The transfer curve is a gamma function with a value of 1/1.8. The white point is D50, the same as is used by CIE Lab. Thus, conversion to Lab does not require the chromatic adaptation step.

The ProPhoto RGB space uses primaries chosen to allow a wide color gamut and to minimise hue shifts under tonal manipulation. It is often used in digital photography as a wide gamut colorspace for the master version of photographic images. The prophoto-rgb colorspace allows CSS to specify colors that will match colors in such images having the same RGB values.

The white luminance is given as a range, and the viewing flare (and thus, the black luminance) is 0.5% to 1.0% of this.

It has the following characteristics:

xy
Red chromaticity0.73470.2653
Green chromaticity0.15960.8404
Blue chromaticity0.03660.0001
White chromaticity0.34570.3585
Transfer function1/1.800
White luminance160.0 to 640.0 cd/m2
Black luminanceSee text
rec2020
The rec2020 [Rec.2020] colorspace accepts three numeric parameters, representing the red, green, and blue channels of the color, with each having a valid range of [0, 1]. ITU Reference 2020 is used for High Definition, 4k and 8k television.

It has the following characteristics:

xy
Red chromaticity0.7080.292
Green chromaticity0.1700.797
Blue chromaticity0.1310.046
White chromaticity0.31200.3290
Transfer function1/2.4 (see note)

Note: rec2020 references a different transfer curve for cameras. However this curve is never used in production cameras or 2020 displays.
"In typical production practice the encoding function of image sources is adjusted so that the final picture has the desired look, as viewed on a reference monitor having the reference decoding function of Recommendation ITU-R BT.1886, in the reference viewing environment defined in Recommendation ITU-R BT.2035."
The transfer function (1886) for reference Rec.2020 displays is gamma 2.4 [Rec.2020]

10.2.1. Converting predefined colorspaces to Lab

For both predefined color spaces, conversion to Lab requires several steps, although in practice all but the first step are linear calculations and can be combined.

  1. Convert from gamma-corrected RGB to linear-light RGB (undo gamma encoding)
  2. Convert from linear RGB to CIE XYZ
  3. Convert from a D65 whitepoint (used by both display-p3 and rec2020) to the D50 whitepoint used in Lab, with the Bradford transform
  4. Convert D50-adapted XYZ to Lab

10.2.2. Converting Lab to predefined colorspaces

Conversion from Lab to display-p3 or rec2020 also requires multiple steps, and again in practice all but the last step are linear calculations and can be combined.

  1. Convert Lab to (D50-adapted) XYZ
  2. Convert from a D50 whitepoint (used by Lab) to the D65 whitepoint used in sRGB, with the Bradford transform
  3. Convert from (D65-adapted) CIE XYZ to linear RGB
  4. Convert from linear-light RGB to RGB (do gamma encoding)

Implementations may choose to implement these steps in some other way (for example, using an ICC profile with relative colorimetric rendering intent) provided the results are the same for colors inside the source and destination gamuts.

10.3. Specifying a color profile: the @color-profile at-rule

The @color-profile rule defines and names a color profile which can later be used in the color() function to specify a color. It’s defined as:

@color-profile = @color-profile <custom-ident> { <declaration-list> }

The <custom-ident> gives the color profile’s name. All of the predefined colorspace keywords (srgb, display-p3, a98-rgb, prophoto-rgb, rec2020) are excluded from this <custom-ident>, as they’re predefined by this specification and always available.

The @color-profile rule accepts the descriptors defined in this specification.

Name:src
For:@color-profile
Value:<url>
Initial:n/a

The src descriptor specifies the URL to retrieve the color-profile information from.

Name:rendering-intent
For:@color-profile
Value:relative-colorimetric | absolute-colorimetric | perceptual | saturation
Initial:relative-colorimetric

Color profiles contain “rendering intents”, which define how to map their color to smaller gamuts than they’re defined over. Often a profile will contain only a single intent, but when there are multiple, the rendering-intent descriptor chooses one of them to use.

The four possible rendering intents are [ICC]:

relative-colorimetric
Media-relative colorimetric is required to leave source colors that fall inside the destination medium gamut unchanged relative to the respective media white points. Source colors that are out of the destination medium gamut are mapped to colors on the gamut boundary using a variety of different methods.

Note: the media-relative colorimetric rendering intent is often used with black point compensation, where the source medium black point is mapped to the destination medium black point as well. This method must map the source white point to the destination white point. If black point compensation is in use, the source black point must also be mapped to the destination black point. Adaptation algorithms should be used to adjust for the change in white point. Relative relationships of colors inside both source and destination gamuts should be preserved. Relative relationships of colors outside the destination gamut may be changed.

absolute-colorimetric
ICC-absolute colorimetric is required to leave source colors that fall inside the destination medium gamut unchanged relative to the adopted white (a perfect reflecting diffuser). Source colors that are out of the destination medium gamut are mapped to colors on the gamut boundary using a variety of different methods. This method produces the most accurate color matching of in-gamut colors, but will result in highlight clipping if the destination medium white point is lower than the source medium white point. For this reason it is recommended for use only in applications that need exact color matching and where highlight clipping is not a concern.

This method MUST disable white point matching and black point matching when converting colors. In general, this option is not recommended except for testing purposes.

perceptual
This method is often the preferred choice for images, especially when there are substantial differences between the source and destination (such as a screen display image reproduced on a reflection print). It takes the colors of the source image and re-optimizes the appearance for the destination medium using proprietary methods. This re-optimization may result in colors within both the source and destination gamuts being changed, although perceptual transforms are supposed to maintain the basic artistic intent of the original in the reproduction. They will not attempt to correct errors in the source image.

Note: With v2 ICC profiles there is no specified perceptual reference medium, which can cause interoperability problems. When v2 ICC profiles are used it may be safer to use the media-relative colorimetric rendering intent with black point compensation, instead of the perceptual rendering intent, unless the specific source and destination profiles to be used have been checked to ensure the combination produces the desired result.

This method should maintain relative color values among the pixels as they are mapped to the target device gamut. This method may change pixel values that were originally within the target device gamut, in order to avoid hue shifts and discontinuities and to preserve as much as possible the overall appearance of the scene.

saturation
This option was created to preserve the relative saturation (chroma) of the original, and to keep solid colors pure. However, it experienced interoperability problems like the perceptual intent, and as solid color preservation is not amenable to a reference medium solution using v4 profiles does not solve the problem. Use of this rendering intent is not recommended unless the specific source and destination profiles to be used have been checked to ensure the combination produces the desired result. This option should preserve the relative saturation (chroma) values of the original pixels. Out of gamut colors should be converted to colors that have the same saturation but fall just inside the gamut.

11. Working Color Space

<https://github.com/w3c/csswg-drafts/issues/300>

12. Device-dependent CMYK Colors: the device-cmyk() function

While screens typically display colors directly with RGB pixels, printers often represent colors in different ways. In particular, one of the most common print-based ways of representing colors is with CMYK: a combination of cyan, magenta, yellow, and black which yields a particular color on that device. The device-cmyk() function allows authors to specify a color in this way:

device-cmyk() = device-cmyk( <cmyk-component>{4} [ / <alpha-value> ]? , <color>? )
<cmyk-component> = <number> | <percentage>

The arguments of the device-cmyk() function specify the cyan, magenta, yellow, and black components, in order, as a number between 0 and 1 or a percentage between 0% and 100%. These two usages are equivalent, and map to each other linearly. Values less than 0 or 0%, or greater than 1 or 100%, are not invalid; instead, they are clamped to 0/0% or 1/100% at computed-value time.

The fifth argument specifies the alpha channel of the color. It’s interpreted identically to the fourth argument of the rgb() function. If omitted, it defaults to 100%.

The sixth argument specifies the fallback color, used when the user agent doesn’t know how to accurately transform the CMYK color to RGB. If omitted, it defaults to the CMYK color naively converted to RGBA.

Typically, print-based applications will actually store the used colors as CMYK, and send them to the printer in that form. Unfortunately, CSS cannot do that; various CSS features require an RGB color, so that compositing/blending/etc. can be done. As such, CMYK colors must be converted to an equivalent RGB color. This is not trivial, like the conversion from HSL or HWB to RGB; the precise conversion depends on the precise characteristics of the output device.

If the user agent has information about the output device such that it believes it can accurately convert the CMYK color to a correct RGB color, the computed value of the device-cmyk() function must be that RGBA color. Otherwise, the computed value must be the fallback color.

For example, the following colors are equivalent (under the default conversion listed above):
color: device-cmyk(0 81% 81% 30%);
color: rgb(178 34 34);
color: firebrick;

Note: these colors might not match precisely if the browser knows a more precise conversion between CMYK and RGB colors. It’s recommended that if authors use any CMYK colors in their document, that they use only CMYK colors in their document to avoid any color-matching difficulties.

12.1. Converting Between Uncalibrated CMYK and RGB-Based Colors

While most colors defined in this specification are directly compatible with RGBA, and thus can be mechanically and consistently converted back and forth with it, device-CMYK colors are not directly compatible; a given device-CMYK color will map to various RGBA colors depending on the physical characteristics of the output device.

Ideally, the user agent will be aware of the output device’s color profiles for RGBA and device-CMYK. If this is true, then the user agent must convert between device-CMYK and RGBA colors (and vice versa) by first converting the color into an appropriate device-independent color space, such as CIELab, and then converting into the output color space, using the appropriate color profiles for each operation.

This is not always possible, however. In that case, the user agent must use the following naive conversion algorithms.

To naively convert from CMYK to RGBA:

If a fallback color was specified, return that color (converting it to RGB as well, if necessary). Otherwise:

  • red = 1 - min(1, cyan * (1 - black) + black)
  • green = 1 - min(1, magenta * (1 - black) + black)
  • blue = 1 - min(1, yellow * (1 - black) + black)
  • Alpha is same as for input color.

To naively convert from RGBA to CMYK:

  • black = 1 - max(red, green, blue)
  • cyan = (1 - red - black) / (1 - black), or 0 if black is 1
  • magenta = (1 - green - black) / (1 - black), or 0 if black is 1
  • yellow = (1 - blue - black) / (1 - black), or 0 if black is 1
  • alpha is the same as the input color
  • fallback color must be set to the input color

13. Transparency: the opacity property

Opacity can be thought of as a postprocessing operation. Conceptually, after the element (including its descendants) is rendered into an RGBA offscreen image, the opacity setting specifies how to blend the offscreen rendering into the current composite rendering. See simple alpha compositing for details.

Name:opacity
Value:<alpha-value>
Initial:1
Applies to:all elements
Inherited:no
Percentages:map to the range [0,1]
Computed value:specified number, clamped to the range [0,1]
Canonical order:per grammar
Animation type:by computed value type
<alpha-value>
The opacity to be applied to the element. It is interpreted identically to its definition in rgb(), except that the resulting opacity is applied to the entire element, rather than a particular color.

The opacity property applies the specified opacity to the element as a whole, including its contents, rather than applying it to each descendant individually. This means that, for example, an opaque child occluding part of the element’s background will continue to do so even when opacity is less than 1, but the element and child as a whole will show the underlying page through themselves.

If a box has opacity less than 1, it forms a stacking context for its children. (This prevents its contents from interleaving in the z-axis with content outside it.)

Furthermore, if the z-index property applies to the box, the auto value is treated as 0 for the element; it is otherwise painted on the same layer within its parent stacking context as positioned elements with stack level 0 (as if it were a positioned element with z-index:0).

See section 9.9 and Appendix E of [CSS2] for more information on stacking contexts.

These rules about z-order do not apply to SVG elements, since SVG has its own rendering model ([SVG11], Chapter 3).

13.1. Simple alpha compositing

When drawing, implementations must handle alpha according to the rules in Section 5.1 Simple alpha compositing of [Compositing].

14. Default Style Rules

The following stylesheet is informative, not normative. This style sheet could be used by an implementation as part of its default styling of HTML4, XHTML1, XHTML1.1, XHTML Basic, and other XHTML Family documents.

html {
  color: black;
}

/* traditional desktop user agent colors for hyperlinks */
:link    { color: blue; }
:visited { color: purple; }

The default background of the root element must be transparent. The default color of the canvas (the surface on which the document is painted) is UA-dependent, but is recommended to be white, especially if the above color rules are used.

15. Sample code for color conversions

This section is not normative.

For clarity, a library is used for matrix multiplication.

// Sample code for color conversions
// Conversion can also be done using ICC profiles and a Color Management System
// For clarity, a library is used for matrix manipulations

// sRGB-related functions

function lin_sRGB(RGB) {
	// convert an array of sRGB values in the range 0.0 - 1.0
	// to linear light (un-companded) form.
	// https://en.wikipedia.org/wiki/SRGB
	return RGB.map(function (val) {
		if (val < 0.04045) {
			return val / 12.92;
		}

		return Math.pow((val + 0.055) / 1.055, 2.4);
	});
}

function gam_sRGB(RGB) {
	// convert an array of linear-light sRGB values in the range 0.0-1.0
	// to gamma corrected form
	// https://en.wikipedia.org/wiki/SRGB
	return RGB.map(function (val) {
		if (val > 0.0031308) {
			return 1.055 * Math.pow(val, 1/2.4) - 0.055;
		}

		return 12.92 * val;
	});
}

function lin_sRGB_to_XYZ(rgb) {
	// convert an array of linear-light sRGB values to CIE XYZ
	// using sRGB's own white, D65 (no chromatic adaptation)
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	var M = math.matrix([
		[0.4124564,  0.3575761,  0.1804375],
		[0.2126729,  0.7151522,  0.0721750],
		[0.0193339,  0.1191920,  0.9503041]
	]);

	return math.multiply(M, rgb).valueOf();
}

function XYZ_to_lin_sRGB(XYZ) {
	// convert XYZ to linear-light sRGB
	var M = math.matrix([
		[ 3.2404542, -1.5371385, -0.4985314],
		[-0.9692660,  1.8760108,  0.0415560],
		[ 0.0556434, -0.2040259,  1.0572252]
	]);

	return math.multiply(M, XYZ).valueOf();
}

//  display-p3-related functions


function lin_P3(RGB) {
	// convert an array of display-p3 RGB values in the range 0.0 - 1.0
	// to linear light (un-companded) form.

	return lin_sRGB(RGB);	// same as sRGB
}

function gam_P3(RGB) {
	// convert an array of linear-light display-p3 RGB  in the range 0.0-1.0
	// to gamma corrected form

	return gam_sRGB(RGB);	// same as sRGB
}

function lin_P3_to_XYZ(rgb) {
	// convert an array of linear-light display-p3 values to CIE XYZ
	// using  D65 (no chromatic adaptation)
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	var M = math.matrix([
		[0.4865709486482162, 0.26566769316909306, 0.1982172852343625],
		[0.2289745640697488, 0.6917385218365064,  0.079286914093745],
		[0.0000000000000000, 0.04511338185890264, 1.043944368900976]
	]);
	// 0 was computed as -3.972075516933488e-17

	return math.multiply(M, rgb).valueOf();
}

function XYZ_to_lin_P3(XYZ) {
	// convert XYZ to linear-light P3
	var M = math.matrix([
		[ 2.493496911941425,   -0.9313836179191239, -0.40271078445071684],
		[-0.8294889695615747,   1.7626640603183463,  0.023624685841943577],
		[ 0.03584583024378447, -0.07617238926804182, 0.9568845240076872]
	]);

	return math.multiply(M, XYZ).valueOf();
}

// prophoto-rgb functions

function lin_ProPhoto(RGB) {
	// convert an array of prophoto-rgb values in the range 0.0 - 1.0
	// to linear light (un-companded) form.
	// Transfer curve is gamma 1.8 with a small linear portion
	return RGB.map(function (val) {
		if (val < 0.031248) {
			return val / 16;
		}

		return Math.pow(val, 1.8);
	});
}

function gam_ProPhoto(RGB) {
	// convert an array of linear-light prophoto-rgb  in the range 0.0-1.0
	// to gamma corrected form
	// Transfer curve is gamma 1.8 with a small linear portion
	return RGB.map(function (val) {
		if (val > 0.001953) {
			return Math.pow(val, 1/1.8);
		}

		return 16 * val;
	});
}

function lin_ProPhoto_to_XYZ(rgb) {
	// convert an array of linear-light prophoto-rgb values to CIE XYZ
	// using  D50 (so no chromatic adaptation needed afterwards)
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	var M = math.matrix([
	[ 0.7977604896723027,  0.13518583717574031,  0.0313493495815248     ],
	[ 0.2880711282292934,  0.7118432178101014,   0.00008565396060525902 ],
	[ 0.0,                 0.0,                  0.8251046025104601     ]
	]);

	return math.multiply(M, rgb).valueOf();
}

function XYZ_to_lin_ProPhoto(XYZ) {
	// convert XYZ to linear-light prophoto-rgb
	var M = math.matrix([
  	[  1.3457989731028281,  -0.25558010007997534,  -0.05110628506753401 ],
  	[ -0.5446224939028347,   1.5082327413132781,    0.02053603239147973 ],
  	[  0.0,                  0.0,                   1.2119675456389454  ]
	]);

	return math.multiply(M, XYZ).valueOf();
}

// a98-rgb functions

function lin_a98rgb(RGB) {
	// convert an array of a98-rgb values in the range 0.0 - 1.0
	// to linear light (un-companded) form.
	return RGB.map(function (val) {
	  return Math.pow(val, 563/256);
	});
}

function gam_a98rgb(RGB) {
	// convert an array of linear-light a98-rgb  in the range 0.0-1.0
	// to gamma corrected form
	return RGB.map(function (val) {
		return Math.pow(val, 256/563);
	});
}

function lin_a98rgb_to_XYZ(rgb) {
	// convert an array of linear-light a98-rgb values to CIE XYZ
	// using  D50 (so no chromatic adaptation needed afterwards)
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	// which has greater numerical precsion than section 4.3.5.3 of
	// https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
	var M = math.matrix([
	[ 0.5766690429101305,   0.1855582379065463,   0.1882286462349947  ],
	[ 0.29734497525053605,  0.6273635662554661,   0.07529145849399788 ],
	[ 0.02703136138641234,  0.07068885253582723,  0.9913375368376388  ]
	]);

	return math.multiply(M, rgb).valueOf();
}

function XYZ_to_lin_a98rgb(XYZ) {
	// convert XYZ to linear-light a98-rgb
	var M = math.matrix([
	[  2.0415879038107465,    -0.5650069742788596,   -0.34473135077832956 ],
	[ -0.9692436362808795,     1.8759675015077202,    0.04155505740717557 ],
	[  0.013444280632031142,  -0.11836239223101838,   1.0151749943912054  ]
	]);

	return math.multiply(M, XYZ).valueOf();
}

//Rec. 2020-related functions

function lin_2020(RGB) {
	// convert an array of rec2020 RGB values in the range 0.0 - 1.0
	// to linear light (un-companded) form.
	const α = 1.09929682680944 ;
	const β = 0.018053968510807;

	return RGB.map(function (val) {
		if (val < β * 4.5 ) {
			return val / 4.5;
		}

		return Math.pow((val + α -1 ) / α, 2.4);
	});
}
//check with standard this really is 2.4 and 1/2.4, not 0.45 was wikipedia claims

function gam_2020(RGB) {
	// convert an array of linear-light rec2020 RGB  in the range 0.0-1.0
	// to gamma corrected form
	const α = 1.09929682680944 ;
	const β = 0.018053968510807;

	return RGB.map(function (val) {
		if (val > β ) {
			return α * Math.pow(val, 1/2.4) - (α - 1);
		}

		return 4.5 * val;
	});
}

function lin_2020_to_XYZ(rgb) {
	// convert an array of linear-light rec2020 values to CIE XYZ
	// using  D65 (no chromatic adaptation)
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	var M = math.matrix([
		[0.6369580483012914, 0.14461690358620832,  0.1688809751641721],
		[0.2627002120112671, 0.6779980715188708,   0.05930171646986196],
		[0.000000000000000,  0.028072693049087428, 1.060985057710791]
	]);
	// 0 is actually calculated as  4.994106574466076e-17

	return math.multiply(M, rgb).valueOf();
}

function XYZ_to_lin_2020(XYZ) {
	// convert XYZ to linear-light rec2020
	var M = math.matrix([
		[1.7166511879712674,   -0.35567078377639233, -0.25336628137365974],
		[-0.6666843518324892,   1.6164812366349395,   0.01576854581391113],
		[0.017639857445310783, -0.042770613257808524, 0.9421031212354738]
	]);

	return math.multiply(M, XYZ).valueOf();
}

// Chromatic adaptation

function D65_to_D50(XYZ) {
	// Bradford chromatic adaptation from D65 to D50
	// The matrix below is the result of three operations:
	// - convert from XYZ to retinal cone domain
	// - scale components from one reference white to another
	// - convert back to XYZ
	// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
	var M = math.matrix([
		[ 1.0478112,  0.0228866, -0.0501270],
		[ 0.0295424,  0.9904844, -0.0170491],
		[-0.0092345,  0.0150436,  0.7521316]
	 ]);

	return math.multiply(M, XYZ).valueOf();
}

function D50_to_D65(XYZ) {
	// Bradford chromatic adaptation from D50 to D65
	var M = math.matrix([
		[ 0.9555766, -0.0230393,  0.0631636],
		[-0.0282895,  1.0099416,  0.0210077],
		[ 0.0122982, -0.0204830,  1.3299098]
	 ]);

	return math.multiply(M, XYZ).valueOf();
}

// Lab and LCH

function XYZ_to_Lab(XYZ) {
	// Assuming XYZ is relative to D50, convert to CIE Lab
	// from CIE standard, which now defines these as a rational fraction
	var ε = 216/24389;  // 6^3/29^3
	var κ = 24389/27;   // 29^3/3^3
	var white = [0.96422, 1.00000, 0.82521]; // D50 reference white

	// compute xyz, which is XYZ scaled relative to reference white
	var xyz = XYZ.map((value, i) => value / white[i]);

	// now compute 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
	];
}

function Lab_to_XYZ(Lab) {
	// Convert Lab to D50-adapted XYZ
	// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
	var κ = 24389/27;   // 29^3/3^3
	var ε = 216/24389;  // 6^3/29^3
	var white = [0.96422, 1.00000, 0.82521]; // D50 reference white
	var f = [];

	// compute f, starting with the luminance-related term
	f[1] = (Lab[0] + 16)/116;
	f[0] = Lab[1]/500 + f[1];
	f[2] = f[1] - Lab[2]/200;

	// compute 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)/κ
	];

	// Compute XYZ by scaling xyz by reference white
	return xyz.map((value, i) => value * white[i]);
}

function Lab_to_LCH(Lab) {
	// Convert to polar form
	var hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI;
	return [
		Lab[0], // L is still L
		Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma
		hue >= 0 ? hue : hue + 360 // Hue, in degrees [0 to 360)
	];
}

function LCH_to_Lab(LCH) {
	// Convert from polar form
	return [
		LCH[0], // L is still L
		LCH[1] * Math.cos(LCH[2] * Math.PI / 180), // a
		LCH[1] * Math.sin(LCH[2] * Math.PI / 180) // b
	];
}

Appendix A: Deprecated CSS System Colors

Earlier versions of CSS defined several additional system colors. These color keywords have been deprecated, however, as they are insufficient for their original purpose (making website elements look like their native OS counterparts), represent a security risk by making it easier for a webpage to “spoof” a native OS dialog, and increase fingerprinting surface, compromising user privacy.

User agents must support these keywords, but are encouraged to map them to default values not based on the user’s OS settings or match them to appropriate (undeprecated) system colors. Authors must not use these keywords.

The deprecated system colors are represented as the <deprecated-colors> sub-type, and are defined as:

ActiveBorder
Active window border.
ActiveCaption
Active window caption.
AppWorkspace
Background color of multiple document interface.
Background
Desktop background.
ButtonHighlight
The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.
ButtonShadow
The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.
CaptionText
Text in caption, size box, and scrollbar arrow box.
InactiveBorder
Inactive window border.
InactiveCaption
Inactive window caption.
InactiveCaptionText
Color of text in an inactive caption.
InfoBackground
Background color for tooltip controls.
InfoText
Text color for tooltip controls.
Menu
Menu background.
MenuText
Text in menus.
Scrollbar
Scroll bar gray area.
ThreeDDarkShadow
The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.
ThreeDFace
The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.
ThreeDHighlight
The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.
ThreeDLightShadow
The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.
ThreeDShadow
The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.
Window
Window background.
WindowFrame
Window frame.
WindowText
Text in windows.

Acknowledgments

Thanks to Brad Pettit both for writing up color-profiles, and for implementing it. Thanks to Steven Pemberton for his write-up on HSL colors. Thanks to Melanie Richards for updating the system colors write-up. Thanks especially to the feedback from Marc Attinasi, Bert Bos, Joe Clark, fantasai, Patrick Garies, Tony Graham, Ian Hickson, Susan Lesch, Alex LeDonne, Cameron McCormack, Krzysztof Maczyński, Chris Moschini, Chris Murphy, Christoph Päper, David Perrell, Jacob Refstrup, Dave Singer, Jonathan Stanley, Andrew Thompson, Russ Weakley, Etan Wexler, David Woolley, Boris Zbarsky, Steve Zilles, the XSL FO subgroup of the XSL working group, and all the rest of the www-style community.

And thanks to Chris Lilley for being the resident CSS Color expert.

Changes

Changes since Working Draft of 5 November 2019

  • Initial value of the "color" property is now CanvasText
  • Removed confusing gray() function per CSS WG resolution
  • Collect scattered definitions into new Color terminology section
  • Minor editorial clarifications, bikeshed markup fixes

Changes since Working Draft of 05 July 2016

  • Changed Lightness in Lab and LCH to be a percentage, for CSS compatibility
  • Clamping of color values clarified
  • Percentage opacity is now allowed
  • Define terms sRGB and linear-light sRGB, for use by other specs
  • Add new list of CSS system colors; renaming Text to CanvasText
  • Make system color keywords compute to themselves
  • Add computed/used entry for system colors
  • Rewrite intro to non-deprecated system colors to center their use around forced-colors mode rather than generic use
  • Consistent hyphenation of predefined colorspaces
  • Restore text about non-opaque elements painting at layeres even when not positioned
  • Initial value of the "color" property is now black
  • Clarify hue in LCH is modulo 360deg
  • Clarify allowed range of L in LCH and Lab, and meaning of L=100
  • Update references for colorspaces used in video
  • Add prophoto-rgb predefined colorspace
  • Correct black and white luminance levels for display-p3
  • Clarify display-p3 transfer function
  • Add a98-rgb colorspace, correct table of primary chromaticities
  • Clarify that currentColor’s computed value is not the resolved color
  • Update syntax is examples to conform to latest specification
  • Remove the color-mod() function
  • Drop the "media" from propdef tables
  • Export, and consistently use, "transparent black" and "opaque black"
  • Clarify calculated values such as percents
  • Clarify required precision and rounding behavior for color channels
  • Clarify "color" property has no effect on color font glyphs (unless specifically referenced, e.g. with currentColor)
  • Clarify how color values are resolved
  • larify that HSL, HWB and named colors resolve to sRGB
  • Simplify conversion from device-cmyk to sRGB
  • Describe previous, comma-using color syntaxes as "legacy"; change examples to commaless form
  • Remove superfluous requirement that displayed colors be restricted to device gamut (like there was any other option!)
  • Rename P3 to display-p3; avoid claiming this is DCI P3, as these are not the same
  • Improved description of the parameters to the "color()" function
  • Disallow predefined spaces from "@color-profile" identifier
  • Add canonical order to "color", "color-adjust" and "opacity" property definitions
  • Switch definition of alpha compositing from SVG11 to CSS Compositing
  • Clarify sample conversion code is non-normative
  • Add Security and Privacy Considerations
  • Update several references to most current versions
  • Convert inline issues to links to GitHub issues
  • Minor editorial clarifications, formatting and markup improvements

Changes from Colors 3

  1. rgb() and rgba() functions now accept <number> rather than <integer>.
  2. hsl() and hsla() functions now accept <angle> as well as <number> for hues.
  3. rgb() and rgba(), and hsl() and hsla() are now aliases of each other (all of them have an optional alpha).
  4. rgb(), rgba(), hsl(), and hsla() have all gained a new syntax consisting of space-separated arguments and an optional slash-separated opacity. All the color functions use this syntax form now, in keeping with CSS’s functional-notation design principles.
  5. All uses of <alpha-value> now accept <percentage> as well as <number>.
  6. 4 and 8-digit hex colors have been added, to specify transparency.

Several brand new features have been added:

  1. hwb() function, for specifying colors in the HWB notation.
  2. predefined, wide color gamut RGB colorspaces
  3. lab() and lch() functions, for device-independent color
  4. color() function and @color-profile at-rule, for profiled device-dependent color, including calibrated CMYK.
  5. device-cmyk() function, for specifying uncalibrated colors in an output-device-specific CMYK colorspace.
  6. Addition of named color rebeccapurple.

16. Security and Privacy Considerations

This specification defines "system" colors, which theoretically can expose details of the user’s OS settings, which is a fingerprinting risk.

The system colors, if they actually correspond to the user’s system colors, also pose a security risk, as they make it easier for a malware site to create user interfaces that appear to be from the system. However, as several system colors are now defined to be "generic", this risk is believed to be mitigated.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Advisements are normative sections styled to evoke special attention and are set apart from other normative text with <strong class="advisement">, like this: UAs MUST provide an accessible alternative.

Conformance classes

Conformance to this specification is defined for three conformance classes:

style sheet
A CSS style sheet.
renderer
A UA that interprets the semantics of a style sheet and renders documents that use them.
authoring tool
A UA that writes a style sheet.

A style sheet is conformant to this specification if all of its statements that use syntax defined in this module are valid according to the generic CSS grammar and the individual grammars of each feature defined in this module.

A renderer is conformant to this specification if, in addition to interpreting the style sheet as defined by the appropriate specifications, it supports all the features defined by this specification by parsing them correctly and rendering the document accordingly. However, the inability of a UA to correctly render a document due to limitations of the device does not make the UA non-conformant. (For example, a UA is not required to render color on a monochrome monitor.)

An authoring tool is conformant to this specification if it writes style sheets that are syntactically correct according to the generic CSS grammar and the individual grammars of each feature in this module, and meet all other conformance requirements of style sheets as described in this module.

Requirements for Responsible Implementation of CSS

The following sections define several conformance requirements for implementing CSS responsibly, in a way that promotes interoperability in the present and future.

Partial Implementations

So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported property values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.

Implementations of Unstable and Proprietary Features

To avoid clashes with future stable CSS features, the CSSWG recommends following best practices for the implementation of unstable features and proprietary extensions to CSS.

Implementations of CR-level Features

Once a specification reaches the Candidate Recommendation stage, implementers should release an unprefixed implementation of any CR-level feature they can demonstrate to be correctly implemented according to spec, and should avoid exposing a prefixed variant of that feature.

To establish and maintain the interoperability of CSS across implementations, the CSS Working Group requests that non-experimental CSS renderers submit an implementation report (and, if necessary, the testcases used for that implementation report) to the W3C before releasing an unprefixed implementation of any CSS features. Testcases submitted to W3C are subject to review and correction by the CSS Working Group.

Further information on submitting testcases and implementation reports can be found from on the CSS Working Group’s website at http://www.w3.org/Style/CSS/Test/. Questions should be directed to the public-css-testsuite@w3.org mailing list.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[AdobeRGB]
Adobe®RGB(1998) Color Image Encoding. May 2005. URL: https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
[Bradford-CAT]
Ming R. Luo; R. W. G. Hunt. A Chromatic Adaptation Transform and a Colour Inconstancy Index. Color Research & Application 23(3) 154-158. June 1998.
[Compositing]
Rik Cabanier; Nikos Andronikos. Compositing and Blending Level 1. 13 January 2015. CR. URL: https://www.w3.org/TR/compositing-1/
[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS Cascading and Inheritance Level 4. 28 August 2018. CR. URL: https://www.w3.org/TR/css-cascade-4/
[CSS-COLOR-ADJUST-1]
Elika Etemad; Rossen Atanassov; Tab Atkins Jr.. CSS Color Adjustment Module Level 1. 23 May 2019. WD. URL: https://www.w3.org/TR/css-color-adjust-1/
[CSS-POSITION-3]
Rossen Atanassov; Arron Eicholz. CSS Positioned Layout Module Level 3. 17 May 2016. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. 16 July 2019. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 6 June 2019. CR. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. 31 January 2019. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS2]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: https://www.w3.org/TR/CSS2/
[CSSOM-1]
Simon Pieters; Glenn Adams. CSS Object Model (CSSOM). 17 March 2016. WD. URL: https://www.w3.org/TR/cssom-1/
[DCI-P3]
SMPTE Recommended Practice - D-Cinema Quality — Reference Projector and Environment. 2011. URL: http://ieeexplore.ieee.org/document/7290729/
[ICC]
ICC.1:2010 (Profile version 4.3.0.0). December 2010. URL: http://www.color.org/specification/ICC1v43_2010-12.pdf
[ITU-R-BT.601]
Recommendation ITU-R BT.601-7 (03/2011), Studio encoding parameters of digital television for standard 4:3 and wide screen 16:9 aspect ratios. 8 March 2011. Recommendation. URL: https://www.itu.int/rec/R-REC-BT.601/
[ITU-R-BT.709]
Recommendation ITU-R BT.709-6 (06/2015), Parameter values for the HDTV standards for production and international programme exchange. 17 June 2015. Recommendation. URL: https://www.itu.int/rec/R-REC-BT.709/
[MEDIAQUERIES-4]
Florian Rivoal; Tab Atkins Jr.. Media Queries Level 4. 5 September 2017. CR. URL: https://www.w3.org/TR/mediaqueries-4/
[MEDIAQUERIES-5]
Media Queries Level 5 URL: https://drafts.csswg.org/mediaqueries-5/
[Rec.2020]
Recommendation ITU-R BT.2020-2: Parameter values for ultra-high definition television systems for production and international programme exchange . October 2015. URL: http://www.itu.int/rec/R-REC-BT.2020/en
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SMPTE296]
ST 296:2012, 1280 × 720 Progressive Image 4:2:2 and 4:4:4 Sample Structure — Analog and Digital Representation and Analog Interface. 17 May 2012. Standard. URL: https://doi.org/10.5594/SMPTE.ST296.2012
[SRGB]
Multimedia systems and equipment - Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB. URL: https://webstore.iec.ch/publication/6169
[SVG11]
Erik Dahlström; et al. Scalable Vector Graphics (SVG) 1.1 (Second Edition). 16 August 2011. REC. URL: https://www.w3.org/TR/SVG11/

Informative References

[CSS-TEXT-DECOR-4]
Elika Etemad; Koji Ishii. CSS Text Decoration Module Level 4. 13 March 2018. WD. URL: https://www.w3.org/TR/css-text-decor-4/
[CSS3-TEXT-DECOR]
Elika Etemad; Koji Ishii. CSS Text Decoration Module Level 3. 13 August 2019. CR. URL: https://www.w3.org/TR/css-text-decor-3/
[WCAG20]
Ben Caldwell; et al. Web Content Accessibility Guidelines (WCAG) 2.0. 11 December 2008. REC. URL: https://www.w3.org/TR/WCAG20/

Property Index

Name Value Initial Applies to Inh. %ages Anim­ation type Canonical order Com­puted value
color <color> CanvasText all elements yes N/A by computed value type per grammar computed color, see resolving color values
opacity <alpha-value> 1 all elements no map to the range [0,1] by computed value type per grammar specified number, clamped to the range [0,1]

@color-profile Descriptors

Name Value Initial
rendering-intent relative-colorimetric | absolute-colorimetric | perceptual | saturation relative-colorimetric
src <url> n/a

Issues Index

Does working color space affect these values? <https://github.com/w3c/csswg-drafts/issues/3844>
Define something for <deprecated-system-color>? <https://github.com/w3c/csswg-drafts/issues/3873>
When should channel-clamping occur? <https://github.com/w3c/csswg-drafts/issues/3845>
<https://github.com/w3c/csswg-drafts/issues/3088>
<https://github.com/w3c/csswg-drafts/issues/300>