Skip to content

Instantly share code, notes, and snippets.

@StanleyMasinde
Created January 5, 2026 01:40
Show Gist options
  • Select an option

  • Save StanleyMasinde/4ac9050c89f6a2af0de9856911ef2901 to your computer and use it in GitHub Desktop.

Select an option

Save StanleyMasinde/4ac9050c89f6a2af0de9856911ef2901 to your computer and use it in GitHub Desktop.

Modern CSS Color Spaces Guide

A comprehensive guide to using P3, oklch, and wide-gamut colors in modern web development

The Problem with RGB/Hex

Traditional approach:

/* Standard RGB/Hex - limited to sRGB gamut */
color: #ff0000;
color: rgb(255, 0, 0);

Limitations:

  • Locked to sRGB color space (~35% of visible colors)
  • Can't access P3's richer reds, greens, cyans
  • Same values look different across color spaces

Modern CSS Color Spaces

1. Display P3 (Most Practical for Wide Color)

/* Rich, vibrant red in P3 */
color: color(display-p3 1 0 0);

/* Deep emerald green */
color: color(display-p3 0 0.8 0.3);

/* Vivid cyan - impossible in sRGB */
color: color(display-p3 0 1 1);

/* Comparison */
color: #ff0000;                    /* sRGB red - basic */
color: color(display-p3 1 0 0);    /* P3 red - 25% more saturated */

Browser support: Excellent (Safari, Chrome, Firefox modern versions)

2. oklch() - Perceptually Uniform (Best for Manipulation)

/* Rich red */
color: oklch(0.6 0.25 25);
/*           ↑    ↑    ↑
         lightness chroma hue */

/* Deep saturated blue */
color: oklch(0.5 0.3 250);

/* Vibrant magenta */
color: oklch(0.7 0.32 330);

Why oklch is great:

  • Perceptually uniform (changing lightness looks consistent)
  • Easy to create color variations
  • Automatically uses widest available gamut
  • Better for programmatic color generation

3. oklab() - Perceptual but Cartesian

/* Similar to oklch but different coordinate system */
color: oklab(0.6 0.2 0.1);

4. lch() - Lab-based

/* Older perceptual space */
color: lch(60% 130 25);

Practical Examples for Vue3/Tailwind 4

In your Tailwind config:

@theme {
  --color-brand-red: color(display-p3 1 0.1 0.1);
  --color-vibrant-green: oklch(0.7 0.25 145);
  --color-deep-cyan: color(display-p3 0 0.9 0.95);
}

Detecting P3 support:

/* Fallback for older displays */
.button {
  background: rgb(255, 50, 50); /* sRGB fallback */
}

/* P3 for capable displays */
@media (color-gamut: p3) {
  .button {
    background: color(display-p3 1 0.2 0.2);
  }
}

In Vue3 SFC:

<style scoped>
.hero-title {
  /* Fallback */
  color: #ff3366;
  
  /* P3 override for capable displays */
  color: color(display-p3 1 0.2 0.4);
}

@supports (color: color(display-p3 1 0 0)) {
  .accent {
    background: color(display-p3 0 0.95 0.7);
  }
}
</style>

Color Space Comparison

/* All "red" but different richness */

/* sRGB - basic web red */
color: rgb(255, 0, 0);

/* P3 - 25% more saturated red */
color: color(display-p3 1 0 0);

/* oklch - same perceptual red, uses best available gamut */
color: oklch(0.628 0.258 29.23);

/* Rec2020 - even wider (few displays support) */
color: color(rec2020 1 0 0);

Best Practices

For brand colors (deep reds, vibrant greens):

:root {
  /* Define once with fallback */
  --accent: rgb(220, 38, 38);
  --accent: color(display-p3 0.9 0.15 0.15);
}

For generated/dynamic colors:

/* oklch makes it easy to adjust saturation/lightness */
--base: oklch(0.6 0.2 25);
--lighter: oklch(0.7 0.2 25);  /* just adjust L */
--more-vivid: oklch(0.6 0.3 25); /* just adjust C */

Browser DevTools

Modern browsers show when colors are outside sRGB:

  • Chrome/Safari DevTools show color space info
  • Color picker indicates if P3/wide gamut
  • Warning if color can't be displayed on current monitor

The Reality Check

Important: Even with P3 CSS colors:

  • User must have P3-capable display
  • Browser must support it
  • OS color management must be working
  • On sRGB displays, colors get compressed back to sRGB

But it's progressive enhancement — specify rich colors, and users with capable displays see them in full glory, others get acceptable sRGB fallback.

Color Gamut Coverage Comparison

Color Space Coverage of Visible Colors Use Case
sRGB ~35% Legacy web, older content
Display P3 ~45-50% Modern displays, HDR content
Rec. 2020 ~75% Future displays, ultra-wide gamut

Recommendation for Nuxt3 Projects

Use color(display-p3 ...) for:

  • Brand colors with RGB fallbacks
  • Hero sections and accent colors
  • Any color where vibrancy matters

Use oklch() when you need to:

  • Programmatically manipulate colors
  • Generate shades and tints
  • Create color scales with consistent perception
  • Build theme systems with predictable variations

Quick Reference: CSS Color Functions

Function Syntax Example Best For
rgb() rgb(255, 0, 0) Legacy support
color(display-p3) color(display-p3 1 0 0) Wide gamut colors
oklch() oklch(0.6 0.25 25) Color manipulation
oklab() oklab(0.6 0.2 0.1) Perceptual mixing
lch() lch(60% 130 25) Lab-based colors

Testing Your Colors

To verify your P3 colors are working:

  1. Use a P3-capable display (modern MacBook Pro, iPad Pro, iPhone)
  2. Open DevTools and inspect the element
  3. Check if color picker shows "Display P3" indicator
  4. Compare with sRGB version side-by-side
  5. Test fallback behavior on non-P3 displays

Resources

  • MDN Web Docs: Comprehensive CSS color documentation
  • OKLCH Color Picker: oklch.com - Interactive tool for exploring oklch colors
  • Can I Use: Check browser support for color functions
  • Webkit Blog: Articles on wide gamut colors in Safari

Generated on January 5, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment