Skip to main content

CSS Color Module Evolution

Modern CSS provides native support for OKLAB/OKLCH color spaces and explicit gradient interpolation control.
┌───────────────────────────────────────────────────────────────────────────────┐
│                    CSS COLOR MODULE EVOLUTION                                  │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Level 1-3 (1996-2011):                                                      │
│   =====================                                                       │
│                                                                               │
│   - rgb(), rgba() - sRGB only                                                │
│   - hsl(), hsla() - sRGB, polar coordinates                                  │
│   - Named colors (140 keywords)                                               │
│   - #RRGGBB, #RGB hex notation                                               │
│                                                                               │
│   Limitations:                                                                │
│   - All interpolation in sRGB (muddy middle)                                 │
│   - No perceptually uniform alternatives                                      │
│   - Limited color gamut (sRGB only)                                          │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Level 4 (2022-2024):                                                        │
│   ===================                                                         │
│                                                                               │
│   New Color Spaces:                                                           │
│   - lab(), lch() - CIE Lab perceptual space                                  │
│   - oklab(), oklch() - Improved perceptual uniformity                        │
│   - color() function for arbitrary color spaces                              │
│   - display-p3, rec2020 wide gamut support                                   │
│                                                                               │
│   New Interpolation:                                                          │
│   - color-mix(in <colorspace>, ...) function                                 │
│   - Explicit interpolation space in gradients                                │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Level 5 (2024-present):                                                     │
│   ======================                                                      │
│                                                                               │
│   Additional Features:                                                        │
│   - Relative color syntax: oklch(from var(--base) l c h)                     │
│   - color-contrast() for accessibility                                       │
│   - Custom color spaces via @color-profile                                   │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘

Gradient Interpolation Syntax

The modern gradient syntax allows explicit specification of interpolation color space.
┌───────────────────────────────────────────────────────────────────────────────┐
│                    GRADIENT INTERPOLATION SYNTAX                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Legacy Syntax (sRGB implicit):                                              │
│   ==============================                                              │
│                                                                               │
│   background: linear-gradient(to right, blue, yellow);                       │
│   /* Interpolates in sRGB - will have muddy middle */                        │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Modern Syntax (explicit color space):                                       │
│   =====================================                                       │
│                                                                               │
│   background: linear-gradient(in oklab to right, blue, yellow);              │
│   /* Interpolates in OKLAB - clean transition */                             │
│                                                                               │
│   background: linear-gradient(in oklch to right, blue, yellow);              │
│   /* Interpolates in OKLCH - may cross through more saturated colors */      │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Full Syntax:                                                                │
│   ============                                                                │
│                                                                               │
│   linear-gradient(                                                            │
│     [in <colorspace>]?                  // Optional: oklab, oklch, srgb, etc │
│     [<hue-interpolation-method>]?       // Optional: shorter, longer, etc    │
│     <direction>,                        // Required: to right, 45deg, etc    │
│     <color-stop-list>                   // Required: colors and positions    │
│   )                                                                           │
│                                                                               │
│   Examples:                                                                   │
│   - linear-gradient(in oklab, red, blue)                                     │
│   - linear-gradient(in oklch shorter hue, red, blue)                         │
│   - linear-gradient(in oklch longer hue to right, red, blue)                 │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘

Hue Interpolation Methods

When using OKLCH (polar coordinates), the hue can be interpolated in different directions around the color wheel.
┌───────────────────────────────────────────────────────────────────────────────┐
│                    HUE INTERPOLATION METHODS                                   │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Given: Red (H=30) to Blue (H=250)                                          │
│                                                                               │
│                          0/360                                                │
│                            │                                                  │
│                       Red  *                                                  │
│                     (30)  /                                                   │
│                          /                                                    │
│                         /  shorter = 140 degrees                             │
│     270 ───────────────┼─────────────── 90                                   │
│                         \                                                     │
│                          \  longer = 220 degrees (other way)                 │
│                           \                                                   │
│                       Blue *                                                  │
│                     (250)                                                     │
│                           │                                                   │
│                          180                                                  │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   shorter hue (default):                                                      │
│   ======================                                                      │
│   - Takes the smaller arc between hues                                       │
│   - 30 -> 250: goes through 0/360 (passing through red, magenta)            │
│   - Distance: 360 - 250 + 30 = 140 degrees                                   │
│                                                                               │
│   longer hue:                                                                 │
│   ============                                                                │
│   - Takes the larger arc between hues                                        │
│   - 30 -> 250: goes through 180 (passing through yellow, green, cyan)       │
│   - Distance: 220 degrees                                                     │
│                                                                               │
│   increasing hue:                                                             │
│   ===============                                                             │
│   - Always increases hue value                                               │
│   - 30 -> 250: 30 -> 250 directly (220 degrees)                             │
│                                                                               │
│   decreasing hue:                                                             │
│   ===============                                                             │
│   - Always decreases hue value                                               │
│   - 30 -> 250: 30 -> 0/360 -> 250 (140 degrees, wrapping)                   │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘

