Color Theory

Color Gamut Mapping: Converting Between Color Spaces

9 min read

When you photograph a vivid sunset on a professional camera and open it in a web browser, something is lost. The deep, saturated oranges and purples that the camera's wide-gamut sensor recorded cannot be reproduced exactly on every display — and even when they can, the colors might not survive conversion to a web-safe format. This process of adapting colors that exist in one color space to fit within the boundaries of another is called gamut mapping. It is one of the least visible but most consequential operations in the entire digital color pipeline, and understanding it is essential for anyone who cares about color accuracy from design to production.

What Is Gamut Mapping?

A color gamut is the complete range of colors that a particular device, format, or color space can represent. Every gamut has boundaries — colors that fall within them can be represented accurately; colors outside them cannot.

Different devices and color spaces have different gamuts:

Color Space / Device Gamut Size Use Case
sRGB Smallest (standard) Web, most consumer monitors
Display P3 ~26% larger than sRGB iPhone, Mac displays, modern Android
Adobe RGB ~35% larger than sRGB Professional photography, print
Rec. 2020 ~57% larger than sRGB HDR video, future displays
ProPhoto RGB Largest RAW photo editing

When you move a color from a larger gamut to a smaller one, some colors may fall outside the target gamut. These are called out-of-gamut colors. Gamut mapping is the process of deciding what to do with them.

The reverse — moving from a smaller gamut to a larger one — is generally lossless, since all the source colors fit within the destination. A sRGB file displayed on a Display P3 monitor simply uses a subset of that monitor's range. No gamut mapping needed.

The Out-of-Gamut Colors Problem

Consider a vivid cyan: #00FFFF (#00FFFF) in sRGB. This color sits near the edge of the sRGB gamut. In Display P3, there are more saturated cyans available — colors that sRGB cannot represent at all.

Now imagine you design an interface in Display P3, using a vivid green that falls outside sRGB: approximately color(display-p3 0.0 0.9 0.3) — a green significantly more saturated than #00E84A (#00E84A) in sRGB. When a user views this on a standard sRGB monitor, the browser must make a decision: what sRGB color should represent this unreproducible green?

This decision is gamut mapping, and there are several approaches with different trade-offs.

Clipping vs Perceptual Compression

The two primary strategies for handling out-of-gamut colors are clipping and perceptual (compression) mapping.

Clipping

Clipping is the simplest approach: colors outside the gamut are snapped to the nearest point on the gamut boundary. It is analogous to taking a value of 1.5 in a 0–1 scale and simply setting it to 1.

For a color with an out-of-gamut saturation value, clipping sets that saturation to the maximum value the target gamut allows, while leaving lightness and hue unchanged. The result:

  • Colors near the boundary: minimal visible change
  • Colors far outside the gamut: significant loss of hue accuracy, colors that may appear very different from the original

The biggest problem with clipping is hue shift. Many out-of-gamut colors clip in a way that shifts their hue perceptibly. A vivid green can clip to a yellow-green; a deep violet can clip to a blue. The original hue is not preserved.

Clipping also creates banding: a range of different source colors all clip to the same maximum-saturation boundary point, producing visible steps in gradients or smooth color transitions that should appear continuous.

Despite these drawbacks, clipping is common for static images and CSS because it is computationally trivial.

Perceptual Rendering Intent (Compression)

Perceptual rendering — sometimes called compression mapping — takes a different approach. Instead of only adjusting out-of-gamut colors, it scales the entire gamut proportionally. The most saturated colors in the source are mapped to the most saturated colors available in the destination, and everything else scales accordingly.

Imagine you are fitting a large painting (Display P3 gamut) onto a smaller canvas (sRGB gamut) by reducing the entire painting proportionally rather than cropping. No colors are cut off; instead, all relationships between colors are preserved — just compressed.

Advantages of perceptual compression: - Smooth gradients remain smooth (no banding) - Relative relationships between colors are preserved - Generally more visually pleasing for photography and gradients

Disadvantages: - In-gamut colors are also shifted (scaled down slightly in saturation), even if they did not need to be - Colors may look slightly less vivid than the original, even where they could have been reproduced accurately

Perceptual rendering intent is the default used by ICC color profiles in print and professional photography workflows. It is also the approach used by the CSS gamut mapping algorithm.

Relative Colorimetric (with Black Point Compensation)

A third approach — relative colorimetric — maps in-gamut colors exactly and clips out-of-gamut colors, while adjusting for the difference in white point between the source and destination. It is a good compromise for documents with few out-of-gamut colors, as it preserves in-gamut accuracy better than perceptual.

Saturation Rendering Intent

A fourth intent used mainly in business graphics: maximize saturation at the expense of hue accuracy. Used for bar charts and pie charts where vivid, distinct colors matter more than accurate hue reproduction.

CSS Gamut Mapping

CSS has supported multiple color spaces since the CSS Color Level 4 specification, and gamut mapping is now built into the CSS color resolution algorithm.

Specifying Wide-Gamut Colors in CSS

/* sRGB (traditional) */
color: #22C55E;
color: rgb(34, 197, 94);

/* Display P3 (wide gamut) */
color: color(display-p3 0.05 0.8 0.35);

/* Rec. 2020 (ultra-wide) */
color: color(rec2020 0.1 0.7 0.2);

/* OKLCH (perceptually uniform, can address wide-gamut colors) */
color: oklch(0.75 0.25 150);  /* Very vivid green — may be out of sRGB */

How CSS Handles Gamut Overflow

When a CSS color value addresses a color that is outside the display's gamut, the browser applies the CSS gamut mapping algorithm defined in CSS Color Level 4. The algorithm uses binary search in OKLCH color space to find the most similar in-gamut color using deltaE 2000 (a perceptual color difference metric) as the distance measure.

