Skip to main content

OKLAB Cartesian Coordinate System

OKLAB is a Cartesian coordinate system for color representation, fundamentally different from the polar coordinate system used by OKLCH. While OKLCH uses Lightness (L), Chroma (C), and Hue (H) in a cylindrical arrangement, OKLAB uses three perpendicular axes.
┌──────────────────────────────────────────────────────────────────────────────┐
│  OKLAB CARTESIAN COORDINATE SYSTEM                                           │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│                              +b (Yellow)                                     │
│                                  │                                           │
│                                  │                                           │
│                                  │                                           │
│                                  │     * (L, a, b)                           │
│                                  │    /                                      │
│                                  │   /                                       │
│                                  │  /                                        │
│              -a ─────────────────┼───────────────── +a                       │
│            (Green)               │   \           (Red/Magenta)               │
│                                  │    \                                      │
│                                  │     \                                     │
│                                  │      * Second Color                       │
│                                  │                                           │
│                              -b (Blue)                                       │
│                                                                              │
│  L axis: Perpendicular to this plane (0 = black, 1 = white)                  │
│  a axis: Green (-) to Red/Magenta (+)                                        │
│  b axis: Blue (-) to Yellow (+)                                              │
│                                                                              │
│  KEY PROPERTY: Straight line between two colors = perceptually uniform path  │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Mathematical Relationship: OKLAB to OKLCH

The conversion between OKLAB (Cartesian) and OKLCH (Polar) follows standard coordinate transformation equations:
┌──────────────────────────────────────────────────────────────────────────────┐
│  COORDINATE CONVERSION FORMULAS                                              │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  OKLAB (Cartesian) → OKLCH (Polar):                                          │
│  ──────────────────────────────────                                          │
│  C = √(a² + b²)           // Chroma = distance from center                   │
│  H = atan2(b, a) × 180/π  // Hue = angle in a,b plane                        │
│  if H < 0: H += 360       // Normalize to [0, 360)                           │
│                                                                              │
│  OKLCH (Polar) → OKLAB (Cartesian):                                          │
│  ──────────────────────────────────                                          │
│  a = C × cos(H × π/180)   // a-axis projection                               │
│  b = C × sin(H × π/180)   // b-axis projection                               │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
// Cartesian to Polar conversion
// Chroma = distance from center (magnitude of a,b vector)
const c = Math.sqrt(a * a + b * b);

// Hue = angle in a,b plane (converted to degrees)
let h = (Math.atan2(b, a) * 180) / Math.PI;
if (h < 0) h += 360;
And the reverse transformation:
// Polar to Cartesian conversion
// a = C * cos(H)
const a = oklch.c * Math.cos((oklch.h * Math.PI) / 180);
// b = C * sin(H)
const b = oklch.c * Math.sin((oklch.h * Math.PI) / 180);

Coordinate System Comparison

┌──────────────────────────────────────────────────────────────────────────────┐
│  COORDINATE SYSTEM COMPARISON: OKLCH vs OKLAB                                │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  OKLCH (Polar/Cylindrical)           OKLAB (Cartesian/Rectangular)           │
│  ═════════════════════════           ═════════════════════════════           │
│                                                                              │
│       L (Lightness)                       L (Lightness)                      │
│           │                                   │                              │
│           │    H (Hue)                        │   +b                         │
│           │   /  \                            │   │                          │
│           │  /    \                           │   │                          │
│           │ /      \                     -a ──┼───┼───+a                     │
│           │         \                         │   │                          │
│           ┼──────────\                        │  -b                          │
│           │     C     \                       │                              │
│           │  (radius)  \                                                     │
│                                                                              │
│  Intuitive for:                      Optimal for:                            │
│  • Human color selection             • Linear interpolation                  │
│  • Hue rotation                      • Color mixing                          │
│  • Identity definition               • Transparency blending                 │
│  • Golden angle distribution         • Gradient generation                   │
│                                                                              │
│  CSS: oklch(L% C H)                  CSS: oklab(L% a b)                      │
│  Example: oklch(55% 0.15 230)        Example: oklab(55% -0.12 -0.09)         │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

The color-mix() Function

The color-mix() function was introduced in CSS Color Level 5 to enable programmatic color blending directly in CSS.
color-mix(in <color-space>, <color1> [<percentage>], <color2> [<percentage>])
Where:
  • <color-space>: The interpolation color space (srgb, lab, oklab, oklch, etc.)
  • <color1>, <color2>: The colors to blend
  • <percentage>: Optional weighting (default 50% each)

Why OKLAB for color-mix()?

