Skip to content
ColorArchive
Issue 113
2028-02-25

Designing gradients that look good: interpolation, stops, and perceptual smoothness

A gradient between two colors should look smooth, but CSS linear-gradient often produces a muddy, desaturated band through the middle of the transition. The problem is that CSS gradients interpolate in sRGB space, which is not perceptually uniform — the midpoint of a red-to-blue gradient passes through a desaturated purple-gray, not a vibrant purple. Modern CSS now offers interpolation in perceptually uniform spaces like OKLCH and OKLab, which produce gradients that stay saturated and visually smooth across the entire range. Understanding this system changes how you design gradients.

Highlights
The sRGB gradient problem is most visible in three specific color transitions: red-to-green (which passes through a muddy brown-yellow band), blue-to-yellow (which passes through a desaturated grayish-green), and any transition between two colors with different hue values in sRGB. The cause is mathematical: sRGB interpolation mixes the raw channel values linearly, which does not correspond to how human perception measures color change. A gradient that looks smooth in a linear interpolation formula often produces a clearly visible dark band at the midpoint when measured perceptually. The fix, available in modern CSS via the `color-interpolation-method` syntax: `background: linear-gradient(in oklch, #hsl1, #hsl2)` — this instructs the browser to perform gradient interpolation in OKLCH space, which is perceptually uniform and produces gradients that stay vibrant and smooth.
Hue interpolation in OKLCH gradients introduces a new choice: which direction to traverse the hue circle between two endpoint colors. The default (shorter arc) is usually correct, but the `increasing` and `decreasing` keywords let you specify clockwise or counterclockwise hue traversal. A gradient from orange to blue-violet in OKLCH shorter arc passes through green (shorter path on the hue wheel); in OKLCH longer arc it passes through red and magenta. Neither is automatically better — the right choice depends on whether the intermediate hues are desirable for your design. The ability to specify hue interpolation direction is one of the key advantages of OKLCH over sRGB gradient interpolation, which gives you no control over the intermediate hue path.
Strategic color stop placement is the professional technique for controlling gradient character without switching interpolation methods. Instead of a 2-stop gradient (color A to color B), adding 1-2 intermediate stops lets you shape the gradient's midpoint behavior: a gradient with a slightly lighter or more saturated midpoint stop creates a more luxurious, backlit quality; a slightly darker midpoint produces depth and dimension. The classic 3-stop technique for premium gradients: darken the midpoint by 5-10% lightness relative to a straight interpolation of the two endpoints. This prevents the gradient from looking flat or washed out at the center, which is the most common failure mode of two-stop gradients.

Why CSS gradients look muddy and how to fix it

Default CSS gradient interpolation happens in sRGB, which is a display-encoding space optimized for hardware signal levels, not perceptual uniformity. When you interpolate from red (#ff0000) to blue (#0000ff) in sRGB, the mathematical midpoint (#7f007f) is a dark, desaturated purple that looks significantly dimmer than either endpoint. The resulting gradient has a clearly visible dark band through the center. The CSS Color Level 4 specification introduced gradient interpolation in perceptually uniform spaces: `background: linear-gradient(in oklch, red, blue)`. In OKLCH, the interpolation path stays at constant perceived lightness and saturation — producing a gradient that maintains visual vibrancy across its full width. Browser support for OKLCH gradient interpolation is now at 93% globally (Chrome 111+, Firefox 113+, Safari 16.2+), making it safe to use in most production contexts with a sRGB fallback for older browsers.

Interpolation space comparison

Gradient interpolation quality varies significantly by color space. sRGB (browser default): produces muddy midpoints on multi-hue gradients; the most common cause of gradient disappointment in UI design. Linear-light sRGB (`in srgb-linear`): slightly better than sRGB for luminance consistency, but still not hue-uniform. OKLab (`in oklab`): perceptually uniform lightness and saturation, but hue interpolation is linear in Lab space which can produce unexpected intermediate hues for some color pairs. OKLCH (`in oklch`): perceptually uniform with hue interpolation along the hue wheel arc — generally the best choice for vibrant multi-hue gradients. HSL (`in hsl`): hue interpolation along the hue wheel like OKLCH but using the non-perceptual HSL space, so luminance varies significantly between hues. P3 (`in display-p3`): useful for wide-gamut gradient endpoints on P3-capable displays, but interpolation still follows sRGB's non-uniform path. The practical recommendation: use `in oklch` as your default for multi-hue gradients; use `in oklab` for same-hue gradients where you want smooth lightness transitions without hue shift.

Designing gradient color stop placement

The professional approach to gradient stop placement: (1) Start with your two endpoint colors. (2) Render the gradient and identify any visual problems — muddy midpoint, perceived dark band, flat center. (3) Add a third stop at 50% position set to a color that corrects the problem: typically 5-10% lighter than the sRGB interpolated midpoint, or shifted toward a more saturated intermediate hue. (4) Add a fourth stop if the correction creates a new problem on either half of the gradient. This process typically reaches a satisfying result in 3-4 stops. More than 4-5 stops usually indicates a more fundamental color choice problem (the two endpoint colors are simply incompatible for a smooth gradient) rather than a stop-placement problem. The alternative: choose endpoint colors that share similar perceptual lightness, which naturally produces smoother gradients regardless of interpolation method.

Practical CSS gradient patterns

The production-ready CSS gradient pattern with OKLCH interpolation and fallback: define the sRGB fallback first, then add the enhanced version using @supports. For a gradient from cobalt to violet: `.gradient-hero { background: linear-gradient(135deg, #2563EB, #7C3AED); } @supports (background: linear-gradient(in oklch, red, blue)) { .gradient-hero { background: linear-gradient(in oklch 135deg, oklch(0.55 0.22 265), oklch(0.47 0.22 305)); } }` — this gives modern browsers the perceptually smooth OKLCH gradient while providing a reasonable sRGB fallback. For animated gradients (CSS custom property animation or JavaScript), prefer OKLCH for the same reason — linear interpolation of OKLCH values produces smooth, physically plausible transitions that sRGB interpolation does not.

Newer issue
Color and typography: contrast ratios, optical size, and legibility at scale
2028-02-18
Older issue
Building a brand color system from scratch: primary, secondary, accent
2028-03-04