Gradients went from tacky to tasteful and back again so many times that designers got gun-shy about them. But a good gradient is one of the cheapest ways to make a flat interface feel like it has depth and light. The problem is that most gradients fail in exactly one place — the middle — and that failure is so common it taught a generation of designers to avoid the tool entirely. Once you understand why the midpoint goes muddy, you can fix it deliberately, and gradients become a reliable part of the kit instead of a gamble. Here's the mental model and the moves I actually use.
A gradient is a path, not a pair
The mistake hiding inside every muddy gradient is thinking of it as two colors. It's not. It's a path between two colors, and the question that decides whether it looks good is: what route does the blend take to get from A to B?
When you write a plain CSS gradient like linear-gradient(#3B82F6, #F59E0B) — a blue to an amber — the browser, by default, interpolates in sRGB by walking a straight line through color space. Picture the color wheel from above. Blue sits on one side, amber roughly opposite. The straight line between them doesn't follow the colorful rim; it cuts directly across the desaturated gray center. So the midpoint of that gradient is a sad, washed-out grayish tone. That's the mud. It's not a rendering bug — it's geometry. The shortest path between two opposite hues runs through gray.
This single insight reframes everything. If muddiness comes from the path, then fixing it means controlling the path. There are three main levers: pick colors whose straight path is already good, reroute the path with an intermediate stop, or change the color space so the default path curves around the wheel instead of through it.
Lever one: choose colors that are kind to each other
The easiest clean gradient is between two colors that are close in hue — an analogous pair. Blend #3B82F6 (blue) into #6366F1 (indigo) and the straight-line path barely leaves the blue-violet neighborhood, so there's no gray zone to fall into. The result is smooth and rich automatically.
This is why so many premium-feeling gradients are subtle: blue to purple, teal to green, magenta to red-orange. They're analogous, often within 30–60 degrees of hue, and they vary lightness more than they vary hue. A gradient that mostly changes lightness while keeping hue near-constant is nearly impossible to make muddy. If you want a safe starting point, build a monochromatic or analogous set first, then blend within it.
The corollary: complementary gradients (colors 180 degrees apart) are the hardest to keep clean, precisely because their straight path runs dead through the center. They can be done — but they need one of the next two levers.
Lever two: add a stop to steer the path
When you genuinely want two distant colors — a blue and a warm orange, say, because they're both brand colors — don't let the browser pick the midpoint. Pick it yourself with a third stop.
Instead of linear-gradient(#3B82F6, #F59E0B), try routing through a hue that bridges them: linear-gradient(#3B82F6, #C084FC, #F59E0B). That violet middle stop pulls the path around the wheel through purple and pink rather than through gray. Now the transition stays saturated the whole way. You've manually drawn the colorful route the straight line refused to take.
Choosing the bridge color is the craft part. Ask which way around the wheel you want to travel — blue to amber can go through purple/magenta (the warm route) or through green/teal (the cool route), and they feel completely different. The warm route reads sunset; the cool route reads tropical. Pick intentionally. You can audition bridge colors quickly by generating a palette in the color palette generator and dropping candidate hues between your endpoints.
Keep it to one, maybe two, intermediate stops. Each extra stop is another place the gradient can develop a visible seam or band. More stops is not more luxury — restraint reads as luxury.
Lever three: interpolate in a better color space
The modern fix, and increasingly my default, is to change the space the blend happens in. CSS now lets you specify the interpolation color space directly: linear-gradient(in oklch, #3B82F6, #F59E0B).
OKLCH (and its cousin LCH) is perceptually uniform — equal numeric steps look like equal visual steps to your eye — and crucially, when you ask it to interpolate hue, it travels around the hue wheel rather than across the Cartesian middle. The practical effect is that the same two-color blue-to-amber gradient stops dipping into gray and instead sweeps through vivid intermediate hues automatically, no manual stop required. The MDN docs on gradient color interpolation cover the syntax and the shorter hue / longer hue options, which let you control which direction around the wheel the blend goes.
A few honest caveats. Browser support for in oklch is good in current browsers but not universal, so provide a standard sRGB fallback (background: linear-gradient(#3B82F6, #F59E0B); before the OKLCH line). And OKLCH can occasionally produce too vivid a midpoint for subtle backgrounds — for a barely-there hero wash, plain sRGB between close colors is still fine. Reach for OKLCH when the endpoints are far apart and you want them to stay saturated.
Angles, types, and where gradients belong
The path is the hard part; the rest is taste, but there are conventions worth knowing.
- Linear, top to bottom (`180deg`) mimics overhead light and feels natural on buttons and cards. A button going from
#4F8EF7down to#3B6FD4reads as gently lit and three-dimensional. - Diagonal (`135deg`) adds direction and energy — the default for big hero backgrounds because it feels dynamic without being loud.
- Radial gradients put a soft glow at a point; lovely for spotlighting a focal element or faking ambient light behind a card.
- Conic gradients sweep hue around a center and are mostly for charts, loaders, and color-picker wheels rather than backgrounds.
For depth, keep the two colors close in lightness and hue — a subtle gradient (#1E293B to #0F172A) on a dark surface adds richness no flat fill can. For impact, let the gradient be the hero and give it room.
Don't forget the text
Gradients and text have a fraught relationship. Contrast has to hold across the entire span of the gradient, not just where you happened to drop the headline. A title that passes WCAG contrast over the light top of a gradient can quietly fail over the darker bottom. Test the worst-case point, lean on the WCAG contrast ratios (4.5:1 for body text, per the W3C guidance), and when in doubt drop a semi-transparent solid overlay behind the text so its background is predictable. Or simply keep gradients in decorative zones and put text on solid fills.
The short version
Stop thinking of a gradient as two colors and start thinking of it as the line between them. Muddy middles come from a straight path through gray; you fix them by choosing kinder colors, steering with an intermediate stop, or interpolating in OKLCH so the path curves around the rim. Master that and gradients stop being a risk and become one of the most efficient ways to add light, depth, and personality to flat work. Pull two colors from the color palette generator, drop them into a linear-gradient(in oklch, …), and watch a blend that would've gone gray stay alive all the way across.
Frequently Asked Questions
Why does the middle of my gradient look gray or muddy?
When you blend two colors in the default sRGB space, the interpolation cuts straight across the color wheel rather than around it. If your two colors are far apart in hue — say a blue and a yellow — that straight line passes through the low-saturation gray center, so the midpoint desaturates and looks muddy. The fix is either to choose colors closer in hue, add an intermediate color stop to route the blend around the wheel, or use a color space and hue interpolation method that travels around the rim instead of through the middle.
What color space should I use for CSS gradients?
For most modern work, interpolating in OKLCH or LCH produces noticeably smoother, more even gradients than the default sRGB, because those spaces are perceptually uniform — equal numeric steps look like equal visual steps. You opt in with syntax like 'linear-gradient(in oklch, #3B82F6, #F59E0B)'. The default sRGB is fine for blends between close, similar colors, but for vivid two-color gradients OKLCH avoids the dull midpoint and dead zones. Always check browser support and provide a standard fallback for older browsers.
How many color stops should a gradient have?
Two stops are enough for a simple, subtle blend, and that's where most clean UI gradients live. Add a third intermediate stop when your two endpoints are far apart in hue and the automatic midpoint looks wrong — the middle stop lets you steer the path through a flattering color instead of through gray. Beyond three or four stops you usually create banding and visual noise rather than richness. For backgrounds, fewer stops with a gentle transition almost always looks more premium than a busy rainbow.
What angle should a linear gradient be?
There's no single correct angle, but a few conventions read as polished: a top-to-bottom gradient (180deg) feels like natural overhead lighting, while a diagonal around 135deg adds a sense of direction and energy without being chaotic. Subtle vertical gradients work well for buttons and cards because they mimic how light falls. Steep or unusual angles draw attention to the gradient itself, which you want only when the gradient is the hero element rather than a quiet background.
Are gradients an accessibility problem for text?
They can be, because text contrast must hold across the entire area the text covers, not just at one point. A heading over a gradient that runs from light to dark might pass contrast at the top and fail at the bottom. The safe approaches are to keep text only over the region of the gradient where contrast stays above the WCAG threshold, add a solid or semi-transparent overlay behind the text, or limit gradients to non-text decorative areas. Always test the worst-case point of the gradient, not the average.
Want to experiment with colors?
Try our free color palette generator to find your perfect harmony — with a built-in WCAG contrast checker.
Open the Generator