Core-to-Core Gradient Patterns

When creating gradients between two Core Colors, you have three main options.
┌───────────────────────────────────────────────────────────────────────────────┐
│                    CORE-TO-CORE GRADIENT PATTERN                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Base colors: Blue (H=230) to Green (H=130)                                 │
│   Both at: L=55%, C=0.15                                                     │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Option 1: OKLAB (Cartesian, direct)                                         │
│   ====================================                                        │
│                                                                               │
│   background: linear-gradient(                                                │
│     in oklab to right,                                                        │
│     var(--oklch-primary),                                                     │
│     var(--oklch-success)                                                      │
│   );                                                                          │
│                                                                               │
│   Path: Blue(230) ----> Cyan(~180) ----> Green(130)                         │
│   Result: Direct line through color space, passes through cyan region        │
│                                                                               │
│   ┌───────────┬───────────┬───────────┬───────────┐                          │
│   │   BLUE    │   teal    │   CYAN    │  GREEN    │                          │
│   │  vibrant  │  clean    │ (neutral) │  vibrant  │                          │
│   └───────────┴───────────┴───────────┴───────────┘                          │
│                                                                               │
│   Note: Center may be slightly desaturated (geometric midpoint)              │
│   But the transition feels CLEAN, not muddy                                   │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Option 2: OKLCH shorter hue                                                 │
│   ===========================                                                 │
│                                                                               │
│   background: linear-gradient(                                                │
│     in oklch shorter hue to right,                                            │
│     var(--oklch-primary),                                                     │
│     var(--oklch-success)                                                      │
│   );                                                                          │
│                                                                               │
│   Hue distance: 230 - 130 = 100 degrees (shorter = direct)                   │
│   Path: Blue(230) --> Teal(200) --> Cyan(180) --> Turquoise(150) --> Green   │
│                                                                               │
│   ┌───────────┬───────────┬───────────┬───────────┐                          │
│   │   BLUE    │   TEAL    │   CYAN    │  GREEN    │                          │
│   │  C=0.15   │  C=0.15   │  C=0.15   │  C=0.15   │                          │
│   └───────────┴───────────┴───────────┴───────────┘                          │
│                                                                               │
│   Note: ALL intermediate colors have SAME CHROMA                             │
│   This is the most "equal saturation" result                                  │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Option 3: OKLCH longer hue                                                  │
│   ==========================                                                  │
│                                                                               │
│   background: linear-gradient(                                                │
│     in oklch longer hue to right,                                             │
│     var(--oklch-primary),                                                     │
│     var(--oklch-success)                                                      │
│   );                                                                          │
│                                                                               │
│   Hue distance: 360 - 100 = 260 degrees (the long way around)               │
│   Path: Blue --> Purple --> Magenta --> Red --> Orange --> Yellow --> Green │
│                                                                               │
│   ┌───────┬───────┬───────┬───────┬───────┬───────┬───────┐                  │
│   │ BLUE  │PURPLE │ RED   │ORANGE │YELLOW │ LIME  │ GREEN │                  │
│   └───────┴───────┴───────┴───────┴───────┴───────┴───────┘                  │
│                                                                               │
│   Note: RAINBOW effect - passes through entire spectrum                       │
│   Use sparingly! Can be overwhelming.                                         │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘

OKLCH vs OKLAB for color-mix

The choice between OKLCH and OKLAB in color-mix() depends on the use case.
┌───────────────────────────────────────────────────────────────────────────────┐
│                    OKLCH vs OKLAB FOR color-mix()                              │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Use case: Lighten a color (hover state)                                     │
│   ======================================                                      │
│                                                                               │
│   color-mix(in oklch, oklch(55% 0.15 230), white 15%)                        │
│                                                                               │
│   OKLCH interpolation:                                                        │
│   - L: 55% -> 100% (interpolated toward white's 100%)                        │
│   - C: 0.15 -> 0 (interpolated toward white's 0)                             │
│   - H: 230 -> undefined (white has no hue)                                   │
│                                                                               │
│   Result: Lighter, slightly less saturated, same hue                          │
│   This is CORRECT for a hover state.                                          │
│                                                                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Use case: Add transparency (muted state)                                    │
│   ========================================                                    │
│                                                                               │
│   color-mix(in oklab, oklch(55% 0.15 230), transparent 80%)                  │
│                                                                               │
│   OKLAB interpolation:                                                        │
│   - L, a, b interpolate linearly                                             │
│   - Alpha becomes 0.2                                                        │
│                                                                               │
│   OKLAB is preferred because:                                                 │
│   - More predictable behavior with transparency                              │
│   - Avoids hue discontinuities near zero chroma                             │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘

Browser Support

┌───────────────────────────────────────────────────────────────────────────────┐
│                    BROWSER SUPPORT: color-mix() and gradients                  │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   As of December 2024:                                                        │
│   ====================                                                        │
│                                                                               │
│   color-mix():                                                                │
│   Chrome:     111+     (March 2023)                                          │
│   Firefox:    113+     (May 2023)                                            │
│   Safari:     16.2+    (December 2022)                                       │
│   Edge:       111+     (March 2023)                                          │
│   Global support: ~94%                                                        │
│                                                                               │
│   oklch() / oklab():                                                          │
│   Chrome:     111+     (March 2023)                                          │
│   Firefox:    113+     (May 2023)                                            │
│   Safari:     15.4+    (March 2022)                                          │
│   Edge:       111+     (March 2023)                                          │
│   Global support: ~94%                                                        │
│                                                                               │
│   gradient interpolation (in <colorspace>):                                   │
│   Chrome:     111+     (March 2023)                                          │
│   Firefox:    121+     (December 2023)                                       │
│   Safari:     16.2+    (December 2022)                                       │
│   Edge:       111+     (March 2023)                                          │
│   Global support: ~93%                                                        │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘

CSS Implementation Examples

/* Core Colors (OKLCH) */
:root {
  --oklch-primary: oklch(55% 0.15 230);
  --oklch-success: oklch(55% 0.15 130);
  --oklch-danger: oklch(55% 0.18 25);
  --oklch-warning: oklch(65% 0.15 85);
}

/* Flow: Hover states use OKLCH */
:root {
  --oklch-primary-hover: color-mix(in oklch, var(--oklch-primary), white 15%);
  --oklch-success-hover: color-mix(in oklch, var(--oklch-success), white 15%);
}

/* Flow: Transparency uses OKLAB */
:root {
  --oklch-primary-muted: color-mix(in oklab, var(--oklch-primary), transparent 80%);
  --oklch-success-muted: color-mix(in oklab, var(--oklch-success), transparent 80%);
}

/* Overlays always use OKLAB */
:root {
  --color-overlay-light-1: color-mix(in oklab, var(--color-text-primary), transparent 92%);
  --color-overlay-dark-1: color-mix(in oklab, black, transparent 95%);
}

/* Gradients between Core Colors */
.gradient-header {
  background: linear-gradient(
    in oklab to right,
    var(--oklch-primary),
    var(--oklch-success)
  );
}

/* Fallback for older browsers */
.gradient-header {
  background: linear-gradient(to right, #0066cc, #00aa55);
  background: linear-gradient(
    in oklab to right,
    oklch(55% 0.15 230),
    oklch(55% 0.15 130)
  );
}

Decision Matrix

┌───────────────────────────────────────────────────────────────────────────────┐
│                    WHEN TO USE WHICH COLOR SPACE                               │
├───────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│   Use OKLCH when:                                                             │
│   ================                                                            │
│   - Defining identity colors (Core Colors)                                   │
│   - Mixing with black/white (no hue change)                                  │
│   - Creating color palettes with hue rotation                                │
│   - Need to preserve chroma during lightening                                │
│                                                                               │
│   Use OKLAB when:                                                             │
│   ===============                                                             │
│   - Mixing with transparency                                                  │
│   - Interpolating between two arbitrary colors                               │
│   - Creating gradients between different hues                                │
│   - Need predictable intermediate colors                                     │
│                                                                               │
│   Use sRGB when:                                                              │
│   ==============                                                              │
│   - Legacy browser support required                                          │
│   - Matching existing sRGB color values                                      │
│   - Hex colors needed for non-CSS contexts                                   │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘

THE CENTER

Gradients as Visual Flow Indicators

In the Core-Flow system, gradients represent the “flow” of information between data points. A gradient from Blue (primary) to Green (success) might indicate a transition from “in progress” to “complete.”
Connection to Core-Flow:
├── Core colors are endpoints (OKLCH identity)
├── Gradient interpolation shows the path (OKLAB flow)
├── Clean gradients = clear progression indication
└── Using `in oklab` ensures perceptual smoothness
The CSS gradient syntax linear-gradient(in oklab, ...) is not a hack - it is the correct way to create perceptually clean color transitions that communicate data relationships effectively.

Syntax Spectrum

File-type specific syntax highlighting colors