CSS color-mix() Recipes Every Designer Should Know
color-mix() lets you blend any two CSS colors at runtime. Six practical patterns: hover states, tints/shades, theming, focus rings, and more.
color-mix() shipped in every modern browser in 2023. It blends two colors in any color space, at any ratio, in one CSS expression. It quietly removes the need for half the SCSS color helpers people still ship. Here are six recipes.
1. Hover states without an extra token
.btn { background: var(--brand); }
.btn:hover { background: color-mix(in oklch, var(--brand), black 12%); }
Adds 12% black in OKLCH. One line, one source of truth - no --brand-hover token needed.
2. Subtle tinted backgrounds
.card { background: color-mix(in oklch, var(--brand), white 92%); }
Mostly white with a whisper of brand color. Perfect for callouts, tags, info cards. Change the brand variable and every tint follows.
3. Disabled states
.btn[disabled] { background: color-mix(in oklch, var(--brand), var(--surface) 60%); color: color-mix(in oklch, var(--text), var(--surface) 50%); }
Mixes the live token with the surface to dim it without picking a separate color.
4. Translucent overlays that respect the brand
.scrim { background: color-mix(in srgb, var(--brand) 30%, transparent); }
Use in srgb when one of the inputs is transparent - OKLCH transparency interpolation is not supported in all engines yet.
5. Focus rings with guaranteed contrast
:focus-visible { outline: 2px solid color-mix(in oklch, var(--brand), white 20%); outline-offset: 2px; }
Lighten the brand slightly so the ring stands clear of the button itself - works on both light and dark themes.
6. Themed scrollbars
::-webkit-scrollbar-thumb { background: color-mix(in oklch, var(--text), transparent 70%); }
::-webkit-scrollbar-thumb:hover { background: color-mix(in oklch, var(--text), transparent 50%); }
Scrollbar that follows your theme without needing dedicated tokens.
Tips
- Default to
in oklch. Cleaner blends thanin srgb, especially when crossing hues. - Mind the percentage. Without a percentage,
color-mix()assumes 50/50. - Cache big tokens. If you mix the same pair in 30 places, make a CSS variable that holds the result.
Need a quick visual of how mixes feel before shipping them? Open our Color Mixer - same math, immediate preview.