# color-mix() in CSS: blending colours in the browser

[Canonical HTML page](https://gradiently.design/guide/css-color-mix)

color-mix() lets the browser do the colour maths you used to do in a preprocessor or by eye. Pick the right colour space and one brand colour can produce a whole palette of tints, shades and translucent versions.

## The short version

- The color-mix CSS function blends two colours in a named colour space, for example color-mix(in oklab, #7c3aed 40%, white).
- If you give only one percentage, the other colour gets the remainder; with none, the mix is half and half.
- Mixing in oklab keeps lightness even and avoids the grey middles that sRGB mixing produces between distant hues.
- Mixing a colour with transparent is the cleanest way to make a translucent version of a colour stored in a custom property.
- color-mix() works in all current major browsers, so it is safe for production with a plain colour as a fallback for very old ones.

The **color-mix CSS** function, `color-mix()`, blends two colours in a colour space you choose and returns a new colour. Write `color-mix(in oklab, #7c3aed 40%, white)` and you get a pale violet that is 40 percent violet and 60 percent white, mixed perceptually. It works in every current major browser. Paired with custom properties, it turns one brand colour into tints, shades, hover states and translucent overlays without a single hard coded hex.

## color-mix() syntax

```css
/* color-mix(in <colour space>, <colour> [<percentage>], <colour> [<percentage>]) */

.a { color: color-mix(in oklab, #7c3aed, white); }          /* 50% each */
.b { color: color-mix(in oklab, #7c3aed 40%, white); }      /* 40% violet, 60% white */
.c { color: color-mix(in oklab, #7c3aed, black 30%); }      /* 70% violet, 30% black */
.d { color: color-mix(in srgb, #7c3aed 50%, transparent); } /* violet at half opacity */
.e { color: color-mix(in oklch shorter hue, #2563eb, #f59e0b); }
```

The colour space comes first and is written out. Hue based spaces such as oklch and hsl also accept a hue direction: shorter, longer, increasing or decreasing.

| You write | Browser uses | Notes |
| --- | --- | --- |
| No percentages | 50% and 50% | An even mix |
| One percentage, say 30% | 30% and 70% | The other colour gets the remainder |
| Two that add to 100% | As written | The clearest form to read later |
| Two that add to more than 100% | Scaled down to 100% | 60% and 60% behaves like 50% and 50% |
| Two that add to less than 100% | Scaled up, then made translucent | 20% and 30% gives a half opacity result |

How percentages resolve. The last row surprises people: an under 100 total makes the result partly transparent.

## Which colour space to mix in

The colour space decides the path between the two colours. In sRGB the browser averages red, green and blue numbers, which is fast to reason about but not how eyes see. Two distant hues pass through a dull grey on the way. In oklab the mix follows perceived lightness and colour, so the middle stays clean and the steps look even. [Gradient interpolation](https://gradiently.design/guide/gradient-interpolation) explains the same choice for gradients, and the effect is easiest to see there.

- sRGB: flat grey in the middle: `linear-gradient(to right, #0000ff, #ffff00)`
- oklab: lighter, cleaner middle: `linear-gradient(in oklab to right, #0000ff, #ffff00)`
- oklch: travels through cyan and green: `linear-gradient(in oklch to right, #0000ff, #ffff00)`

Blue to yellow in three spaces. The midpoint of each strip is exactly what `color-mix()` returns at 50 percent in that space: `#808080` in sRGB, a light blue grey in oklab.

- **oklab** for tints, shades and most everyday mixing. Even lightness, no grey dip.
- **oklch** when you want the hue to travel, for example blending two brand colours into a third that sits between them on the wheel.
- **srgb** for mixing with `transparent` or matching older design tools that blend in sRGB.
- **srgb-linear** for physically based light mixing, which reads brighter in the middle.

For the background on why perceptual spaces behave better, see [OKLCH explained](https://gradiently.design/guide/oklch-explained). Recent versions of the specification allow you to leave the colour space out and default to oklab, but support for that shorthand is newer, so write `in oklab` explicitly.

## Tints and shades from one brand colour

The most useful pattern is a scale built from a single variable. Mix towards white for tints, towards black for shades. Change the variable and every step updates, which makes it ideal for multi brand products or themes chosen by the user.

```css
:root {
  --brand: #7c3aed;

  --brand-100: color-mix(in oklab, var(--brand) 20%, white);
  --brand-200: color-mix(in oklab, var(--brand) 40%, white);
  --brand-300: color-mix(in oklab, var(--brand) 60%, white);
  --brand-400: color-mix(in oklab, var(--brand) 80%, white);
  --brand-500: var(--brand);
  --brand-600: color-mix(in oklab, var(--brand) 80%, black);
  --brand-700: color-mix(in oklab, var(--brand) 60%, black);
}
```

A seven step scale from one colour. Swap `--brand` for any hex and the scale follows.

- brand-100: #e1dbff
- brand-200: #c5b7fe
- brand-300: #aa92fa
- brand-400: #926bf4
- brand-500: #7c3aed
- brand-600: #5a28b0
- brand-700: #3b1877

What the scale above resolves to for `#7c3aed`, computed in oklab. Mixed in sRGB, the tints come out a little greyer and the shades a little flatter.

Mixing with pure white and black is a starting point. For warmer tints, mix towards an off white such as `#fdf6ec`; for richer shades, mix towards a deep navy instead of black. That keeps the scale feeling like your brand rather than a generic ramp. [Tints, tones and shades](https://gradiently.design/guide/tints-tones-shades) covers the colour theory.

## Transparency with color-mix()

Before `color-mix()`, making a translucent version of a colour stored in a variable meant storing the channels separately. Now you mix with `transparent`. The amount you keep is the opacity.

```css
.badge {
  color: var(--brand);
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 30%, transparent);
}

.button:hover {
  background: color-mix(in oklab, var(--brand), black 12%);
}
```

A tinted badge and a hover state from the same variable. No second colour to maintain.

## Common color-mix() mistakes

- **Leaving out the colour space** in code that must run in older browsers. The whole declaration is dropped, not just the space.
- **Mixing with black for every shade.** Shades of saturated colours go dull; mix towards a deep version of the hue instead.
- **Expecting percentages under 100 to stay opaque.** `color-mix(in oklab, red 20%, blue 30%)` is half transparent.
- **Using hsl for tints.** Lightness in hsl is not perceptual, so a yellow and a blue at the same mix look nothing like the same step.

## Browser support and fallbacks

`color-mix()` has been available in Chrome, Edge, Firefox and Safari since 2023, and current support is listed on [caniuse](https://caniuse.com/mdn-css_types_color_color-mix). If you need to cover very old browsers, declare a plain colour first and let the mixed one override it. Browsers that don't understand the second line ignore it.

```css
.card {
  background: #ede9fe;
  background: color-mix(in oklab, var(--brand) 15%, white);
}
```

Fallback first, enhancement second. The cascade does the rest.

A full theme built on these patterns, with light and dark modes, is in [CSS variables for theming](https://gradiently.design/guide/css-custom-properties-theming).

## Mixing colours for gradients

`color-mix()` is handy inside gradients, where it can compute a middle stop from two brand colours so the blend never passes through mud. `linear-gradient(135deg, var(--a), color-mix(in oklch, var(--a), var(--b)), var(--b))` gives you a third stop on the hue path between the two. The underlying problem is covered in [muddy gradients](https://gradiently.design/guide/muddy-gradients).

If your brand colour lives in a Gradiently Mark, the Mark's recipe already holds a family of related colours chosen to work together, and the Market lets you search by colour words such as "deep violet" to find one built around the hue you start from.

## FAQ

### What does color-mix() do in CSS?

It blends two colours in a colour space you name and returns the result, for example `color-mix(in oklab, red 30%, white)`.

### Which colour space should I use with color-mix()?

Use oklab for tints, shades and most mixing, oklch when you want the hue to travel, and srgb for mixing with transparent.

### How do I make a colour transparent with color-mix()?

Mix it with `transparent`: `color-mix(in srgb, var(--brand) 20%, transparent)` gives the brand colour at 20 percent opacity.

### Is color-mix() supported in all browsers?

It works in current versions of Chrome, Edge, Firefox and Safari. Declare a plain colour first as a fallback for older browsers.

### What happens if the percentages don't add up to 100?

Totals above 100 are scaled down. Totals below 100 are scaled up and the result becomes partly transparent.