/* Using color-mix() for perceptually accurate transparency (in oklab color space) */

/* Light overlays (using color-mix in oklab) */
--color-overlay-light-1: color-mix(in oklab, var(--color-text-primary), transparent 92%);
--color-overlay-light-2: color-mix(in oklab, var(--color-text-primary), transparent 88%);
--color-overlay-light-3: color-mix(in oklab, var(--color-text-primary), transparent 84%);
--color-overlay-light-4: color-mix(in oklab, var(--color-text-primary), transparent 80%);

/* Dark overlays (using color-mix in oklab) */
--color-overlay-dark-1: color-mix(in oklab, black, transparent 95%);
--color-overlay-dark-2: color-mix(in oklab, black, transparent 90%);
--color-overlay-dark-3: color-mix(in oklab, black, transparent 80%);
--color-overlay-dark-4: color-mix(in oklab, black, transparent 70%);

Interpolation Behavior: OKLAB vs sRGB

┌──────────────────────────────────────────────────────────────────────────────┐
│  INTERPOLATION PATH COMPARISON                                               │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Example: Mixing Blue (oklch 55% 0.15 230) with Orange (oklch 55% 0.15 50)   │
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐  │
│  │                    sRGB Interpolation                                  │  │
│  │                    (NON-perceptually uniform)                          │  │
│  │                                                                        │  │
│  │         Blue ──────────► MUDDY ◄────────── Orange                      │  │
│  │         #2380c7          BROWN             #b58900                     │  │
│  │                          #7d7064                                       │  │
│  │                                                                        │  │
│  │  Path curves through low-saturation zone = "muddy" appearance          │  │
│  └────────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐  │
│  │                    OKLAB Interpolation                                 │  │
│  │                    (Perceptually uniform)                              │  │
│  │                                                                        │  │
│  │         Blue ──────────► CLEAN ◄────────── Orange                      │  │
│  │         #2380c7          PURPLE            #b58900                     │  │
│  │                          #8b6aa0                                       │  │
│  │                                                                        │  │
│  │  Straight line through color space = maintains saturation              │  │
│  └────────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
│  KEY INSIGHT: OKLAB's straight-line interpolation preserves perceived        │
│  chroma throughout the transition, preventing "muddy" intermediate colors.   │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

color-mix() Pattern Taxonomy

┌──────────────────────────────────────────────────────────────────────────────┐
│  COLOR-MIX() PATTERN TAXONOMY                                                │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  PATTERN A: Transparency Derivation                                          │
│  ══════════════════════════════════                                          │
│                                                                              │
│  color-mix(in oklab, <CORE-COLOR>, transparent <N%>)                         │
│                                                                              │
│  Purpose: Create semi-transparent versions of Core Colors                    │
│  Usage:   Backgrounds, selections, overlays                                  │
│                                                                              │
│  ──────────────────────────────────────────────────────────────────────────  │
│                                                                              │
│  PATTERN B: Lightness Adjustment                                             │
│  ═══════════════════════════════                                             │
│                                                                              │
│  color-mix(in oklch, <CORE-COLOR>, white <N%>)                               │
│  color-mix(in oklab, <CORE-COLOR>, black <N%>)                               │
│                                                                              │
│  Purpose: Create lighter/darker variants of Core Colors                      │
│  Usage:   Hover states, active states, shadows                               │
│                                                                              │
│  ──────────────────────────────────────────────────────────────────────────  │
│                                                                              │
│  PATTERN C: Saturation Reduction                                             │
│  ═══════════════════════════════                                             │
│                                                                              │
│  color-mix(in oklab, <CORE-COLOR>, gray <N%>)                                │
│                                                                              │
│  Purpose: Desaturate colors (reduce chroma)                                  │
│  Usage:   Disabled states, muted variants, comments                          │
│                                                                              │
│  ──────────────────────────────────────────────────────────────────────────  │
│                                                                              │
│  PATTERN D: Color Blending                                                   │
│  ═════════════════════════                                                   │
│                                                                              │
│  color-mix(in oklab, <CORE-COLOR-A>, <CORE-COLOR-B> <N%>)                    │
│                                                                              │
│  Purpose: Blend two Core Colors together                                     │
│  Usage:   Merge lines, gradients, state transitions                          │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Implementation Examples

