CSS Color Of My Dreams

A Collection of Interesting Ideas,

This version:
http://tabatkins.github.io/specs/css-color/
Issue Tracking:
GitHub
Inline In Spec
Editors:
Tab Atkins Jr. (Google)
(W3C)
Former Editors:
(Mozilla Corporation)
This Document Is Obsolete and Has Been Replaced

This specification is obsolete and has been replaced by the document at http://dev.w3.org/csswg/css-color. Do not attempt to implement this specification. Do not refer to this specification except as a historical artifact.


Abstract

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

Table of Contents

1. Introduction

This section is not normative.

This module describes CSS properties which allow authors to specify the foreground color and opacity 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 and CSS2, but also defines new properties and values.

2. Foreground color: the color property

Name: color
Value: <color>
Initial: UA-defined, see prose
Applies to: all elements
Inherited: yes
Percentages: N/A
Media: visual
Computed value: an RGBA color
Animatable: no

This property describes the foreground color of an element’s text content. In addition, it provides the value that currentcolor resolves to. If the currentcolor keyword is set on the color property itself, it is treated as color: inherit.

The initial value of this property is a UA-defined color. In many existing user-agents, it is black.

There are different ways to specify lime green:

em { color: lime; }              /* color keyword   */
em { color: rgb(0,255,0); }      /* RGB range 0-255 */
<color>
The <color> type is defined in a later section.

3. The <color> type

CSS colors 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 displaying colors on other types of devices, like printers. (See [COLORIMETRY].) Additionally, every color is accompanied by an alpha component, indicating how transparent it is, and how much of the backdrop one can see behind the color. The components are also sometimes called "channels". Each channel has a minimum and maximum value, and can take any value between those two.

While all colors share an underlying storage format, CSS contains several syntaxes for specifying <color> values. Some directly specify the RGB color, such as the rgb() and rgba() functions and the hex notation. Others are more human-friendly to write and understand, and are converted to an RGB color by CSS, such as the hsl() and hsla() functions, or the long list of named colors defined by CSS.

In total, a <color> can be expressed with the rgb() and rgba() functions, the hsl() and hsla() functions, the hswb() notation, the hex color notations, or as a named color.

Some operations work differently on achromatic colors. An achromatic color is a shade of gray: in the RGB colorspace, a color is achromatic if the red, green, and blue channels are all the same value; in the HSL colorspace, a color is achromatic if the saturation is 0%; in the HWB colorspace, a color is achromatic if the sum of the whiteness and blackness is at least 100%.

3.1. The RGB functional notations: rgb() and rgba()

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

rgb() = rgb( <component>, <component>, <component> [, <alpha-value> ]? )
<component> = <number> | <percentage>
<alpha-value> = <number> | <percentage>

The three <component>s 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 emany graphics engines store the color channels internally as a single byte, which can hold integers between 0 and 255. However, the CSS syntax allows full <number>s, not just <integer>s, for authoring convenience.

Some devices can output colors technically outside of the sRGB gamut, represented by channels with values less than 0% or greater than 100%. For this reason, values outside of the 0%-100% range are allowed, but are clamped to the device’s gamut.)

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. Values outside these ranges are not invalid, but are clamped to the ranges defined here at computed-value time. If omitted, it defaults to 100%.

For legacy purposes, an rgba() function is defined. It’s identical to rgb(), except that the fourth argument (for the alpha channel) is not optional.

rgba() = rgba( <component>, <component>, <component>, <alpha-value>)

3.2. The RGB hexadecimal notations: #RRGGBB

The CSS hex color notation allows a 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 rgba(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 fo 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.

3.3. The HSL functional notations: hsl() and hsla()

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> | <named-hue>

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 an a number of degrees. Alternately, as many people have trouble associating numbers with hues, a <named-hue> may be used to give the hue. This allows for the hue to be specified with easy-to-understand terms, like red or greenish blue.

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 is less than 0% or the lightness is greater than 100%, they are clipped to those values before being converted to an RGB color. Some output devices may support saturations greater than 100%, just as they support RGB values greater than 100%. If the saturation exceeds the output device’s gamut, it must be clipped to that device’s gamut before being converted to an RGB color. This clipping should preserve the hue of the color (that is, it’s shouldn’t be the same thing as clipping an RGB component to the device’s gamut), but this specification does not define how to do so.

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(0, 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).

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

For legacy purposes, an hsla() function is defined. It is identical to hsl(), except that the fourth argument (for the alpha channel) is not optional.

hsla() = hsla( [ <number> | <angle> ], <percentage>, <percentage>, <alpha-value> )

3.3.1. Converting HSL colors to RGB colors

Converting an HSL color to RGB 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 - t1;
  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;
}

