color-mix() vs opacity — When to Use Which

Understand the practical difference between mixing a color toward transparent and using the opacity property. Includes accessibility and stacking implications.

Advanced

Detailed Explanation

Two Ways to "Fade" a Color, Two Different Effects

It is tempting to think opacity: 0.5 and color-mix(in oklch, c, transparent 50%) do the same thing. They do not.

opacity: 0.5

.card { background: blue; opacity: 0.5; }

This fades the entire element, including all its descendants — text, icons, borders, child components. It also creates a new stacking context. Useful for "ghost" overlays but disastrous for accessibility: text inside the element fails contrast checks even when the underlying color choice was fine.

color-mix(... transparent 50%)

.card { background: color-mix(in oklch, blue, transparent 50%); }

This fades only the background. Text and icons inside the element keep their full alpha. No stacking-context surprise.

A practical decision tree

Goal Use
Fade out a whole pop-over during a transition opacity
Show a translucent header background color-mix(... transparent ...)
Disabled state for an entire button group opacity
Disabled background fill, but keep label readable color-mix(... transparent ...)
50% chip background tint color-mix(... transparent ...)

Bonus: alpha math via Relative Color Syntax

If you want to take an existing color and halve its alpha precisely, Relative Color Syntax gives you direct access:

.faded { color: oklch(from var(--brand) l c h / calc(alpha * 0.5)); }

Use Case

Refactoring legacy code that uses `opacity` for visual fading where it is producing accessibility regressions. Choosing the right primitive for translucent UI surfaces.

Try It — CSS color-mix() Generator

Open full tool