A gradient's interpolation space is a hint written inside the function, and leaving it out is not neutral: every unhinted gradient in CSS blends in sRGB, which is where blue to yellow runs through grey. Two background-image declarations come out of this page and you need both, in the order they are written.
What in oklch is, and when it landed in CSS
A gradient's colour interpolation method is the space the browser blends the stops in, written inside the function after the geometry: linear-gradient(90deg in oklch, #0000ff, #ffff00). Leave it out and every gradient in CSS interpolates in sRGB, which is what browsers have always done. The syntax comes from CSS Color 4 and shipped in Safari 16.2 in December 2022, Chrome and Edge 111 in March 2023, and Firefox 127 in June 2024.
One name collision worth clearing up: the images spec calls a bare percentage between two stops, as in linear-gradient(red, 30%, blue), a colour interpolation hint, and all it does is move the halfway point of the blend along the line. That is a separate and much older feature, in browsers since Firefox 36 and Chrome 40, and it has nothing to say about which space the blend happens in.
Why sRGB runs blue to yellow through dead grey
In sRGB the three coordinates are the values a display is driven with, and #0000ff and #ffff00 sit at opposite corners of that cube: (0, 0, 255) and (255, 255, 0). A straight line between opposite corners passes through the exact centre, so the midpoint is (128, 128, 128), which is #808080. That is not a browser bug and nudging the endpoints does not fix it. Saturation is not one of the three coordinates, so nothing in the arithmetic preserves it, and the colour drains out of the middle of the ramp.
OKLCH's coordinates are lightness, chroma and hue, on axes Björn Ottosson fitted to how people report seeing colour in 2020. Interpolation moves the three separately, so chroma carries all the way across and the hue travels around the circle rather than through the neutral point at its centre. The same blue to yellow goes through a teal at hue 187 with its chroma intact. The reading under each comparison bar is that difference as a number: the chroma of the halfway colour, measured in OKLCH either way.
in hsl gives a third answer again
HSL is polar too, so in hsl rotates the hue rather than crossing the middle, but its axes are geometry rather than perception and the route is different. Blue is hsl(240) and yellow is hsl(60): exactly half a turn apart, which is the one case where "the shorter way round" has no answer. The spec leaves the difference signed, so browsers walk down from 240 and the middle of the ramp is the green at 150. Ask for longer hue and the same two stops go the other way, through magenta and red. HSL holds saturation the whole way, so neither route greys out, but HSL's lightness is the midpoint of the largest and smallest channel rather than anything perceptual, so the ramp gets a bright band wherever the hue passes through yellow-green.
shorter hue and longer hue on a conic gradient
The hue methods choose which arc of the hue circle the blend walks, and on a conic gradient that choice is the difference between a slice of the colour wheel and nearly all of it. shorter hue is the default and takes the smaller arc; longer hue takes the other one. Two stops with almost the same hue and longer hue sweep close to a full 360 degrees, which is the shortest way to write a colour wheel in CSS.
increasing hue and decreasing hue name a direction outright instead of measuring which arc is shorter, and they are what you want whenever two hues sit near half a turn apart. There, "shorter" is decided by a rounding difference and can flip to the opposite side of the wheel when you nudge a stop by one unit. Naming the direction makes the result stable. All four are only valid in a polar space: in oklab longer hue is a parse error, because OKLab has no hue axis to walk, and this tool hides the control rather than emitting a declaration a browser will drop.
The fallback declaration has to come first
A browser that does not understand in oklch does not quietly fall back to sRGB. The value fails to parse, so the whole background-image declaration is thrown away and the element gets no gradient at all. Nothing in CSS can say "use this hint if you know it", so the only mechanism available is the cascade: write the unhinted declaration first, the hinted one second, and every engine keeps the last one it could parse. Older engines stop at the first, current ones take the second, and no @supports block is needed. Reversing the order is the one way to get this wrong, and it fails silently by making the fallback win everywhere.
What the preview can and cannot tell you
The preview is your own browser rendering the same CSS you are about to copy, not a re-implementation of it, so what you see is what ships to a browser like yours. It is not what everyone sees. A browser without interpolation methods gets the first declaration, and that is a genuinely different picture: blue to yellow through grey instead of through teal. The two comparison bars are those two pictures side by side, which is as close as this page can get to showing you both at once. A wide-gamut display adds a second gap, because the browser maps colours to the screen rather than to sRGB, so a saturated ramp can look more vivid on your machine than the hex values imply.
Common problems
- The element has no gradient at all in an older browser. Only the hinted declaration shipped. An unparseable value invalidates its own declaration and nothing else, so the unhinted one has to be there, above it, to be kept.
- A stop added by clicking is not the colour that was under the pointer. The sampler walks the shorter way round the hue circle, so under
longer,increasingordecreasing huethe rendering took a different route than the sample did. It also happens within hslbetween two hues exactly half a turn apart, where the sampler and the browser break the tie in opposite directions. Set the stop's colour to what you wanted; nothing else about the gradient is affected. - A conic gradient has a hard seam. The sweep comes back to where it started, so unless the last stop is the same colour as the first there is a visible edge at the start angle. That is the geometry, not a bug. Add a closing stop at 100% matching the one at 0%.
- The ramp is banded rather than smooth. A gradient stretched across a large area crosses fewer than one 8-bit step per column, and the flat bands are what is left. Browsers dither to hide it and mostly succeed. Shorten the run, or overlay a faint noise texture, which is what the banding-free gradients in design systems are doing.
Frequently asked questions
Which interpolation space should I use?
OKLCH for anything new: it keeps chroma across the middle and its lightness matches what you see. OKLab when you would rather the hue never surprised you, since it interpolates on rectangular axes and cannot swing round the wheel. sRGB when you are reproducing a gradient that already exists, where a better ramp is the wrong answer. HSL only to match something built in it.
Does the space change the colours at the ends?
No. Both endpoints are exactly the colours you wrote, in every space. The interpolation method only decides the path between them, which is why the hinted and unhinted declarations can safely disagree: any browser shows the stops you chose, and they differ only in what happens between them.
Why does fading to transparent not go grey any more?
Because gradients interpolate in premultiplied alpha. transparent is defined as transparent black, and interpolating its channels directly used to drag the middle of a fade towards a dark grey. Premultiplying makes a fully transparent stop's colour irrelevant, so #0000ff to transparent and #0000ff to #0000ff00 now give the same ramp. That fix has been in Chrome since 29, Firefox since 36 and Safari since 15.
Can I put a gradient on text or on a border?
On text, set the gradient as the background-image, then background-clip: text and color: transparent. Give the element a readable fallback color first, because the text vanishes if the clip fails. A border needs border-image, which does not follow border-radius; for a rounded gradient border, layer two backgrounds with background-clip: padding-box, border-box instead.
Does anything here leave my browser?
No. The stops, the sampling, the gamut mapping and the CSS are all computed in the page, and the preview is your own browser painting the result. There is no request to send anywhere. The only thing that leaves is the URL, if you choose to share it, and it carries nothing but the stops, the geometry, the space and the hue path.