The CSS color() Function: Color Spaces Beyond OKLCH
AI generated
{ }
@
CSS · Color Spaces · Wide Gamut
The Generic color() Function
Color spaces beyond OKLCH: display-p3, a98-rgb, prophoto-rgb, rec2020

While oklch() and lab() describe self-contained color models, the generic color() function opens CSS up to a whole set of named color spaces, including display-p3, a98-rgb, prophoto-rgb and rec2020. Anyone wanting to render product photos or brand colors faithfully on modern displays with a wider color range has to deal with this function, but also needs a clean fallback for older screens and browsers.

12 min read color() · display-p3 · rec2020 CSS Color Module Level 4

1. Why CSS needs more than one color space

Classic sRGB, the web's standard color space since the 1990s, only covers part of the colors modern displays can actually render. A current smartphone or laptop display with a wide-gamut panel can show rich reds and greens that cannot be encoded in sRGB at all, because the color space is simply too small at that point. Images or color values limited to sRGB automatically look slightly more muted on such displays than the hardware could actually deliver.

The generic function color(<color-space> <components>) closes that gap by letting CSS specify color values explicitly in one of several defined color spaces, instead of implicitly always assuming sRGB. Unlike oklch(), which describes a self-contained, perceptually based color model, color() is a generic container whose first argument names the desired color space and whose remaining arguments specify the color values within that space.


.hero-banner {
  /* sRGB as the base */
  background: rgb(220, 38, 38);
}

.hero-banner.wide-gamut {
  /* display-p3 shows a more saturated red on capable displays */
  background: color(display-p3 0.86 0.15 0.15);
}

2. display-p3: the most relevant wide-gamut space for consumer hardware

display-p3 is the color space actually in use on current Apple devices, many high-end Android smartphones, and modern monitors. Compared to sRGB, it covers noticeably more of the visible color space, especially in reds and greens, and is the only wide-gamut space that, in practice, is actually rendered in hardware on a meaningful share of devices currently in circulation.

For product photography, especially of objects with rich colors like textiles, cosmetics, or food, the difference between sRGB and display-p3 makes a visible difference in color depth on a capable display. Since display-p3 is also the most broadly supported wide-gamut space, it is the right first choice in the vast majority of cases, before even considering more exotic spaces like prophoto-rgb.

3. a98-rgb and prophoto-rgb: color spaces from professional photography

a98-rgb corresponds to the classic Adobe RGB color space, used for decades in professional photography and print, and offers more color depth than sRGB especially in the cyan-green range. It matters when image material was already produced in Adobe RGB, for example from a professional camera or image-editing pipeline, and needs to be displayed on the web without a lossy conversion.

prophoto-rgb goes a step further and covers a color space larger than any current consumer display can actually render. It is used almost exclusively in professional RAW image-editing workflows, as an intermediate format with maximum color reserve. For web applications, prophoto-rgb is rarely the right choice in practice, since no widespread display can even show its full range, and the values effectively get downmapped to the display's gamut anyway.

4. rec2020: the color space for HDR video and future displays

rec2020, also called BT.2020, is the color space standard for UHD and HDR video and covers an even larger range than display-p3. Current consumer displays can so far only partially exploit this color space, which is why the practical benefit of rec2020 in ordinary web design remains limited today. It becomes relevant primarily for video content already mastered in rec2020, and for projects deliberately preparing for future display generations.

Anyone using rec2020 values in CSS today should be aware that the actually visible color on most current devices is limited to the respective display's gamut anyway, meaning the browser automatically falls back to the best renderable value. That makes rec2020 an investment in the future, whose effect only fully unfolds with broader hardware support.


.video-overlay {
  /* rec2020 for future HDR-capable displays,
     the browser automatically falls back to the renderable gamut */
  background: color(rec2020 0.7 0.05 0.1 / 0.85);
}

5. color() compared to oklch() and lab()

oklch() and lab() describe self-contained, perceptually based color models, in which equal numeric distances are also perceived as equally sized color differences, regardless of the rendering device. That makes them ideal for computing gradients, color palettes, or algorithmically generated color tones, because interpolation in these spaces looks more even than in classic RGB.

The generic color() function, on the other hand, addresses a different question: not how a color is computed or mixed, but in which color space it should actually be encoded and rendered. In practice, both concepts do not exclude each other: a color can be computed in oklch() and then converted for display into a wide-gamut color space like display-p3, if a certain saturation would not even be reachable within sRGB.

6. Fallback strategy for browsers and displays without wide-gamut support

Not every browser supports color() with wide-gamut color spaces, and even where it does, the connected display might still only render sRGB. That's why every use of color(display-p3 ...) needs an sRGB fallback, written as a regular rgb() or hex declaration before the modern declaration, since CSS keeps the last valid declaration of a property when a value is not recognized.

This cascade order works automatically: a browser without wide-gamut support ignores the color() line entirely and stays on the preceding sRGB value, with no @supports check needed at all. What matters is only that the sRGB fallback actually precedes the wide-gamut declaration, since CSS always applies the last valid declaration at equal specificity.


.brand-accent {
  /* sRGB fallback first */
  color: rgb(217, 70, 239);
  /* Wide-gamut value after -- ignored if unsupported */
  color: color(display-p3 0.83 0.28 0.93);
}

