What Is CSS color-mix()? How to Mix Two Colors to Create a New Color

TIPS

When you want a new color that sits between blue and teal on a website, you do not have to search for its color code manually. CSS color-mix() can blend two specified colors in controlled proportions. Changing those proportions gives you variations from the same pair of source colors. Mixing colors is different from overlaying a transparent layer, though, and the result is not automatically suitable for text. This guide explains the syntax, shows a practical event card, and checks the finished combinations.

What is color-mix(), and how do its percentages work?

color-mix() is a CSS (Cascading Style Sheets) function that returns a color produced by mixing specified source colors. CSS defines the visual appearance of webpages. Suppose the source colors are blue #2563EB and teal #0F766E. Writing color-mix(in srgb, var(--event-blue) 60%, var(--event-teal)) combines 60% blue with 40% teal. When you provide a percentage for only one of two colors, the other percentage is filled in to make 100%. If you omit both, the default is 50% of each.

in srgb tells the browser to mix colors in the sRGB color space, a numerical representation widely used for web colors. Other spaces, such as oklab, can produce a different result from the same source colors and proportions. This example uses sRGB consistently so the channel calculations are easier to follow. The function returns one color, not a gradient, and that value can be used for properties such as background-color and border-color.

This is a calculation using digital color values, not the physical mixing of paint. For straightforward examples, specify proportions that add up to 100%, or let the browser determine the remainder. If you explicitly provide both percentages and their total is below 100%, the result can have reduced opacity. That behavior is different from simply choosing two ordinary opaque colors at a 60:40 mix.

Example: use two mixed colors in an event information card

Imagine an information card for a weekend design workshop. Start with a vivid blue #2563EB and a more subdued teal #0F766E. Mixing 60% blue and 40% teal produces approximately #1C6BB9, which works as the main action-button background in this design. Mixing 20% blue and 80% teal produces approximately #137287, which we use for the short “Registration open” label and the card’s left border. Both variations come from the same two colors, helping the accents feel related while serving distinct purposes.

<section class="event-card">
  <p class="event-card__label">Registration open</p>
  <h2>Weekend design workshop</h2>
  <p>Review the schedule and details before signing up.</p>
  <a class="event-card__action" href="/events/">View event details</a>
</section>
:root {
  --event-blue: #2563EB;
  --event-teal: #0F766E;
}
.event-card {
  padding: 24px;
  border-left: 6px solid #137287;
  background-color: #F8FAFC;
  color: #172033;
}
.event-card__label {
  display: inline-block;
  padding: 6px 12px;
  border-radius: 999px;
  background-color: #137287;
  color: #FFFFFF;
}
.event-card__action {
  display: inline-block;
  padding: 12px 18px;
  border-radius: 8px;
  background-color: #1C6BB9;
  color: #FFFFFF;
  text-decoration: underline;
}
.event-card__action:hover { background-color: #137287; }
.event-card__action:focus-visible {
  outline: 3px solid #172033;
  outline-offset: 3px;
}
@supports (color: color-mix(in srgb, red, blue)) {
  .event-card {
    border-left-color: color-mix(
      in srgb, var(--event-blue) 20%, var(--event-teal));
  }
  .event-card__label, .event-card__action:hover {
    background-color: color-mix(
      in srgb, var(--event-blue) 20%, var(--event-teal));
  }
  .event-card__action {
    background-color: color-mix(
      in srgb, var(--event-blue) 60%, var(--event-teal));
  }
}

The broad card surface is a very light gray #F8FAFC, with dark blue-gray #172033 for its heading and paragraph. The label and button use white #FFFFFF lettering. On hover, the action changes toward the teal-heavy mixture while retaining its underline. The :focus-visible selector adds a focus outline when the link is navigated to using the keyboard or a comparable input method. The /events/ URL is illustrative and should be replaced with an actual destination.

The CSS starts with fixed colors as fallbacks for older browsers without color-mix() support. The @supports rule checks whether the color-mixing syntax is supported before applying mixtures based on the two CSS custom properties, also known as CSS variables. In a supported browser, changing either source color updates the mixed accents. The fixed fallback values would need separate updating for browsers that rely on them.

Check contrast and the effect of changing the mixing ratio

For this palette, dark blue-gray text #172033 on the light card surface #F8FAFC has a contrast ratio of approximately 15.55:1. White text #FFFFFF on the usual action-button background #1C6BB9 reaches about 5.45:1; white text on the teal-heavy label or hover background #137287 reaches about 5.55:1. These combinations exceed the 4.5:1 minimum for normal-sized text in the Web Content Accessibility Guidelines (WCAG) 2.2.

The teal-heavy left border #137287 against the card surface #F8FAFC has a contrast ratio of approximately 5.30:1. The dark blue-gray focus outline #172033 against the card background measures about 15.55:1. When an interface boundary or state indicator is necessary for understanding or operating a control, a non-text contrast ratio of at least 3:1 against its adjacent colors is an important requirement. Also inspect line thickness and the actual colors around the component.

Whenever you change the mixing ratio, recheck the resulting color against its text. Changing the color space or mixing partially transparent colors also affects the output. Unlike background-blend-mode, which blends an element’s background layers, color-mix() calculates a new color value from its inputs. HueRoll can help you explore palette candidates and HEX codes and compare a selected color against white or black. It does not automatically check every arbitrary foreground/background pair, so verify the final combination separately.