TaskBuild a button with hover/pressed states using color-mix. :root --primary oklch(0.66 0.18 252). .btn background var(--primary), color white. .btn:hover background color-mix(in oklch, var(--primary), white 15%). .btn:active background color-mix(in oklch, var(--primary), black 15%).
color-mix(): derive shades from one source
100 XP7 min
Theory
One color, infinite tints
:root { --brand: oklch(0.66 0.18 252); }
.hover { background: color-mix(in oklch, var(--brand), white 20%); } /* 20% lighter */
.pressed { background: color-mix(in oklch, var(--brand), black 20%); } /* 20% darker */
.bg-tint { background: color-mix(in oklch, var(--brand), transparent 90%); } /* 10% opacity */color-mix(in COLORSPACE, COLOR-A, COLOR-B PERCENT) blends A and B at the given percentage in the specified color space.
Why mix in OKLCH
color-mix(in srgb, blue, white 30%); /* sRGB mix β can look washed out */ color-mix(in oklch, blue, white 30%); /* OKLCH mix β perceptually correct */
OKLCH interpolation keeps perceived brightness on the path. Use it for any "lighten/darken" mix.
Common patterns
:root { --primary: oklch(0.66 0.18 252); }
.button { background: var(--primary); }
.button:hover { background: color-mix(in oklch, var(--primary), white 15%); }
.button:active { background: color-mix(in oklch, var(--primary), black 15%); }ONE source color, derived states. Redesign? Change --primary once, all states update.
Browser support (2026)
Chrome / Edge / Safari / Firefox all shipped. Treat as fully available. Older Safari (<16.4) needs the @supports (color: color-mix(...)) fallback for production sites with long-tail support.
π
Sign up to start coding
Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial β card required, cancel anytime.
Sign up β free trial βFirst 10 lessons in each track are free. No card needed for those.