7. Practical example: product photos and brand colors with display-p3

An online shop with color-intensive products, for example fashion items or cosmetics, benefits most directly from display-p3, because exactly this market segment is where color fidelity of product presentation can be a purchase-deciding factor. Instead of only shipping the product photo itself in a wide-gamut format, it pays off to also define accompanying UI elements like accent colors, badges, or call-to-action buttons in display-p3, so overall brand perception feels consistently richer.

For actual corporate branding, for example a logo's primary color, display-p3 pays off especially when the brand color sits near the edge of the sRGB color space, for example a very saturated pink or orange. If the brand color comfortably sits within the sRGB space already, for example a muted blue or gray, display-p3 brings hardly any visible difference and the extra maintenance effort rarely pays off in that case.

8. Determining wide-gamut values: tooling and conversion

Wide-gamut color values cannot simply be derived from an existing sRGB hex code, because an actual color space conversion is required, not just a numeric transformation. Modern image-editing programs like Photoshop or Affinity Photo display color values directly in the chosen target color space, and several browser-based color picker tools now support direct output of color(display-p3 ...) syntax as well.

Anyone wanting to maintain brand colors consistently across multiple color spaces should store them in a central design token system as a pair of sRGB fallback and display-p3 value, similar to light-dark() value pairs for color schemes. That prevents wide-gamut values from existing only sporadically in isolated spots of the project while the rest of the stylesheet stays limited to pure sRGB.


:root {
  --brand-pink-srgb: rgb(236, 72, 153);
  --brand-pink-p3: color(display-p3 0.87 0.36 0.58);
}

.badge {
  background: var(--brand-pink-srgb);
  background: var(--brand-pink-p3);
}

9. Browser support status for color() and wide-gamut color spaces

Safari has fully supported display-p3 through color() for several years already, which is unsurprising given its close ties to Apple's own wide-gamut displays. Chrome and Edge followed with complete color() support, so the function is now production ready across all three major browser engines.

The display side remains the limiting factor regardless: even a browser with full color() support cannot show a visible difference on a classic sRGB monitor, because the hardware simply cannot render the additional hues. The cascade-based fallback mechanism therefore stays sensible for the long term too, independent of pure browser support status.

Color space Coverage vs. sRGB Typical source Web relevance today
display-p3 Noticeably more red/green Apple devices, modern monitors High, widely available hardware
a98-rgb More cyan/green Professional photography, print Medium, niche-specific
prophoto-rgb Larger than any display RAW image editing Low, barely renderable
rec2020 Largest of all HDR video, UHD standards Low, future investment

Mironsoft

Modern CSS, layout architecture and rendering performance

CSS that stays maintainable instead of breaking with every change?

We review existing stylesheets for specificity chaos and layout thrashing, then build a CSS architecture with cascade layers, custom properties and modern layout primitives that still makes sense after the tenth feature.

CSS Audit

Systematically uncovering specificity issues, cascade conflicts and unused selectors.

Architecture Refactoring

Introducing cascade layers, custom properties and design tokens cleanly.

Performance Tuning

Fixing layout thrashing, expensive selectors and rendering bottlenecks.

10. Summary

The color() Function in CSS: The Essentials at a Glance

Core idea

color(space values) encodes colors explicitly in a named color space, instead of implicitly assuming sRGB.

display-p3

The most relevant wide-gamut space for today's web projects, broadly supported on consumer hardware.

a98-rgb, prophoto-rgb, rec2020

Special cases from photography and video, of limited practical relevance for most web projects today.

Fallback

An sRGB value before the color() declaration automatically applies in browsers or on displays without wide-gamut support.

11. FAQ: The color() Function in CSS: The Essentials at a Glance

1What does the color() function do in CSS?
color() is a generic function that encodes color values explicitly in a named color space like display-p3, a98-rgb, prophoto-rgb or rec2020, instead of implicitly assuming sRGB.
2What is the difference between color() and oklch()?
oklch() describes a self-contained, perceptually based color model for calculations and interpolation. color() specifies which color space a color is encoded and rendered in.
3Which wide-gamut color space matters for most projects?
display-p3, because it is the most broadly supported wide-gamut space on current consumer hardware, especially on Apple devices and modern monitors.
4When should I use a98-rgb?
When image material already comes from the Adobe RGB color space in a professional photo or print pipeline and needs to be displayed without a lossy conversion.
5Does prophoto-rgb make sense for web projects?
Barely, because no widespread consumer display can render the full range of prophoto-rgb. It is primarily an intermediate format for professional RAW image editing.
6What is rec2020 used for in CSS?
Mainly for HDR video content and as preparation for future display generations. Current consumer displays can so far only partially render the full rec2020 color space.
7How do I safeguard color() for browsers without wide-gamut support?
By placing a regular sRGB value before the color() declaration. Browsers without support ignore the color() line and keep the preceding value.
8Is the difference between sRGB and display-p3 visible on every display?
No, only on displays with an actual wide-gamut panel. On classic sRGB monitors, the color value automatically gets limited to the renderable gamut.
9Can I derive color() values directly from a hex code?
No, an actual color space conversion is required, not just a numeric transformation. Image-editing programs or browser-based color pickers help determine the right values.
10Do all major browsers support color() by now?
Yes, Safari, Chrome and Edge now fully support color() with the common color spaces in current versions.