Color Shifting Without the Muddy Middle
Part of the series Wobbly Motion
- Share image
A little while ago I tried to animate a background so that it cycled through the rainbow. Easy, right? Except the transition kept passing through a dull, murky grey. It turns out browsers have a surprising limitation when it comes to colour.
Why the middle goes muddy
By default, the browser interpolates each RGB channel separately. Halfway between rgb(255 0 0) and rgb(0 0 255) is rgb(128 0 128)... and as you move further, the channels cancel each other out.
Option 1: interpolate in a better space
.banner {
background: linear-gradient(
in oklch longer hue,
red, blue
);
}oklch is perceptually even, so equal steps look equal. longer hue takes the long way round the colour wheel, which is how you get a rainbow out of two stops.
Option 2: animate a custom property
Registered custom properties can be animated, which means we can animate a hue rather than a colour:
@property --hue {
syntax: '<number>';
inherits: false;
initial-value: 0;
}
.rainbow {
background: hsl(var(--hue) 90% 60%);
animation: spin-hue 6s linear infinite;
}
@keyframes spin-hue {
to { --hue: 360; }
}The takeaway
When colour looks wrong, ask which space the browser is mixing in. Nine times out of ten, that's the bug.