Glossary

CSS color() Function

CSS color() is a function that specifies a color by its components in a named color space, such as display-p3 or rec2020, instead of the default sRGB. It is defined in CSS Color Module Level 4, in the section on specifying predefined colors, and it has worked in all major browsers since May 2023. The syntax is a space name followed by three values and an optional alpha, with no commas.

How it works

The grammar is color( <space> <c1> <c2> <c3> [ / <alpha> ]? ). The three components are numbers or percentages, and each may be the keyword none. The spec defines these color spaces:

  • RGB-style spaces: srgb, srgb-linear, display-p3, display-p3-linear, a98-rgb, prophoto-rgb and rec2020.
  • XYZ spaces: xyz, xyz-d50 and xyz-d65. The bare name xyz is an alias for xyz-d65.
  • Range: for the RGB spaces, 0 to 1 (or 0% to 100%) covers the space's own gamut.
  • Out of range: values below 0 or above 1 are not an error. They are kept for calculations and gamut mapped when the color is displayed.

Commas are an error. The spec says color() has no legacy comma syntax, because it was new in Level 4.

#a { color: color(display-p3 1 0 0); }
#b { color: color(srgb 1 0 0 / 50%); }
#c { color: color(xyz 0.2 0.3 0.4); }
#d { color: color(srgb, 1, 0, 0); }

Computed values in headless Chromium 141:

#a  color(display-p3 1 0 0)
#b  color(srgb 1 0 0 / 0.5)
#c  color(xyz-d65 0.2 0.3 0.4)
#d  rejected (CSS.supports returned false)

The browser keeps the color in its original space, and #c shows the xyz alias being rewritten as xyz-d65. #d has commas, so the declaration is dropped.

How do I fall back when a browser lacks display-p3?

Declare an sRGB color first and the color() line after it. An engine that cannot parse the second line ignores it and keeps the first. In Chromium 141, color: rgb(255 0 0); color: color(foo 1 0 0) computed to rgb(255, 0, 0), because the unknown space name made the second declaration invalid. For a wide-gamut screen test, use @media (color-gamut: p3).

What happens to colors outside the sRGB gamut?

They are converted when drawn. Reading pixels back from an sRGB canvas in Chromium 141 gave these results.

color(srgb 1 0 0)             -> 255,0,0,255
color(display-p3 1 0 0)       -> 255,0,0,255
color(display-p3 0.9 0.5 0.2) -> 245,121,13,255

Display P3 red is more saturated than sRGB red, so on an sRGB target it lands on the sRGB edge. On a P3 display the same value would render more vividly. The headless test browser reported no P3 gamut, so the on-screen difference was not observed.

Common pitfalls

  • Using commas: color(srgb, 1, 0, 0) is invalid. Separate values with spaces and put alpha after a slash.
  • Misspelling the space name: color(foo 1 0 0) is dropped as a declaration. Use one of the listed names exactly.
  • Assuming 255-based numbers: color(srgb 255 0 0) is far outside the 0 to 1 range. Use 1, or 100%.
  • Expecting the same look on every screen: display-p3 values are mapped down on sRGB screens, so two shades that differ in P3 can look identical there.
  • No fallback line: put an rgb or hex color first so older engines still render a color.

Related terms

  • sRGB — the default space that color() leaves when you name another.
  • Color gamut — the range of colors a space or display can show.
  • Color management — how colors are converted between spaces and devices.
  • LCH color — a perceptual space with its own lch() function.
  • Oklab — a perceptual space with its own oklab() function.
  • RGB — the model that srgb, display-p3 and rec2020 are variations of.

See also