What Is CSS color-mix()? Mixing Colors Without Sass
CSS color-mix() blends two colors in a chosen color space right in a stylesheet, replacing the color math Sass and JavaScript used to handle.
color-mix() is a CSS function that blends two colors together in a specified color space and returns the result, directly in a stylesheet. It takes the interpolation logic that used to require a preprocessor like Sass or a JavaScript color library and puts it natively in CSS, which means the blend can now reference custom properties and update live, without a build step.
The basic syntax
.button {
background: color-mix(in srgb, royalblue 70%, white);
}
This reads as “mix royalblue and white in the sRGB color space, using 70% royalblue.” The percentage is optional on one color if you provide it on the other — color-mix(in srgb, royalblue 70%, white 30%) is equivalent — and if you omit both percentages entirely, it splits 50/50.
The first argument, in srgb, names the color space the interpolation happens in. This matters more than it looks: mixing the same two colors in different spaces produces visibly different midpoints, because each space defines “halfway between two colors” differently.
Why the color space argument matters
srgbinterpolates in the color space most monitors and CSS colors have historically used. It’s familiar but can produce muddy, desaturated grays in the middle of a mix between complementary colors.oklchandoklabare perceptually uniform spaces designed so that numerically equal steps look like equal steps to the human eye. Mixing inoklchtends to preserve vividness through the transition instead of graying out.hslandhwbinterpolate hue, saturation, and lightness (or whiteness/blackness) directly, which can produce different — sometimes more intuitive — hue transitions than sRGB’s channel-by-channel blend.
For most UI work, mixing in oklch gives the most visually pleasing gradient between two brand colors, while in srgb is a reasonable default when you just need “somewhat lighter” or “somewhat darker.”
Tinting and shading with a variable
The most common real-world use isn’t mixing two arbitrary colors — it’s deriving lighter and darker variants of a single brand color without hand-picking new hex values for every shade.
:root {
--brand: oklch(60% 0.15 250);
}
.button:hover {
background: color-mix(in oklch, var(--brand), white 20%);
}
.button:active {
background: color-mix(in oklch, var(--brand), black 20%);
}
Change --brand once and every derived shade updates with it — something that previously required a Sass lighten()/darken() function running at build time, disconnected from any runtime value. Because color-mix() runs in the browser, it also works with colors that only exist at runtime, like a user-selected theme color stored in a custom property.
Mixing with transparency
color-mix() also handles alpha correctly when one of the inputs is transparent, which makes it a clean way to fade a color toward invisible without hardcoding an rgba value:
.overlay {
background: color-mix(in srgb, black 40%, transparent);
}
This produces black at 40% opacity — equivalent to rgba(0, 0, 0, 0.4), but expressed relative to whatever “black” resolves to, which matters if you’re mixing a custom-property color instead of a literal.
color-mix() vs a Sass color function
Sass (lighten()/mix()) | CSS color-mix() | |
|---|---|---|
| Runs | At build time | In the browser, at paint time |
| Works with custom properties | No — build time can’t see runtime values | Yes |
| Color space control | Limited (HSL-based) | Explicit: srgb, oklch, hsl, and others |
| Requires a build step | Yes | No |
| Updates with a theme switch | No — needs a rebuild | Yes, automatically |
The build-time/runtime distinction is the real dividing line. A Sass mix is baked into the shipped stylesheet forever; a color-mix() mix re-evaluates any time its inputs change, which is exactly what a dark-mode toggle or a user-customizable accent color needs.
Browser support and fallbacks
color-mix() shipped across all major evergreen browsers within the same rough window as other modern color functions like oklch(). For a codebase that still needs to support older browsers, @supports (background: color-mix(in srgb, red, blue)) lets you gate the feature and fall back to a precomputed static color, similar to how you’d feature-detect CSS :has() or other recent selectors.
The takeaway
color-mix() moves color blending out of the build pipeline and into the stylesheet itself, which means it can react to custom properties, user themes, and runtime state that a Sass function never could. Pick the color space deliberately — oklch for perceptually smooth tints and shades, srgb for a simpler default — and use it to derive hover, active, and disabled states from a single brand color instead of maintaining a hand-picked palette.
Tagged
Keep reading
Takina · · 4 min read Container Query Units: cqw, cqh, and cqi Explained
Container query units like cqw and cqi size elements relative to their containing element, not the viewport — here's how and when to use them.
Takina · · 4 min read CSS Relative Color Syntax: Deriving Colors from Colors
Relative color syntax lets CSS derive a new color from an existing one by adjusting its channels directly, no preprocessor or JS required.
Takina · · 4 min read What Is CSS Subgrid? Nested Grid Alignment Explained
CSS subgrid lets a nested grid item inherit its parent's track sizing, so children can align to the same columns or rows across unrelated containers.