Back to Blog
CSSColorsDesignFunctions

CSS Color Functions Guide

Master modern CSS color functions. From color-mix to relative colors to color spaces.

B
Bootspring Team
Engineering
January 16, 2021
7 min read

Modern CSS provides powerful color manipulation functions. Here's how to use them.

color-mix()#

1/* Mix two colors */ 2.mixed { 3 /* 50% of each color */ 4 background: color-mix(in srgb, red, blue); 5 /* Result: purple */ 6} 7 8/* Custom percentages */ 9.custom-mix { 10 /* 25% red, 75% blue */ 11 background: color-mix(in srgb, red 25%, blue); 12 13 /* Explicit percentages */ 14 background: color-mix(in srgb, red 30%, blue 70%); 15} 16 17/* Mix with currentColor */ 18.tinted { 19 color: blue; 20 background: color-mix(in srgb, currentColor 20%, white); 21} 22 23/* Mix with transparent */ 24.faded { 25 background: color-mix(in srgb, blue 50%, transparent); 26 /* Same as: rgba(0, 0, 255, 0.5) */ 27} 28 29/* Different color spaces */ 30.oklch-mix { 31 /* Perceptually uniform mixing */ 32 background: color-mix(in oklch, red, blue); 33} 34 35.hsl-mix { 36 background: color-mix(in hsl, red, blue); 37} 38 39.lab-mix { 40 background: color-mix(in lab, red, blue); 41}

Relative Color Syntax#

1/* Modify existing colors */ 2.lighter { 3 --base: blue; 4 /* Increase lightness by 20% */ 5 background: oklch(from var(--base) calc(l + 0.2) c h); 6} 7 8.darker { 9 --base: blue; 10 /* Decrease lightness */ 11 background: oklch(from var(--base) calc(l - 0.2) c h); 12} 13 14.saturated { 15 --base: blue; 16 /* Increase chroma */ 17 background: oklch(from var(--base) l calc(c + 0.1) h); 18} 19 20.desaturated { 21 --base: blue; 22 /* Decrease chroma */ 23 background: oklch(from var(--base) l calc(c * 0.5) h); 24} 25 26/* Shift hue */ 27.complementary { 28 --base: blue; 29 /* Rotate hue 180 degrees */ 30 background: oklch(from var(--base) l c calc(h + 180)); 31} 32 33.triadic { 34 --base: blue; 35 background: oklch(from var(--base) l c calc(h + 120)); 36} 37 38/* With transparency */ 39.semi-transparent { 40 --base: blue; 41 background: oklch(from var(--base) l c h / 0.5); 42} 43 44/* Using HSL */ 45.hsl-lighter { 46 --base: hsl(220 80% 50%); 47 background: hsl(from var(--base) h s calc(l + 20%)); 48}

OKLCH Color Space#

1/* OKLCH: Lightness, Chroma, Hue */ 2.oklch-color { 3 /* l: 0-1, c: 0-0.4, h: 0-360 */ 4 background: oklch(0.7 0.15 250); 5} 6 7/* More readable with percentages */ 8.oklch-percent { 9 background: oklch(70% 0.15 250); 10} 11 12/* With alpha */ 13.oklch-alpha { 14 background: oklch(70% 0.15 250 / 0.8); 15} 16 17/* Creating a color palette */ 18:root { 19 --hue: 250; /* Blue */ 20 --chroma: 0.15; 21 22 --color-50: oklch(0.97 calc(var(--chroma) * 0.3) var(--hue)); 23 --color-100: oklch(0.93 calc(var(--chroma) * 0.5) var(--hue)); 24 --color-200: oklch(0.87 calc(var(--chroma) * 0.7) var(--hue)); 25 --color-300: oklch(0.78 calc(var(--chroma) * 0.85) var(--hue)); 26 --color-400: oklch(0.68 var(--chroma) var(--hue)); 27 --color-500: oklch(0.58 var(--chroma) var(--hue)); 28 --color-600: oklch(0.48 var(--chroma) var(--hue)); 29 --color-700: oklch(0.38 var(--chroma) var(--hue)); 30 --color-800: oklch(0.28 calc(var(--chroma) * 0.9) var(--hue)); 31 --color-900: oklch(0.20 calc(var(--chroma) * 0.8) var(--hue)); 32}