3.3.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.

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%

3.4. The HWB functional notation: hwb()

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.

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, or some shade of gray, without any hint of the chosen hue.

3.4.1. Converting HWB colors to RGB colors

Converting an HWB color to RGB 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;
}

3.4.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%

3.5. Specifying grays: the gray() functional notation

Grays are a very special set of colors. They’re fully desaturated (lacking any actual color at all), which means that specifying a gray with any of the other notations requires specifying some redundant information: if specifying the color with rgb(), all three channels are identical; if specifying the color with hsl(), the hue is irrelevant and the saturation is locked to 0%.

The gray() functional notation simplifies specifying this common set of colors, so that only the necessary information is required.

gray() = gray( [<number> | <percentage>] [, <alpha-value>]? )

The first argument specifies the shade of gray, while the second optional argument specifies the alpha channel of the color.

gray(A) represents the same color as rgb(A,A,A). gray(A,B) represents the same color as rgb(A,A,A,B).

gray() should have a keyword arg that opts it into smarter modes. "luminance", for example, instead of being a simple expansion to rgb(), could actually compute the gray with the specified luminance. The sRGB power curve means that grays are much darker than they "should" be; 50% gray has a luminance of .21, for example, rather than .5. Reversing luminance to color is easy for grays: if L < .0774, x * 12.92; otherwise, (x ^ (5/12)) * 1.055 - .055.

Alternately, base it on relative contrast ratios somehow? #757575 is the gray that lives exactly between white and black, in contrast-ratio space. Taking 0% to be black, 100% to be white, and 50% to be #757575, you convert between contrast-ratio space and luminance space with L = 21^p, then find the gray with that luminance.

3.6. Named Colors

In addition to the various numeric syntaxes for <color>s, CSS defines a large set of named colors that can be used instead, so that common colors can be written and read more easily. These are written as simple <ident>s, accepted anywhere a <color> is. As usual for CSS-defined <ident>s, all of these keywords are case-insensitive.

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. Nearly all of the rest (save two special values, transparent and currentcolor) come from one version of the X11 color system, used in Unix-derived systems to specify colors for the console.

The following table defines all of the HTML and X11 colors, by giving equivalent numeric specifications in the other color syntaxes. All of these colors are fully opaque.

Named Numeric Color name Hex rgb Decimal
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
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

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

3.6.1. The transparent keyword

The keyword transparent specifies a transparent black color; that is, a color with its red, green, and blue channels all set to the minimum value and its alpha channel set to full transparency, equivalent to rgba(0, 0, 0, 0).

3.6.2. The currentcolor keyword

The keyword currentcolor takes its value from the value of the color property on the same element. This happens at used-value time, which means that if the value is inherited, it’s inherited as currentcolor, not as the value of the color property, so descendants will use their own color property to resolve it.

If currentcolor is used as the value of the color property, it instead takes its value from the inherited value of the color property.

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.

3.6.3. Simple Named Hues: the <named-hue> term

The hsl() and hwb() notations both start from a saturated hue, and then modify it in various ways to achieve the exact color desired. This hue can be specified as a number/angle, but many people do not intuitively associate colors with numbers. Instead, the hue can be specified using simple color names and mixtures between them.

The syntax of <named-hue> is:

<named-hue> = <base-hue> | <base-hue> <base-hue> | <splash-hue> <base-hue>
<base-hue> = red | orange |  yellow | green | blue | purple
<splash-hue> = reddish | orangish | yellowish | greenish | bluish | purplish |
    reddish(<percentage>) | orangish(<percentage>) | yellowish(<percentage>) |
    greenish(<percentage>) | bluish(<percentage>) | purplish(<percentage>)

A named hue can be specified as one of the six base hues (like red), as an equal mixture of two base hues (like red orange or orange red), or as an unequal mixture of a base hue and a splash hue (like reddish orange or orangish(20%) red). A hue can only be mixed with hues that are "next" to it around the color wheel: red is next to orange and purple, but not yellow or green or blue, etc.

