flashman
← All guides

Mix CSS colors in a named interpolation space

Mix CSS colors in a named color space, normalize percentages that do not sum to 100, and choose a hue path so the midpoint is the color you meant to ship.

2026-10-15 · 8 min read

  • css
  • color
  • design-systems

color-mix() is a computed color, not a blend mode on two layers. You name a color space, optionally a hue path, and two colors with percentages. The browser interpolates in that space and then converts the result back to the color it paints.

The space is part of the design. in srgb mixes the bytes people type. in srgb-linear mixes light. in oklch mixes a perceptual lightness and chroma. The same two endpoints and the same 50/50 percentages produce different hex values in those spaces.

Normalize the percentages on paper

Omitted percentages become 50% and 50%. One omitted percentage becomes the remainder of 100%. A pair that sums above 100% is scaled down to 100%, and the result stays as opaque as the inputs allow. A pair that sums below 100% is normalized for the color ratio, then the alpha is multiplied by the sum.

color-mix(in srgb, #ff0000 40%, #0000ff 40%) is therefore a half-and-half mix at 80% alpha. Authors who wanted a tint of each color at full opacity need both numbers to sum to 100%, for example 40% and 60%, or they need to put the transparency on a different layer.

  • Write both percentages when you care about alpha.
  • Scale an over-100 pair before reviewing the swatch.
  • Treat an under-100 pair as a transparency change.
  • Read the computed color after the cascade, not the token name.

Choose a hue path in polar spaces

hsl, hwb, lch, and oklch are polar. The default path is shorter hue, the smaller turn from the first hue to the second. From red to blue that turn passes through magenta, so the midpoint is a purple. longer hue takes the other way, through yellow and green.

increasing hue and decreasing hue force a direction when you do not want the shorter arc. A pair of hues 180 degrees apart has two equal arcs, so shorter and longer do not pick a unique side. Name increasing or decreasing if a gradient must pass a particular hue.

Account for premultiplied alpha

The mix is premultiplied. A 50% transparent red contributes less red than an opaque red at the same percentage. Mixing it with opaque blue does not average the raw RGB and then average the alphas. If a token is sometimes translucent, compute the mix with that alpha in the fixture, not only with the opaque brand color.

A declaration that is invalid at computed-value time is dropped. Both percentages at 0% is not a useful transparent color to depend on. Inspect the computed style and confirm the color-mix rule is the one that won.

Keep the endpoints next to the component

Store the two endpoint colors, the space, the hue method, both percentages, and the computed hex. A later edit that changes only the space will move the midpoint without changing the endpoint names. Diff the declaration, then sample the painted pixels.

Flashman's color tool converts a computed hex and checks its contrast against the surface behind the text. The CSS formatter makes the color-mix arguments readable. Diff compares the source rule with the built stylesheet. The color tool does not run color-mix itself, so the hex has to come from the browser.

Try these tools