Color Mix Crossfade
Three CSS blocks compare color-mix() blending paths live — oklch vs sRGB, zero JavaScript.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Backgrounds has 50 effects, including 6 free. Explore the category →
3 usage examples



How it works
The CSS color-mix() function takes two colors and a color space, then returns the color at the midpoint of the path between them in that space. The effect places two instances side by side: the center block shows color-mix(in oklch, …) at rest, and switches to color-mix(in srgb, …) on hover — via a :hover selector alone, no JavaScript.
The visual difference comes from the geometry of each space: oklch is perceptually uniform (L = constant lightness, C = chroma, H = hue), so the midpoint between an orange-red oklch(.65 .28 30) and a blue-violet oklch(.6 .25 260) produces a saturated purple. sRGB linearly interpolates its raw R, G, B channels — the path crosses the center of the RGB cube, which desaturates the result toward a muddy gray.
On hover of the .crossfade-container, three changes trigger at once: blocks A and B shift apart by 20 px via transform: translateX(±20px), the mix block widens from 60 px to 120 px, and its background switches from the oklch version to the sRGB version. Every animation is driven by the transition properties declared on each block (1.2 s for A and B, 1 s for the mix). The active blend space is indicated by the .crossfade-info label that gains opacity on hover.
Accessibility
- ⚠️ prefers-reduced-motion is absent: transitions (1.2 s and 1 s) run regardless of system preference. Add
@media (prefers-reduced-motion: reduce) { .crossfade-block { transition: none } }before deploying to production. - The interaction is triggered by :hover only — keyboard users cannot trigger the comparison without an additional script.
.crossfade-infois a<span>in the DOM flow — its text is read by screen readers.- No
roleoraria-labelon the colored blocks — they are purely decorative in the original demo. .crossfade-infocontrast: white at 60% opacity on#0f0f1a— ratio below the WCAG AA threshold for small text (target 4.5:1 not met).
Browser compatibility
Requires color-mix() and oklch() — available in all modern browsers since early 2023.
Without <code>color-mix()</code> or <code>oklch()</code> support, the mix block renders without a background (transparent); blocks A and B may also lose their color. No JS error — degradation is silent.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="demo-preview">
<div class="chroma-demo crossfade-container">
<div class="crossfade-blocks">
<div class="crossfade-block block-a"></div>
<div class="crossfade-block block-mix"></div>
<div class="crossfade-block block-b"></div>
</div>
<span class="crossfade-info">hover: oklch → srgb blend path</span>
</div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| .block-a { background } | oklch(.65 .28 30) | First source color. Accepts any valid CSS format: hex, rgb, hsl, oklch. |
| .block-b { background } | oklch(.6 .25 260) | Second source color. Keeping both in the same space (oklch + oklch) gives the most predictable results. |
| color-mix(in oklch, …) — rest | oklch | Blend space shown at rest. Replace with lch, lab, or hsl for a different starting comparison. |
| color-mix(in srgb, …) — hover | srgb | Blend space revealed on hover. The oklch / sRGB pair shows the most striking contrast; try oklch / hsl for another perspective. |
| .crossfade-block { transition } | 1.2s | Duration of the A and B block translation. Reduce to 0.4 s for a snappy response, increase to 2 s for a slow crossfade. |
| .block-mix { width } / hover 120px | 60px / 120px | Mix block width at rest and on hover. Increase the hover value to emphasize the result; reduce both for more compact blocks. |
| .crossfade-info (text) | "hover: oklch → srgb blend path" | Descriptive label below the blocks. Update it to reflect the color spaces you are comparing. |
FAQ
background: #hex fallback just before the color-mix() rule — browsers that don't recognize the value apply the previous one.background: var(--color-a) and color-mix(in oklch, var(--color-a), var(--color-b)). Update them from JavaScript: el.style.setProperty('--color-a', newColor). color-mix() recomputes the result immediately.color-mix(in lab, …), color-mix(in hsl, …)) and reveal them on other states: :focus-within, a JS-toggled class on click, or cascading :hover selectors. The CSS structure is identical for each additional block.