The result is a gamut mapping approach that prioritizes: 1. Preserving lightness first (lightness shifts are the most perceptible) 2. Preserving hue second 3. Reducing chroma (saturation) until the color fits within the target gamut

This is a significant improvement over simple sRGB clipping. The CSS algorithm produces results closer to perceptual compression for colors that are only slightly out-of-gamut, while degrading gracefully for colors far outside.

The color-gamut Media Query

CSS provides a media query to detect what gamut the display supports, allowing you to serve different colors to different capabilities:

/* Default: sRGB colors for all displays */
.brand-color {
  color: #22C55E;
}

/* Enhanced: more vivid P3 colors for capable displays */
@media (color-gamut: p3) {
  .brand-color {
    color: color(display-p3 0.05 0.8 0.35);
  }
}

/* Ultra-wide: maximum vibrancy for Rec. 2020 displays */
@media (color-gamut: rec2020) {
  .brand-color {
    color: color(rec2020 0.1 0.7 0.2);
  }
}

The three values for color-gamut: - srgb — display covers approximately the sRGB gamut (most common) - p3 — display covers approximately the Display P3 gamut (modern Mac, iPhone, high-end Android) - rec2020 — display covers approximately the Rec. 2020 gamut (professional and HDR displays)

OKLCH and Wide Gamut

OKLCH is particularly well-suited for wide-gamut design work because high-chroma values naturally address colors outside sRGB. A chroma value above approximately 0.37 in OKLCH will be out of sRGB gamut for most hues, landing in Display P3 or beyond.

/* In sRGB: vivid green */
color: oklch(0.75 0.22 145);

/* Out of sRGB, in Display P3: more vivid green */
color: oklch(0.75 0.35 145);

/* Far out of sRGB: browser will gamut-map down */
color: oklch(0.75 0.5 145);

When an OKLCH color is out of gamut, CSS automatically applies its gamut mapping algorithm. You do not need to manually handle this — the browser resolves it.

Use the Color Converter to convert colors between color spaces and see how values shift when moving between sRGB, Display P3, and OKLCH representations.

Practical Solutions for Designers

Understanding gamut mapping changes how you approach color work for screens:

1. Design in the Target Gamut

If your product targets primarily web users on a mix of devices, design in sRGB. If you know your audience is primarily on modern Apple hardware (Mac, iPhone), consider designing in Display P3 and providing sRGB fallbacks.

2. Know Your Vivid Colors' Gamut Status

Many vivid colors that "work" in tools like Figma (which uses Display P3 on Apple hardware) may look different when exported to sRGB for web use. Always verify final colors with a CSS value you have explicitly defined, not just what Figma renders on your screen.

Some extremely vivid greens, cyans, and magentas in Design P3 have no sRGB equivalent. If your brand color is color(display-p3 0.0 0.9 0.3) — a green more vivid than any sRGB green — you need to decide what sRGB fallback to use, or accept that sRGB users will see a less vivid version.

3. Test Gradient Transitions Across Gamuts

Gradients between two wide-gamut colors can produce banding when displayed on sRGB monitors, because intermediate colors that looked distinct in P3 all map to similar sRGB values (color clipping in the middle of the gradient). If you see banding in a gradient, try:

  • Reducing the chroma of both endpoints to sRGB-safe levels
  • Adding intermediate gradient stops to spread the transition
  • Routing the gradient through OKLCH for perceptually even spacing

4. Use the Correct Export Format

For images containing wide-gamut colors: - JPEGs: Embed the color profile (Display P3 or Adobe RGB) — browsers will use it for color management - PNGs: Same — embed the profile - WebP: Supports ICC profiles; embed for accurate color - SVG: Colors are specified in CSS — use color() function for wide gamut

Images without embedded profiles are assumed to be sRGB and will be displayed without gamut conversion. A wide-gamut image without an embedded profile will appear more washed out than intended on P3 displays.

5. The Safe Wide-Gamut Approach

For designers who want richer colors without the complexity of managing multiple gamut targets, OKLCH with moderate chroma (0.18–0.25) stays mostly within sRGB while providing slightly more vivid results than typical RGB colors in that range. The CSS gamut mapping handles any edge cases automatically.

/* Vivid but mostly sRGB-safe blues */
--color-primary: oklch(0.55 0.22 255);
--color-primary-hover: oklch(0.60 0.22 255);

Key Takeaways

  • A color gamut is the range of colors a device or color space can represent. sRGB is standard web; Display P3 is ~26% larger and available on modern Apple and high-end devices.
  • Out-of-gamut colors are colors that fall outside a target gamut and cannot be reproduced accurately on that device — something must happen to bring them in bounds.
  • Clipping snaps out-of-gamut colors to the gamut boundary — fast but can cause hue shifts and banding. Perceptual compression scales the entire gamut proportionally — slower but preserves color relationships and gradients.
  • CSS Color Level 4 defines a gamut mapping algorithm that uses OKLCH and deltaE 2000 to intelligently reduce chroma while preserving lightness and hue — far superior to naive sRGB clipping.
  • The color-gamut media query lets you serve more vivid color(display-p3) colors to capable displays while maintaining sRGB fallbacks for others.
  • Wide-gamut design pitfalls: Figma on Apple hardware renders Display P3 by default — colors that look vivid in Figma may look less saturated when exported as sRGB for web use. Always verify with explicit CSS values.
  • Use the Color Converter to inspect how any color translates across sRGB, Display P3, and OKLCH to understand its gamut status and find the closest in-gamut equivalent.

Related Colors

Related Brands

Related Tools