color() Function#

1/* Access wider color gamuts */ 2.display-p3 { 3 /* Display P3 color space - more vibrant */ 4 background: color(display-p3 1 0 0); 5 /* Fallback for browsers without P3 */ 6 background: color(display-p3 1 0 0) or red; 7} 8 9.srgb { 10 background: color(srgb 1 0.5 0); 11} 12 13.rec2020 { 14 /* Even wider gamut */ 15 background: color(rec2020 0.3 0.7 0.2); 16} 17 18/* With @supports */ 19@supports (color: color(display-p3 1 0 0)) { 20 .vibrant-red { 21 background: color(display-p3 1 0.1 0.1); 22 } 23}

LAB and LCH#

1/* LAB: Lightness, a-axis (green-red), b-axis (blue-yellow) */ 2.lab-color { 3 background: lab(60% -30 50); 4} 5 6/* LCH: Lightness, Chroma, Hue */ 7.lch-color { 8 background: lch(60% 40 250); 9} 10 11/* LAB is good for perceptual uniformity */ 12.gradient-lab { 13 background: linear-gradient( 14 in lab, 15 blue, 16 yellow 17 ); 18 /* No muddy middle colors */ 19} 20 21/* Compare with sRGB */ 22.gradient-srgb { 23 background: linear-gradient( 24 in srgb, 25 blue, 26 yellow 27 ); 28 /* May have greenish middle */ 29}

HWB Colors#

1/* HWB: Hue, Whiteness, Blackness */ 2.hwb-color { 3 /* Hue: 0-360, Whiteness: 0-100%, Blackness: 0-100% */ 4 background: hwb(200 10% 20%); 5} 6 7/* Pure hue */ 8.pure-blue { 9 background: hwb(240 0% 0%); 10} 11 12/* Tinted (add white) */ 13.light-blue { 14 background: hwb(240 40% 0%); 15} 16 17/* Shaded (add black) */ 18.dark-blue { 19 background: hwb(240 0% 40%); 20} 21 22/* With transparency */ 23.hwb-alpha { 24 background: hwb(240 10% 10% / 0.5); 25}

Creating Color Scales#

1/* Programmatic color scale with OKLCH */ 2:root { 3 --primary-hue: 220; 4 5 /* Light mode */ 6 --primary-light: oklch(0.95 0.02 var(--primary-hue)); 7 --primary-base: oklch(0.55 0.18 var(--primary-hue)); 8 --primary-dark: oklch(0.25 0.12 var(--primary-hue)); 9 10 /* Hover/active states */ 11 --primary-hover: oklch(from var(--primary-base) calc(l - 0.05) c h); 12 --primary-active: oklch(from var(--primary-base) calc(l - 0.1) c h); 13} 14 15/* Dark mode adjustments */ 16@media (prefers-color-scheme: dark) { 17 :root { 18 --primary-light: oklch(0.25 0.08 var(--primary-hue)); 19 --primary-base: oklch(0.65 0.16 var(--primary-hue)); 20 --primary-dark: oklch(0.90 0.04 var(--primary-hue)); 21 } 22} 23 24/* Semantic colors */ 25:root { 26 --success-hue: 145; 27 --warning-hue: 45; 28 --error-hue: 15; 29 30 --success: oklch(0.55 0.18 var(--success-hue)); 31 --warning: oklch(0.70 0.18 var(--warning-hue)); 32 --error: oklch(0.55 0.20 var(--error-hue)); 33}

Color Contrast#

1/* Ensuring contrast with color-mix */ 2.auto-contrast { 3 --bg: blue; 4 --light-text: color-mix(in oklch, white 90%, var(--bg)); 5 --dark-text: color-mix(in oklch, black 85%, var(--bg)); 6 7 background: var(--bg); 8 /* Choose text color based on background lightness */ 9} 10 11/* Using OKLCH for guaranteed contrast */ 12.high-contrast { 13 --base-hue: 220; 14 --bg: oklch(0.2 0.1 var(--base-hue)); 15 --text: oklch(0.9 0.05 var(--base-hue)); 16 17 background: var(--bg); 18 color: var(--text); 19} 20 21/* Accessible focus rings */ 22.focus-visible { 23 --focus-color: oklch(0.7 0.2 250); 24 outline: 3px solid var(--focus-color); 25 outline-offset: 2px; 26}