If the <splash-hue> is a function, the <percentage> specifies how much of the color is splashed into the <base-hue>: 0% means there’s no splash hue at all, while 100% means that it’s *entirely* the splash hue. In technical terms, a <named-hue> with a functional <splash-hue> is computed by finding the equivalent hue angles of the two hues, then linearly interpolating between them, where 0% represents the base hue angle, and 100% represents the splash hue angle. The <percentage> must be between 0% and 100%; values outside of that range are invalid and a syntax error.

If a <splash-hue> is specified as an identifier, it’s equivalent to specifying it as a function with the argument 25%. That is, greenish blue specifies the same color as greenish(25%) blue.

If two <base-hue>s are specified, it’s equivalent to specifying the first hue as a functional <splash-hue> with the argument 50%. That is, green blue specifies the same color as greenish(50%) blue.

3.6.3.1. Examples of Simple Named Hues

There are a total of 24 named hues not using the functional notation, arranged evenly around the color wheel:

Name Equivalent Hue Angle
red 0deg
orangish red 7.5deg
red orange or orange red 15deg
reddish orange 22.5deg
orange 30deg
yellowish orange 37.5deg
orange yellow or yellow orange 45deg
orangish yellow 52.5deg
yellow 60deg
greenish yellow 75deg
yellow green or green yellow 90deg
yellowish green 105deg
green 120deg
bluish green 150deg
green blue or blue green 180deg
greenish blue 210deg
blue 240deg
purplish blue 255deg
blue purple or purple blue 270deg
bluish purple 285deg
purple 300deg
reddish purple 315deg
red purple or purple red 330deg
purplish red 345deg

Note: The named hue cycle isn’t perfectly even. If it was, every hue would be 15deg apart. Instead, it adds orange and omits cyan, in order to bias the words closer to English usage, and make the colors themselves denser in colors that the human eye can see better.

3.7. Notes on using colors

Although colors can add significant amounts of information to document and make them more readable, please consider the W3C Web Content Accessibility Guidelines [WCAG20] when including color in your documents.

4. Modifying colors: the color() function

When specifying a color scheme for a site, one often wants a color that is close to another color, but slightly different. This becomes more important when CSS Variables are used, where an author may wish to define a "base" color, and then produce an array of slightly modified colors to use elsewhere.

The color() function takes an existing color, and applies zero or more "color adjusters" to it, which specify how to manipulate the color in some way.

Several of the color adjusters straightforwardly manipulate the color as an RGB, HSL, or HWB color, as if you’d specified a color in the appropriate syntax with one argument slightly modified. Others perform more complex manipulations of the color, such as blending it or finding contrasting colors.

Additionally, the color() function defines a new, more intuitive syntax for specifying named colors, based on CNS.

color() = color( [ <color> | <hue> ] <color-adjuster>* )
<color-adjuster> =
    [red( | green( | blue( | alpha( | a(] ['+' | '-']? [<number> | <percentage>] ) |
    [red( | green( | blue( | alpha( | a(] '*' <percentage> ) |
    rgb( ['+' | '-'] [<number> | <percentage>]{3} ) |
    rgb( ['+' | '-'] <hash-token> ) |
    rgb( '*' <percentage> ) |

    [hue( | h(] ['+' | '-' | '*']? <angle> ) |
    [saturation( | s(] ['+' | '-' | '*']? <percentage> ) |
    [lightness( | l(] ['+' | '-' | '*']? <percentage> ) |
    [whiteness( | w(] ['+' | '-' | '*']? <percentage> ) |
    [blackness( | b(] ['+' | '-' | '*']? <percentage> ) |

    tint( <percentage> ) |
    shade( <percentage> ) |

    blend( <color> <percentage> [rgb | hsl | hwb]? ) |
    blenda( <color> <percentage> [rgb | hsl | hwb]? ) |

    contrast( <percentage>? )

The first argument specifies the base color. If a <hue> is given, the base color is the HSL color with the given <hue>, 100% saturation, and 50% lightness (in other words, the fully-saturated color with the given hue).

After the base color, zero or more <color-adjuster>s can be specified. Each <color-adjuster> modifies the color in some way, passing a new base color to the next <color-adjuster> in the list. The same <color-adjuster> can be specified more than once in the list, such as color(red s(- 10%) s(- 10%)); each instance just modifies the color appropriately (in this case, producing hsl(0deg, 80%, 50%)).

There are several classes of <color-adjuster>s with various effects, defined in the following sections.

The computed value of a color() function is the color produced by applying all the <color-adjuster>s to the base color.

Note: While scaling can be specified without any spaces, like lightness(*150%), adding/subtracting must be done with spaces after the +/-, or else the +/- will be interpreted as part of the number by the CSS parser.

An achromatic color doesn’t have a unique hue, so some <color-adjuster>s that would make the color no longer achromatic (such as s(50%)) have special behavior for achromatic colors, as described in each adjuster’s description. However, it is possible for, within the space of a single color() function, for the base color to be chromatic, an adjuster to make it achromatic, and a following adjuster to make it chromatic again, with an author having the reasonable expectation that the hue is maintained.

To allow this, during the evaluation of a color() function’s <color-adjuster>s, rather than storing intermediate colors as a 4-tuple of red, green, blue, and alpha, as usual for CSS colors, intermediate colors must be stored as a 5-tuple of red, green, blue, alpha, and hue angle, where the hue angle may be null for some colors and after some operations.

Whenever an operation interprets an achromatic color in HSL or HWB space, if the color has a non-null hue angle, that hue must be used for the color’s HSL/HWB interpretation. (Individual operations define how to handle null hue angles.)

If the base color is achromatic, the hue angle is initially null.

For example, here’s a possible color() function that lightens and brightens the base color:
color(X w(+ 20%) s(+ 20%))

If X is a color like blue, this works in the expected way - after each operation, the color is still chromatic (and the return value is #33f).

On the other hand, if X is a greenish gray like #787, which is represented in HWB as hwb(120deg, 44%, 50%), the first operation will boost the sum of white and black to greater than 100%, making it an achromatic gray (#8f8f8f, to be specific).

However, the color() function remembers that the hue of the color was originally 120deg, so when the second operation saturates the color, it will result in a greenish-gray again (hsl(120deg, 20%, 56%), slightly lighter and brighter than the original color, which is what was intended).

More possibilities:

4.1. RGBA Adjustment

The most basic set of <color-adjuster>s modify the color’s channels directly, altering the amount of red, green, blue, or alpha in the color.

''[red( | green( | blue( | alpha( | a(] ['+' | '-']? [<number> | <percentage>] )''
''[red( | green( | blue( | alpha( | a(] * <percentage> )''
Sets or adjust the red, blue, green, or alpha channels of the base color.

If there is no operator, the given channel is set to the given value.

If the operator is + or -, the given channel is interpreted as the matching type (<number> or <percentage>) and then incremented or decremented by the given value.

If the operator is *, the given channel is multipled by the given value.

''rgb( ['+' | '-']? [<number> | <percentage>]{3} )''
Adjusts the base color in the red, green, and blue channels simultaneously. All three channels are interpreted as the matching type (<number> or <percentage>) and then incremented or decremented by the given values, with the first value adjusting the red channel, the second value adjusting the green channel, and the third value adjusting the blue channel.
''rgb( ['+' | '-'] <hash-token> )''
Identical to the previous clause, except that the adjustments to the three channels are specified in hexadecimal format; the <hash-token> is interpreted as a hex color, then the red, green, and blue channels of the color are applied as adjustments to the base color.
For example, in color(red rgb(+ #004400)), the base color is red (#ff0000). The red and blue channels aren’t adjusted at all (those channels in the given color are both 0), and the green channel is increased by 4416, resulting in a final color of #ff4400.
''rgb( * <percentage> )''
The red, green, and blue channels of the base color are multiplied by the given value.

All <color-adjuster>s in this section, except for alpha() and a(), set the hue angle to null if the resulting color is achromatic.

4.2. HSL/HWB Adjustment

The hsl() and hwb() functions provide alternative ways to specify colors numerically, intended to be easier and more intuitive for humans. Similarly, the color() function allows a color to be adjusted in these "virtual channels".

''[hue( | h(] ['+' | '-' | *]? <angle> )''
Sets or adjusts the hue of the base color, when base color is interpreted as an HSL color.

If there is no operator, the hue is set to the given value, regardless of what the hue angle was previously.

Otherwise, the hue is incremented or decremented, as appropriate, by the given value. If the hue angle is null, the adjuster instead does nothing.

''[saturation( | s(] ['+' | '-' | *]? <percentage> )''
''[lightness( | l(] ['+' | '-' | *]? <percentage> )''
''[whiteness( | w(] ['+' | '-' | *]? <percentage> )''
''[blackness( | b(] ['+' | '-' | *]? <percentage> )''
Sets or adjusts the saturation, lightness, whiteness, or blackness of the base color, when base color is interpreted as an HSL or HWB color, as appropriate.

If there is no operator, the given channel is set to the given value.

If the operator is + or -, the given channel is incremented or decremented by the given value.

If the operator is *, the given channel is multiplied by the given value.

If the hue angle is null, the operation is s() or saturation(), and the adjuster would make the saturation greater than 0%, it instead does nothing.

If the hue angle is null, the operation is w(), white(), b(), or black(), and the adjuster would make the sum of whiteness and blackness less than 100%, it additionally adjusts the opposite HWB channel to make the sum equal to 100%. (That is, color(white w(- 20%)) would represent the same color as hwb(0, 80%, 20%).)

4.3. Tints and Shades: the tint and shade adjusters

While the color() function does allow HWB adjustment of colors, the peculiarities of how HWB is defined make it more difficult than it should be to just define a lighter or darker version of a color. The tint and shade adjusters fix this, by simply mixing the base color with white or black.

''tint( <percentage> )''
Mixes the base color with pure white to produce a lighter version of the base color.

Specifying a <percentage> less than 0% or greater than 100% is a syntax error, and makes the function invalid.

Linearly interpolate the red, green, and blue channels of the base color with the red, green, and blue channels of pure white (rgb(255,255,255)), where 0% returns the base color and 100% returns pure white.

Note: tint(X%) is identical to blend(white X% rgb).

''shade( <percentage> )''
Mixes the base color with pure black to produce a darker version of the base color.

Identical to the previous clause, except the base color is mixed with pure black (rgb(0,0,0)) rather than pure white.

4.4. Color Blending: the blend and blenda adjusters

The tint() and shade() adjusters are common cases of the more general blend() adjuster, which mixes the base color with an arbitrary color.

''blend( <color> <percentage> [rgb | hsl | hwb]? )''
Mixes the base color with the given color to produce an intermediate color.

Specifying a <percentage> less than 0% or greater than 100% is a syntax error, and makes the function invalid.

The final argument specifies which color space to blend the colors in, defaulting to rgb if not specified. Both the base color and the given color are interpreted as colors in the given color space, then the components are blended.

For example, color(yellow blend(blue 50%)) blends yellow (#ffff00) with blue (#0000ff) equally, resulting in #808080, a medium gray.

On the other hand, color(yellow blend(blue 50% hsl)) blends the same colors in HSL space, where yellow is hsl(60, 100%, 50%) and blue is hsl(240, 100%, 50%), which results in hsl(150, 100%, 50%), a fully-saturated shade of green.

To determine the resulting color, interpret the base color and the given color in the appropriate color space (RGB, HSL, or HWB). Linearly interpolate each of the channels of the colors according to the given <percentage>, where 0% produces the specified <color> and 100% produces the base color.

If the color space is hsl or hwb, interpolate the hue channel either clockwise or counterclockwise, whichever results in a shorter "path" between the two hue angles. If the two hue angles are on opposite sides of the hue circle (separated by 180 degrees), take the clockwise path.

If the hue angle is null for one of the colors but not the other, treat the null hue angle as being equal to the non-null hue angle for the purpose of this adjuster. If both hue angles are null, the resulting color’s hue angle is null as well.

Note: The choice of how to transition when the difference is 180deg is arbitrary, and was chosen merely to provide an unambiguous answer. To achieve counter-clockwise behavior, adjust either color’s hue angle by a small amount toward the desired direction.

For example, blending yellow (hue angle 60deg) with 50% purple (hue angle 300deg) results in red (hue angle 0deg), not cyan (hue angle 180deg), even though 60*50% + 300*50% == 180, because the distance between the two colors when moving counter-clockwise is only 120 degrees, as opposed to 240 degrees when going clockwise.
''blenda( <color> <percentage> [rgb | hsl | hwb]? )''
Identical to the previous clause, except it pays attention to the alpha channel of the two colors (blend() just preserves the alpha channel of the base color).

Let w be the specified <percentage>, rescaled to the range [-1,1], where 0% maps to -1 and 100% maps to 1. Let a be the difference of the alpha channels of the base color and the specified <color>, also rescaled to the range [-1,1], where -100% (0% base color alpha and 100% specified color alpha) maps to -1 and 100% maps to 1.

If w * a == -1, let new weight equal w. Otherwise, let new weight equal (w + a) / (1 + w*a).

Reinterpret new weight as a percentage in the range [0%, 100%], where -1 maps to 0% and 1 maps to 100%. Calculate the result color as if blend() had been specified, using the new weight percentage instead of the specified <percentage>, and set the alpha channel of the result color to the average of the alpha channels of the base color and the specified <color>.

This blends the two colors in a way that pays attention to alpha, similar to how compositing does. Is there a better formula? The current one was determined empirically to give good results, but isn’t motivated by any theory.

Should we swap the defaults, so blend() does the alpha blending, and another name (or maybe another parameter) ignores alpha like blend() currently does?

4.5. Guaranteeing Adequate Contrast: the constrast adjuster

Guaranteeing that foreground and background colors contrast sufficiently is important, but even if one knows the mathematical definition of "appropriate contrast", it’s not trivial to calculate and figure out whether two arbitrary colors are good enough. The contrast() adjuster makes this easy, automatically computing a color that is sufficiently contrasting with the base color to satisfy accessibility guidelines.

''contrast( <percentage>? )''
Finds a color that contrasts with the base color suffficiently to satisfy accessibility guidelines, using the definition of "contrast" given by WCAG 2.0 Guideline 1.4.3.

The <percentage> specifies the desired similarity between the base color and the returned color. 0% will return the minimum-contrast color (the closest color to the base color that still contrasts sufficiently), while 100% will return the maximum-contrast color (white or black, whichever contrasts the base color more) Specifying a value less than 0% or greater than 100% is invalid and a syntax error. If omitted, the <percentage> defaults to 100%.

  1. Compute the luminance of the base color. If it’s less than .5, the maximum-contrast color is hwb(X, 100%, 0%), where X is the hue angle of the base color. Otherwise, the maximum-contrast color is hwb(X, 0%, 100%), where X is the hue angle of the base color.

    Note: In other words, the maximum-contrast color is either white or black, but with the hue set up correctly for the next step’s linear interpolation.

  2. Looking only at colors that are linear interpolations in HWB space (a la the blend() adjuster) between the base color and the maximum-contrast color, find the color with the smallest contrast ratio with the base color that is greater than 4.5. This is the minimum-contrast color. If there is no color with contrast ratio greather than 4.5, return the maximum-contrast color immediately.

    Note: 4.5 is the contrast ratio required by WCAG for Level AA contrast.

    Note: Using this method, the contrast ratio will be monotonically non-increasing as you go from the maximum-contrast color to the base color, so a simple binary search will identify the minimum-contrast color in a small number of iterations.

  3. Blend the minimum-contrast color and maximum-contrast color according to the specified <percentage>, as if ''color(maximum-contrast color blend(minimum-contrast color <percentage> hwb))'' were specified. Return the blended color.

To compute the luminance of a color:

  1. Scale the red, green, and blue channels of the color to the range [0,1].
  2. For each channel, if the channel’s value is less than or equal to 0.03928, set the channel’s value to channel / 12.92. Otherwise, set the channel’s value to ((channel + 0.055) / 1.055) ^ 2.4.

    Note: This reverses the logarithmic power scaling of the sRGB gamut, so the value of the channel is approximately linear related to the amount of light required to represent it.

  3. The luminance is:

    0.2126*R + 0.7152*G + 0.0722*B

    where R, G, and B are the adjusted red, green, and blue channels from the previous step.

Note: The luminance of a color within the sRGB gamut is contained within the range [0,1], where black is 0 and white is 1.

To compute the contrast ratio of two colors:

  1. Compute the luminance of both colors.
  2. The contrast ratio is:

    (L1 + 0.05) / (L2 + 0.05)

    where L1 is the smaller of the two luminances, and L2 is the larger.

Note: The contrast ratio of two colors is contained within the range [1,21], where two identical colors are 1 and the ratio of white and black is 21.

5. 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: N/A
Media: visual
Computed value: The specified value, clamped to the range [0,1].
Animatable: no
<alpha-value>
The opacity to be applied to the element. It is interpreted identically to its definition in rgba(), 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 opacity has a value less than 1, the element forms a stacking context for its children. This means that any content outside of it cannot be layered in z-order between pieces of content inside of it, and vice versa. If the element is in a context where the z-index property applies, the auto value is treated as 0 for the element. See section 9.9 and Appendix E of [CSS21] for more information on stacking contexts. The rules in this paragraph do not apply to SVG elements, since SVG has its own rendering model ([SVG11], Chapter 3).

5.1. Simple alpha compositing

When drawing, implementations must handle alpha according to the rules in Section 14.2 Simple alpha compositing of [SVG11]. (If the color-interpolation or color-rendering properties mentioned in that section are not implemented or do not apply, implementations must act as though they have their initial values.)

6. Color Management: the color-correction property

CSS Level 1 ([CSS1]), CSS Level 2 ([CSS21]), and CSS Color Level 3 ([CSS3COLOR]) define colors specified in CSS to be in the sRGB color space ([SRGB]). However, most or all existing Web browser implementations do not correct colors specified in HTML, CSS, or untagged images even when the proper correction is known.

If browsers did so, it would make the colors displayed in Web pages more consistent between different displays and operating systems. However, a more important type of consistency is the consistency of colors in different parts of a page on the same display, such as between colors specified in style sheets and colors in images, or between those colors and colors drawn by plugins. Improving the consistency of colors between different displays, therefore, requires care not to cause the worse problem of inconsistency of colors on the same display.

In the long run, we hope that it might be possible for implementations to switch to treating CSS colors and colors in untagged images as being in sRGB by default. (This may depend on additions for color management being made to the plugin API and popular plugins using those additions.) Therefore, this specification provides a way to clearly opt in to that correct behavior, but provides an default behavior (initial value) that may be equivalent to this opt-in.

Name: color-correction
Value: auto | sRGB
Initial: auto
Applies to: all elements
Inherited: yes
Percentages: N/A
Media: visual
Computed value: as specified
Animatable: no

The color-correction property specifies the color space that colors specified in CSS and colors in untagged images are in. An untagged image is an image that is not explicitly assigned a color profile, as defined by the image format. It does not apply to videos, since untagged video should be presumed to be in CCIR 601.

Really? Shouldn’t video be consistent with images? Or do implementations really do this differently?

sRGB
Colors specified in CSS and colors in untagged images are in the sRGB color space.
auto
The color space for colors specified in CSS and colors in untagged images is not defined. However, implementations must use a single color space for such colors so that they match each other. When doing so would not cause color mismatches with content such as plugins, implementations should treat auto the same as sRGB.

Note: The initial value of this property may change in a future level of this specification.

7. Sample style sheet for (X)HTML

This appendix 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;
  background: white;
}

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

Appendix A: Deprecated CSS System Colors

Earlier versions of CSS defined several additional named color keywords, which were meant to take their value from operating system themes. These color names have been deprecated, however, as they are insufficient for their original purpose (making website elements look like their native OS counterparts), and represent a security risk, as it makes it easier for a webpage to "spoof" a native OS dialog.

User agents must support these keywords, but should map them to "default" values, not based on the user’s OS settings (for example, mapping all the "background" colors to white and "foreground" colors to black). Authors must not use these keywords.

ActiveBorder
Active window border.
ActiveCaption
Active window caption.
AppWorkspace
Background color of multiple document interface.
Background
Desktop background.
ButtonFace
The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.
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.
ButtonText
Text on push buttons.
CaptionText
Text in caption, size box, and scrollbar arrow box.
GrayText
Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.
Highlight
Item(s) selected in a control.
HighlightText
Text of item(s) selected in a control.
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 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 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. All uses of <alpha-value> now accept <percentage> as well as <number>.
  4. 4 and 8-digit hex colors have been added, to specify transparency.
  5. The color-correction property has been pulled in from the unpublished Color Correction proposal.

Several brand new features have been added:

  1. gray() function, for specifying grays compactly. (And maybe allowing specification via luminance.)
  2. hwb() function, for specifying colors in the HWB notation.
  3. color() function, for manipulating colors.
  4. <named-hue>, for specifying hsl/hwb hue with readable names, rather than a more opaque angle.

Conformance

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.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS21]
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. 7 June 2011. REC. URL: http://www.w3.org/TR/CSS2
[SRGB]
Multimedia systems and equipment - Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB. as amended by Amendment A1:2003. URL: http://www.iec.ch/nr1899.htm
[SVG11]
Erik Dahlström; et al. Scalable Vector Graphics (SVG) 1.1 (Second Edition). 16 August 2011. REC. URL: http://www.w3.org/TR/SVG11/
[SVG2]
Nikos Andronikos; et al. Scalable Vector Graphics (SVG) 2. 15 September 2015. WD. URL: http://www.w3.org/TR/SVG2/
[CSS-POSITION-3]
CSS Positioned Layout Module Level 3 URL: http://www.w3.org/TR/css3-positioning/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. 20 February 2014. CR. URL: http://www.w3.org/TR/css-syntax-3/
[CSS-TEXT-DECOR-3]
Elika Etemad; Koji Ishii. CSS Text Decoration Module Level 3. 1 August 2013. CR. URL: http://www.w3.org/TR/css-text-decor-3/
[CSS-VALUES]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 11 June 2015. CR. URL: http://www.w3.org/TR/css-values/
[FILTERS-1]
Filter Effects Level 1 URL: http://www.w3.org/TR/filter-effects-1/
[MEDIAQUERIES-4]
Florian Rivoal; Tab Atkins Jr.. Media Queries Level 4. 5 June 2014. WD. URL: http://www.w3.org/TR/mediaqueries-4/
[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
[SELECTORS-4]
Selectors Level 4 URL: http://www.w3.org/TR/selectors4/

Informative References

[COLORIMETRY]
Colorimetry, Third Edition. ISBN 978-3-901906-33-6
[CSS1]
Håkon Wium Lie; Bert Bos. Cascading Style Sheets (CSS1) Level 1 Specification. 11 April 2008. REC. URL: http://www.w3.org/TR/CSS1/
[CSS3-TEXT-DECOR]
Elika Etemad; Koji Ishii. CSS Text Decoration Module Level 3. 1 August 2013. CR. URL: http://www.w3.org/TR/css-text-decor-3/
[CSS3COLOR]
Tantek Çelik; Chris Lilley; David Baron. CSS Color Module Level 3. 7 June 2011. REC. URL: http://www.w3.org/TR/css3-color
[WCAG20]
Ben Caldwell; et al. Web Content Accessibility Guidelines (WCAG) 2.0. 11 December 2008. REC. URL: http://www.w3.org/TR/WCAG20/

Property Index

Name Value Initial Applies to Inh. %ages Media Ani­mat­able Com­puted value
color <color> UA-defined, see prose all elements yes N/A visual no an RGBA color
opacity <alpha-value> 1 all elements no N/A visual no The specified value, clamped to the range [0,1].
color-correction auto | sRGB auto all elements yes N/A visual no as specified

Issues Index

gray() should have a keyword arg that opts it into smarter modes. "luminance", for example, instead of being a simple expansion to rgb(), could actually compute the gray with the specified luminance. The sRGB power curve means that grays are much darker than they "should" be; 50% gray has a luminance of .21, for example, rather than .5. Reversing luminance to color is easy for grays: if L < .0774, x * 12.92; otherwise, (x ^ (5/12)) * 1.055 - .055.

Alternately, base it on relative contrast ratios somehow? #757575 is the gray that lives exactly between white and black, in contrast-ratio space. Taking 0% to be black, 100% to be white, and 50% to be #757575, you convert between contrast-ratio space and luminance space with L = 21^p, then find the gray with that luminance.

More possibilities:
This blends the two colors in a way that pays attention to alpha, similar to how compositing does. Is there a better formula? The current one was determined empirically to give good results, but isn’t motivated by any theory.
Should we swap the defaults, so blend() does the alpha blending, and another name (or maybe another parameter) ignores alpha like blend() currently does?
Really? Shouldn’t video be consistent with images? Or do implementations really do this differently?