# .toOKLab()

Get a color in OKLab, where straight-line math between colors looks even, for your own blends.

Do your own color math in OKLab with `toOKLab()`: lightness plus two axes, green to red (`a`) and blue to yellow (`b`), spaced so equal steps look equal. It takes nothing and returns an `OKLabColor`:

```swift
Color(hex: "#00B386").toOKLab()   // OKLabColor(l: 0.680, a: -0.136, b: 0.031)
```

## Mixing in a straight line

OKLab mixes two colors along a straight line, so the middle can be a little grayer than either end. OKLCH turns around the hue wheel instead and keeps chroma up:

```swift
let start = Color(hex: "#00B386")
let end = Color.proSky._200.toOKLCH()

start.toOKLab().lerp(end.toOKLab(), t: 0.5)   // #64C9C1, a little grayer
start.toOKLCH().lerp(end, t: 0.5)             // #4BCACF
```

- OKLab halfway: #64c9c1
- OKLCH halfway: #4bcacf

To mix two tokens and keep dark mode, use [`blend(with:by:)`](https://colortokenskit.com/api/blend/index.md). [`.lerp(_:t:)`](https://colortokenskit.com/api/lerp/index.md) compares every space.

## Same lightness as OKLCH

OKLab and OKLCH share their lightness, `l`. OKLCH writes `a` and `b` as a chroma, how far from gray, and a hue angle, so `toOKLCH()` turns one into the other without any change in color.

OKLab's lightness isn't CIELab L\*, the lightness contrast depends on, so two colors with the same `l` can have different contrast on white. [Why OKLCH?](https://colortokenskit.com/under-the-hood/why-oklch/index.md) shows a pair.

## How it behaves

Conversions pass through extended sRGB without clipping, so a Display P3 color comes through unchanged. Inside sRGB, `a` runs from about −0.23 to 0.28 and `b` from about −0.31 to 0.2; Display P3 colors reach further. A token gives its light-mode value on iOS 17, macOS 14 and later.

From an `OKLabColor` you can go to `toRGB()`, `toLAB()`, `toLCH()`, `toOKLCH()` and `toColor()`, which gives an opaque color.

## API

```swift
public extension Color {
    func toOKLab() -> OKLabColor
}

public struct OKLabColor: Hashable, Sendable {
    public let l: CGFloat       // 0 to 1
    public let a: CGFloat       // green (negative) to red (positive)
    public let b: CGFloat       // blue (negative) to yellow (positive)
    public let alpha: CGFloat   // 0 to 1

    public init(l: CGFloat, a: CGFloat, b: CGFloat, alpha: CGFloat = 1)

    public func lerp(_ other: OKLabColor, t: CGFloat) -> OKLabColor
    public func toRGB() -> RGBColor
    public func toLAB() -> LABColor
    public func toLCH() -> LCHColor
    public func toOKLCH() -> OKLCHColor
    public func toColor() -> Color
}
```

`toOKLab()` takes no parameters.

## Sources

- [Color+ColorSpaces.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Platform/SwiftUI/Color+ColorSpaces.swift), which defines `toOKLab()` on `Color`.
- The [OKLab](https://github.com/metasidd/ColorTokensKit-Swift/tree/main/Sources/ColorTokensKit/ColorSpace/OKLab) folder, which defines `OKLabColor`.
- Björn Ottosson, [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/) (2020), which introduces OKLab.

## See also

- [.toOKLCH()](https://colortokenskit.com/api/to-oklch/index.md): Read a color's lightness, chroma and hue the way the palette sees them, to compare or adjust it.
- [.lerp(\_:t:)](https://colortokenskit.com/api/lerp/index.md): Find the color partway between two others, for your own blends, chart scales or animations.
- [.blend(with:by:)](https://colortokenskit.com/api/blend/index.md): Mix two colors into one that follows dark mode, or fade a color out cleanly.
- [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.

---

From ColorTokensKit, by Penguin Design Ventures: https://colortokenskit.com/api/to-oklab/ (updated September 26, 2026).