Gradients with Color Spaces#

1/* Smooth gradients in OKLCH */ 2.smooth-gradient { 3 background: linear-gradient( 4 in oklch, 5 oklch(0.7 0.2 30), /* Red */ 6 oklch(0.7 0.2 150), /* Green */ 7 oklch(0.7 0.2 270) /* Blue */ 8 ); 9} 10 11/* Hue interpolation */ 12.rainbow-short { 13 background: linear-gradient( 14 in oklch shorter hue, 15 oklch(0.7 0.2 0), 16 oklch(0.7 0.2 270) 17 ); 18} 19 20.rainbow-long { 21 background: linear-gradient( 22 in oklch longer hue, 23 oklch(0.7 0.2 0), 24 oklch(0.7 0.2 270) 25 ); 26} 27 28/* Avoiding muddy midpoints */ 29.clean-gradient { 30 background: linear-gradient( 31 in oklch, 32 hsl(0 80% 50%), /* Red */ 33 hsl(60 80% 50%) /* Yellow */ 34 ); 35 /* No orange-brown in middle */ 36}

Dynamic Theming#

1/* Theme with CSS variables and color functions */ 2:root { 3 --theme-hue: 220; 4 --theme-saturation: 0.15; 5 6 /* Generate full palette from one hue */ 7 --surface: oklch(0.98 calc(var(--theme-saturation) * 0.2) var(--theme-hue)); 8 --surface-hover: oklch(0.95 calc(var(--theme-saturation) * 0.3) var(--theme-hue)); 9 --border: oklch(0.85 calc(var(--theme-saturation) * 0.4) var(--theme-hue)); 10 --text-muted: oklch(0.55 calc(var(--theme-saturation) * 0.5) var(--theme-hue)); 11 --text: oklch(0.25 calc(var(--theme-saturation) * 0.3) var(--theme-hue)); 12 --primary: oklch(0.55 var(--theme-saturation) var(--theme-hue)); 13 --primary-hover: oklch(0.50 var(--theme-saturation) var(--theme-hue)); 14} 15 16/* Change entire theme by changing hue */ 17.theme-purple { 18 --theme-hue: 280; 19} 20 21.theme-green { 22 --theme-hue: 145; 23} 24 25.theme-orange { 26 --theme-hue: 30; 27}

Button Variations#

1/* Generate button states from base color */ 2.button { 3 --btn-color: oklch(0.55 0.18 220); 4 5 background: var(--btn-color); 6 color: oklch(from var(--btn-color) 0.98 0.02 h); 7} 8 9.button:hover { 10 background: oklch(from var(--btn-color) calc(l - 0.05) c h); 11} 12 13.button:active { 14 background: oklch(from var(--btn-color) calc(l - 0.1) c h); 15} 16 17.button:disabled { 18 background: oklch(from var(--btn-color) l calc(c * 0.3) h / 0.5); 19} 20 21/* Outline variant */ 22.button--outline { 23 background: transparent; 24 color: var(--btn-color); 25 border: 2px solid var(--btn-color); 26} 27 28.button--outline:hover { 29 background: oklch(from var(--btn-color) 0.95 calc(c * 0.3) h); 30}

Best Practices#

Color Spaces: ✓ Use OKLCH for perceptual uniformity ✓ Use color-mix for simple blending ✓ Use relative colors for modifications ✓ Test in different color spaces Accessibility: ✓ Maintain WCAG contrast ratios ✓ Test with color blindness simulators ✓ Don't rely on color alone ✓ Use sufficient lightness differences Performance: ✓ Prefer CSS over JavaScript ✓ Use CSS custom properties ✓ Minimize calculations ✓ Test browser support Fallbacks: ✓ Provide sRGB fallbacks ✓ Use @supports queries ✓ Test in older browsers ✓ Consider progressive enhancement

Conclusion#

Modern CSS color functions enable powerful color manipulation directly in stylesheets. Use OKLCH for perceptual uniformity, color-mix for blending, and relative color syntax for modifications. Always provide fallbacks for older browsers.

Share this article

Help spread the word about Bootspring