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