← All articles

Color Shifting Without the Muddy Middle

Juniper Hale · 1 min read

Part of the series Wobbly Motion

Share image
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.

Two gradients from red to blue: the top passes through grey, the bottom through vivid purple
Top: interpolating in RGB. Bottom: the scenic route through hue.

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

gradient.css
.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.

0 comments

  • Be the first to comment.