/* Derived colors using color-mix() */
--oklch-primary-hover: color-mix(in oklch, var(--oklch-primary), white 15%);
--oklch-primary-muted: color-mix(in oklab, var(--oklch-primary), transparent 80%);
--oklch-success-hover: color-mix(in oklch, var(--oklch-success), white 15%);
--oklch-success-muted: color-mix(in oklab, var(--oklch-success), transparent 80%);
--oklch-danger-hover: color-mix(in oklch, var(--oklch-danger), white 15%);
--oklch-danger-muted: color-mix(in oklab, var(--oklch-danger), transparent 80%);
--oklch-warning-hover: color-mix(in oklch, var(--oklch-warning), white 10%);
--oklch-warning-muted: color-mix(in oklab, var(--oklch-warning), transparent 80%);
Notice the deliberate choice:
  • Hover states: Use oklch for hue preservation during lightening
  • Muted states: Use oklab for perceptually uniform transparency

TypeScript color-mix() Utilities

┌──────────────────────────────────────────────────────────────────────────────┐
│  COLOR-MIX UTILITY FUNCTIONS                                                 │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  colorMix(color1, color2, space, percent)                                    │
│       └──► "color-mix(in {space}, {color1} {percent}%, {color2})"            │
│                                                                              │
│  colorTransparent(color, opacity, space)                                     │
│       └──► "color-mix(in {space}, {color}, transparent {100-opacity}%)"      │
│                                                                              │
│  colorDarker(color, amount=30)                                               │
│       └──► colorMix(color, "black", "oklab", 100-amount)                     │
│                                                                              │
│  colorLighter(color, amount=30)                                              │
│       └──► colorMix(color, "white", "oklab", 100-amount)                     │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
/**
 * Generate CSS color-mix() string
 * @param color1 First color (CSS value or variable)
 * @param color2 Second color (CSS value or variable)
 * @param space Color space for mixing
 * @param percent Percentage of color1 (0-100)
 */
export function colorMix(
  color1: string,
  color2: string,
  space: ColorMixSpace = "oklch",
  percent: number = 50
): string {
  return `color-mix(in ${space}, ${color1} ${percent}%, ${color2})`;
}

/**
 * Generate transparent variant using color-mix
 * @param color CSS color value or variable
 * @param opacity Opacity 0-100
 * @param space Color space (oklab recommended for transparency)
 */
export function colorTransparent(
  color: string,
  opacity: number,
  space: ColorMixSpace = "oklab"
): string {
  return `color-mix(in ${space}, ${color}, transparent ${100 - opacity}%)`;
}

/**
 * Generate darker variant using color-mix
 * Uses oklab for perceptually uniform darkening
 */
export function colorDarker(color: string, amount: number = 30): string {
  return colorMix(color, "black", "oklab", 100 - amount);
}

/**
 * Generate lighter variant using color-mix
 * Uses oklab for perceptually uniform lightening
 */
export function colorLighter(color: string, amount: number = 30): string {
  return colorMix(color, "white", "oklab", 100 - amount);
}

Color Space Decision Matrix

┌──────────────────────────────────────────────────────────────────────────────┐
│  COLOR-MIX() COLOR SPACE DECISION MATRIX                                     │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Operation                      Recommended Space    Reason                  │
│  ═══════════════════════════    ═════════════════    ════════════════════    │
│                                                                              │
│  Mix with white (lighten)       oklch                Preserves hue           │
│  Mix with black (darken)        oklab                Uniform darkening       │
│  Mix with transparent           oklab                Perceptual opacity      │
│  Mix with gray (desaturate)     oklab                Even chroma reduction   │
│  Mix two Core Colors            oklab                No muddy midpoints      │
│  Create hover state             oklch                Identity preservation   │
│  Create active state            oklab                Subtle darkening        │
│  Create disabled state          oklab                Desaturation            │
│  Create selection background    oklab                Clean transparency      │
│  Create gradient                oklab                Smooth transition       │
│                                                                              │
│  DEFAULT RULE: When in doubt, use oklab                                      │
│  EXCEPTION: When preserving hue is critical, use oklch                       │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

THE CENTER

How This Component Helps Visualize Information Flow

Connection to Core-Flow:
├── Flow colors derive from Core using color-mix()
├── OKLAB ensures perceptually uniform transitions
├── No "muddy" colors when flowing between states
└── Information intensity mapped to opacity levels
The OKLAB coordinate system and color-mix() function form the mathematical foundation of the Flow Color system. When a user hovers, clicks, or interacts with an element, the color “flows” from one state to another. OKLAB ensures these transitions appear natural and consistent to human perception. The key insight: straight-line interpolation in OKLAB space preserves perceived color quality, preventing the muddy intermediate colors that plague sRGB-based systems. This means information conveyed through color remains clear throughout all state transitions.

Transparency Patterns

Learn how transparency creates visual hierarchy through opacity gradients