Modern CSS Color Functions: rgb(), hsl(), oklch(), and More
The Evolution of CSS Color Syntax
CSS color handling has undergone a remarkable transformation in recent years. Gone are the days when hex codes and named colors were our only options. Today's CSS provides a rich set of color functions that offer greater precision, better readability, and more powerful color manipulation capabilities.
The evolution has moved from the limited color: red; and #FF0000 syntax toward modern functions that separate hue, saturation, and lightness in intuitive ways. This progression isn't just about adding features—it's about making color in CSS more predictable, accessible, and powerful.
Legacy Syntax: hex and rgb()
Hexadecimal Colors
Hex codes have been the backbone of web colors for decades:
.hero {
background-color: #3B82F6; /* Blue */
color: #FFFFFF; /* White */
}
Hex notation represents colors using three pairs of hexadecimal digits (00-FF) for red, green, and blue. While compact, hex has significant drawbacks:
- Difficult to intuitively understand what color
#E879F0represents - No built-in way to adjust lightness or saturation
- No alpha/transparency support without the
#RRGGBBAAextension (which has poor browser support)
The Old rgb() Function
The traditional rgb() function required comma-separated values:
.button {
background-color: rgb(59, 130, 246); /* Blue */
color: rgb(255, 255, 255); /* White */
}
With alpha transparency, you'd use rgba():
.overlay {
background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent black */
}
Modern rgb() and rgba() Syntax
CSS Color Level 4 introduced a space-separated syntax that's more consistent with other color functions:
.modern-rgb {
background-color: rgb(59 130 246); /* No commas! */
color: rgb(255 255 255 / 0.9); /* Alpha with slash syntax */
}
.modern-rgba {
background-color: rgba(59 130 246 / 50%); /* Percentage alpha */
}
Key Improvements
- Space separation:
rgb(59 130 246)instead ofrgb(59, 130, 246) - Slash for alpha:
rgb(255 255 255 / 0.5)instead of needingrgba() - Percentage values:
rgb(50% 50% 100%)is now valid - None keyword:
rgb(none none none)for intentionally missing components
/* All these are now valid */
.valid-examples {
color: rgb(255 0 0);
color: rgb(100% 0% 0%);
color: rgb(255 0 0 / 0.5);
color: rgb(255 0 0 / 50%);
color: rgb(none none none); /* Resets to default */
}
hsl(): Hue, Saturation, Lightness
The hsl() function represents colors using a cylindrical coordinate system that aligns better with human perception:
.hsl-example {
/* hsl(hue saturation lightness) */
background-color: hsl(217 91% 60%); /* Same blue as before */
}
Understanding HSL Components
- Hue (0-360): The color type, measured in degrees on the color wheel
- 0° = Red, 120° = Green, 240° = Blue
- Saturation (0-100%): Color intensity (0% = gray, 100% = vivid)
- Lightness (0-100%): Brightness (0% = black, 50% = normal, 100% = white)
.color-palette {
--primary-hue: 217;
--primary-50: hsl(var(--primary-hue) 91% 95%);
--primary-100: hsl(var(--primary-hue) 91% 90%);
--primary-200: hsl(var(--primary-hue) 91% 80%);
--primary-300: hsl(var(--primary-hue) 91% 70%);
--primary-400: hsl(var(--primary-hue) 91% 60%);
--primary-500: hsl(var(--primary-hue) 91% 50%);
--primary-600: hsl(var(--primary-hue) 91% 40%);
--primary-700: hsl(var(--primary-hue) 91% 30%);
--primary-800: hsl(var(--primary-hue) 91% 20%);
--primary-900: hsl(var(--primary-hue) 91% 10%);
}
Modern hsl() Syntax
Like rgb(), modern hsl() uses space separation:
.modern-hsl {
color: hsl(217 91% 60%);
color: hsl(217 91% 60% / 0.8); /* With alpha */
color: hsl(none none none); /* Reset */
}
oklch(): The Perceptually Uniform Revolution
oklch() is the newest and most scientifically advanced CSS color function. It uses the Oklab color space, which is perceptually uniform—meaning equal numerical changes produce equal perceived color differences.
.oklch-example {
/* oklch(lightness chroma hue) */
background-color: oklch(60% 0.2 264); /* Perceptually pleasing blue */
}
Components of oklch()
- Lightness (0-100%): Perceptually uniform lightness (0% = black, 50% = middle gray, 100% = white)
- Chroma (0-0.4+): Colorfulness/saturation (0 = gray, higher = more vivid)
- Hue (0-360): Same as hsl()—the color wheel position
Why oklch() is Superior
- Predictable lightness:
oklch(60% ...)always appears at the same perceptual lightness regardless of hue - Better gradients:
hsl()gradients can look muddy in the middle;oklch()stays vibrant - Accessibility: Easier to create accessible color pairs with consistent contrast ratios
- Wide gamut: Supports colors beyond sRGB (P3, Rec.2020)
/* Compare these gradients */
.hsl-gradient {
background: linear-gradient(
to right,
hsl(0 100% 50%),
hsl(120 100% 50%),
hsl(240 100% 50%)
);
/* Notice the dark, muddy center */
}
.oklch-gradient {
background: linear-gradient(
to right,
oklch(65% 0.25 29), /* Red */
oklch(65% 0.25 142), /* Green */
oklch(65% 0.25 264) /* Blue */
);
/* Consistent perceptual lightness throughout */
}
color-mix(): Blending Colors in CSS
The color-mix() function allows you to blend two colors directly in CSS, similar to mixing paint:
.mixed-colors {
/* Mix 50% blue with 50% white in sRGB */
background-color: color-mix(in srgb, blue, white);
/* 75% red, 25% black */
color: color-mix(in srgb, red 75%, black);
/* Mix in different color spaces */
border-color: color-mix(in oklch, blue, white);
}
Syntax Breakdown
color-mix(in <colorspace>, <color1> [<percentage>], <color2> [<percentage>])
<colorspace>:srgb,oklch,hsl,lab, etc.<color>: Any valid CSS color<percentage>: How much of that color to use (defaults to 50%)
.practical-mixing {
--brand-color: oklch(60% 0.2 264);
/* Create hover state by mixing with white */
--brand-hover: color-mix(in oklch, var(--brand-color), white 20%);
/* Create active state by mixing with black */
--brand-active: color-mix(in oklch, var(--brand-color), black 20%);
/* Create disabled state */
--brand-disabled: color-mix(in oklch, var(--brand-color), white 60%);
}
Relative Color Syntax
Relative color syntax lets you transform existing colors mathematically:
.relative-example {
--base-color: oklch(60% 0.2 264);
/* Increase lightness by 10% */
background-color: oklch(from var(--base-color) l+10% c h);
/* Reduce saturation to half */
color: oklch(from var(--base-color) l c/2 h);
/* Rotate hue by 180 degrees (complementary) */
border-color: oklch(from var(--base-color) l c h+180);
}
The from Keyword
The from <color> syntax extracts components into variables you can modify:
.component {
--input: oklch(70% 0.1 264);
/* Create a palette from one base color */
--input-bg: oklch(from var(--input) l+20% c h);
--input-border: oklch(from var(--input) l-10% c h);
--input-focus: oklch(from var(--input) l c+0.1 h);
--input-error: oklch(from var(--input) l c h+30); /* Shift hue slightly */
}
Browser Support and Fallbacks
Current Support (as of 2026)
| Function | Chrome/Edge | Firefox | Safari | Notes |
|---|---|---|---|---|
rgb() modern syntax | ✅ 90+ | ✅ 103+ | ✅ 15+ | Widely supported |
hsl() modern syntax | ✅ 90+ | ✅ 103+ | ✅ 15+ | Widely supported |
oklch() | ✅ 111+ | ✅ 113+ | ✅ 16.4+ | Modern browsers |
color-mix() | ✅ 111+ | ✅ 113+ | ✅ 16.4+ | Modern browsers |
| Relative color syntax | ✅ 119+ | ✅ 118+ | ✅ 17+ | Very new |
Providing Fallbacks
.with-fallbacks {
/* Start with hex fallback */
background-color: #3B82F6;
/* Modern rgb() */
background-color: rgb(59 130 246);
/* Modern hsl() */
background-color: hsl(217 91% 60%);
/* Cutting-edge oklch() */
background-color: oklch(60% 0.2 264);
}
/* Or use @supports */
@supports (background-color: oklch(0% 0 0)) {
.modern-only {
background-color: oklch(60% 0.2 264);
}
}
Practical Tips for Adoption
- Use CSS custom properties: Define colors once and reference them everywhere
- Start with hsl(): It's well-supported and intuitive for creating palettes
- Experiment with oklch(): Use for new projects where browser support allows
- Leverage color-mix(): Great for hover/active states without defining new variables
- Test in both light and dark modes: Modern color functions make this much easier
:root {
--hue: 217;
--primary: hsl(var(--hue) 91% 60%);
}
[data-theme="dark"] {
--primary: hsl(var(--hue) 91% 70%); /* Lighter for dark mode */
}
Related Tools
- Color Converter - Convert between HEX, RGB, and HSL formats