Modern CSS Colour: oklch(), color-mix() and Relative Colours
#hex and rgb() describe colours the way screens produce them, not the way people see them. Newer CSS colour functions make palettes more consistent and easier to generate.
oklch(): perceptual colour
:root {
/* oklch(lightness chroma hue) */
--brand-300: oklch(0.80 0.10 190);
--brand-500: oklch(0.62 0.15 190);
--brand-700: oklch(0.45 0.12 190);
}
- Lightness (0-1) matches perceived brightness, so equal steps look like equal steps.
- Chroma is colourfulness; hue is an angle from 0 to 360.
- Keep lightness the same and change hue to get colours that feel equally bright, ideal for charts and status colours.
- It can describe wide-gamut (P3) colours that hex can't.
color-mix(): tints, shades and transparency
.button:hover {
background: color-mix(in oklch, var(--brand-500), black 15%);
}
.badge {
background: color-mix(in srgb, var(--brand-500) 12%, transparent); /* soft tinted background */
}
Relative colour syntax
Take an existing colour and change one channel:
.card {
--accent: oklch(0.62 0.15 190);
border-color: oklch(from var(--accent) calc(l + 0.2) c h); /* lighter */
box-shadow: 0 0 0 3px oklch(from var(--accent) l c h / 0.3); /* 30% opacity */
}
Practical advice
- Define a few base colours as variables and derive hover, focus and background shades from them.
- Still check contrast for text; perceptual lightness helps but isn't a guarantee.
- All of these work in current versions of every major browser.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.