# Fitting colors into Display P3

Stay inside Display P3 without losing contrast: chroma drops, lightness holds.

The live page plots one hue's slice of OKLCH, chroma against lightness, colored where Display P3 can show the color, with the ramp's stops marked. It starts at hue 40. [Try it on the live page](https://colortokenskit.com/under-the-hood/gamut-mapping/).

The colored area is every color [Display P3](https://colortokenskit.com/reference/glossary/index.md#display-p3) can show at hue 40°, coral, with lightness up and [chroma](https://colortokenskit.com/reference/glossary/index.md#chroma) to the right. It's widest at medium lightness and narrows toward white and black, so a vivid light coral has nowhere to go. Drag the hue to see where other hues run out.

```swift
let coral = OKLCHColor(l: 0.85, c: 0.25, h: 40)   // beyond Display P3
coral.toColor()                                   // passed on as is, so the system clips it
```

Clipping a light coral into Display P3 makes it about two stops darker, and more orange. So when ColorTokensKit makes a color, it lowers chroma instead and keeps lightness, and with it contrast. A color you build yourself, like this one, is left as it is.

## Tokens and color functions hold lightness

```swift
// Asks for chroma 0.300; Display P3 allows 0.236 at this lightness and hue.
Color.proGreen._500.toColor().saturate(by: 1)   // L* 58.2, 3.37:1 on white, as before
```

Ask [`saturate(by:)`](https://colortokenskit.com/api/saturate/index.md) for more chroma than Display P3 can show, and you get the most it can, at the same contrast. The ramps and the other color functions fit colors the same way, and a palette color lands on [an exact stop](https://colortokenskit.com/under-the-hood/palette-snapping/index.md) instead.

## Blends and gradients follow CSS Color 4

`blend(with:by:)` and every `proGradient` blend fit colors into Display P3 with the gamut mapping CSS Color 4 defines for browsers. It lowers chroma at the same OKLCH lightness, and stops once clipping would be within a just-noticeable difference. That keeps colors at the edge of the gamut vivid, and [gradients](https://colortokenskit.com/under-the-hood/gradient-blends-and-easing/index.md) free of kinks. L\* can shift a little, which a gradient can afford because it doesn't set text contrast.

## sRGB-only screens

- proTeal.\_600: #0a837f
- Clipped to sRGB: #008580

The palette targets Display P3, the gamut of every iPhone since the iPhone 7, and 301 of its 720 colored stops lie beyond [sRGB](https://colortokenskit.com/reference/glossary/index.md#srgb). There's no sRGB fallback. On a screen that only shows sRGB, such as many external monitors, the system clips those colors, so they look less vivid.

Clipping moves lightness a little too. The text tokens keep AA with room to spare, but a bare `_600` from mint to cerulean can drop to 4.48:1 on white, just under AA.

Hex can't hold these colors either: `getHexString()` clamps a color beyond sRGB into it. This wiki writes palette colors as Display P3 hex.

## Sources

- W3C, [CSS Color Module Level 4, gamut mapping](https://www.w3.org/TR/css-color-4/#gamut-mapping), and its definition of [`display-p3`](https://www.w3.org/TR/css-color-4/#predefined-display-p3).
- Björn Ottosson, [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/) (2020), for OKLab.
- ColorTokensKit source, [Gamut.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Services/Ramps/Gamut.swift).

## See also

- [What does equal lightness cost?](https://colortokenskit.com/under-the-hood/trade-offs/index.md): What equal contrast costs, from quieter reds to olive yellows, and what you can do about each.
- [Why OKLCH?](https://colortokenskit.com/under-the-hood/why-oklch/index.md): Every hue looks evenly matched at each stop, so you can swap families without rechecking contrast.
- [.toRGB()](https://colortokenskit.com/api/to-rgb/index.md): Read a color's red, green and blue channels, even past sRGB, to hand to other graphics code.
- [How did we choose and build these colors?](https://colortokenskit.com/basics/how-the-colors-were-built/index.md): Why every hue shares one lightness and one chroma at each stop, and how the 36 hues were named.

---

From ColorTokensKit, by Penguin Design Ventures: https://colortokenskit.com/under-the-hood/gamut-mapping/ (updated September 26, 2026).
