Most active commenters
  • itishappy(8)
  • chrismorgan(6)
  • layer8(4)
  • cubefox(4)
  • the_af(4)
  • Dylan16807(4)
  • JKCalhoun(3)
  • anotheryou(3)

←back to thread

856 points tontonius | 68 comments | | HN request time: 1.513s | source | bottom
1. chrismorgan ◴[] No.45011025[source]
The “Better Gradients” thing is dodgy.

OKLCH is a polar coordinate space. Hue is angle in this space. So to interpolate hue from one angle to another, to get from one side of a circle to the other, you go round the edge. This leads to extreme examples like the one shown:

  linear-gradient(in oklch, #f0f, #0f0)
You can also go round the circle the other way, which will take you via blue–aqua instead of via red–yellow:

  linear-gradient(in oklch longer hue, #f0f, #0f0)
The gradient shown (in either case) is a good example of a way that perceptual colour spaces are really bad to work in: practically the entire way round the edge of the circle, it’s outside sRGB, in fact way outside of the colours humans can perceive. Perceptual colour spaces are really bad at handling the edges of gamuts, where slightly perturbing the values take you out of gamut.

Accordingly, there are algorithms defined (yes, plural: not every application has agreed on the technique to use) to drag the colour back in-gamut, but it sacrifices the perceptual uniformity. The red in that gradient is way darker than the rest of it.

When you’re looking for better gradients, if you’re caring about perceptual uniformity (which frequently you shouldn’t, perceptual colour spaces are being massively overapplied), you should probably default to interpolating in Oklab instead, which takes a straight line from one side of the circle to the other—yes, through grey, if necessary.

  linear-gradient(in oklab, #f0f, #0f0)
And in this case, that gets you about as decent a magenta-to-lime gradient as you can hope for, not going via red and yellow, and not exhibiting the inappropriate darkening of sRGB interpolation (… though if I were hand-tuning such a gradient, I’d actually go a bit darker than Oklab does).

During its beta period, Tailwind v4 tried shifting from sRGB to Oklch for gradient interpolation; by release, they’d decided Oklab was a safer default.

replies(12): >>45011178 #>>45011340 #>>45012378 #>>45012990 #>>45013291 #>>45013348 #>>45014196 #>>45015512 #>>45018962 #>>45019530 #>>45023600 #>>45040825 #
2. ta8645 ◴[] No.45011178[source]
Very interesting. Is this just a limitation of our current hardware? How much of this problem would still exist if everyone had a wider gamut monitor, say full DCI-P3? That still doesn't cover the full gamut of Oklch, but would it make the problem practically disappear?
replies(2): >>45011248 #>>45013136 #
3. chrismorgan ◴[] No.45011248[source]
No. We’re talking about colours way beyond the ranges of human perception.

For this specific gradient, see https://oklch.com/#0.7017,0.3225,328.36,100 and https://oklch.com/#0.86644,0.294827,142.4953,100, and look at the Chroma panel, see how far out of our screen gamuts they are (even tick “Show Rec2020”, which adds a lot of chroma around blue–green and magenta–red), and try to imagine the colours between the lime and magenta (in either direction). The red direction is probably the easier to reason about: there’s just no such colour as a light, bright red. You can have bright or light, but not both. (Its 3D view can also be useful to visualise these things: you’re building a straight-line bridge between two peaks, and there’s a chasm in between.)

replies(3): >>45011276 #>>45011437 #>>45013719 #
4. ta8645 ◴[] No.45011276{3}[source]
But once an algorithm to drag the colours back in-gamut was applied, would the lost perceptual uniformity still be a problem practically speaking, with DCI-P3 monitors?
replies(1): >>45011314 #
5. chrismorgan ◴[] No.45011314{4}[source]
Yes. I repeat: these colours are way outside gamut. Not just a little bit. P3 helps a little bit, Rec.2020 would help a fair bit more, but you’re still asking for a yellow that is about twice as vibrant as is possible.
6. Vingdoloras ◴[] No.45011340[source]
For anyone else copy pasting the gradients into dev tools to look at them: The second one is missing the # sign on the first color.

And yes, both oklch gradients look pretty weird while the oklab gradient looks nice (if you can accept it going through grey).

replies(2): >>45011374 #>>45013579 #
7. chrismorgan ◴[] No.45011374[source]
Sorry, fixed.
8. shrx ◴[] No.45011437{3}[source]
I don't get it, why am I seeing the "out of gamut" colors if my sRGB monitor is unable to display them? Would the charts look different on a P3 monitor?

edit: Also, you mentioned the colors "beyond the ranges of human perception" but I don't think there is any such limitation here, the bottleneck is the hardware (computer monitors).

replies(2): >>45011477 #>>45013739 #
9. chrismorgan ◴[] No.45011477{4}[source]
It’s squashing the range of the colours down to simulate it.
10. Diggsey ◴[] No.45012378[source]
Also, isn't the way browsers interpolate colors in sRGB just a bug that I assume is retained for backwards compatibility? sRGB is a logarithmic encoding, you were never supposed to interpolate between colors directly in that encoding - the spec says you're suppose to convert to linear RGB first and do the interpolation there...
replies(1): >>45014341 #
11. djoldman ◴[] No.45012990[source]
But what really is a "color gradient"?

Isn't it any continuous function that starts at a specified color and ends at another specified color?

How then does one say that any gradient is good or bad?

Isn't the problem you are highlighting guaranteed to exist for any colorspace that defines colors outside of human perception?

replies(2): >>45013072 #>>45015813 #
12. layer8 ◴[] No.45013072[source]
A good gradient is one that takes a perceptually uniform, and typically perceptually shortest, path. The OKLCH gradient isn't perceptual uniform and appears to take unnecessary detours through other hues.
replies(1): >>45013444 #
13. layer8 ◴[] No.45013136[source]
The underlying problem is that the color space humans can see doesn’t have nice uniform linear boundaries. The larger your color space, the more relevant that issue actually becomes.
14. jakubkrehel ◴[] No.45013291[source]
This is super insightful, thank you! I wrote the article and will make changes to explain this better :)
15. cubefox ◴[] No.45013348[source]
> The red in that gradient is way darker than the rest of it.

It doesn't look significantly darker to me.

16. cubefox ◴[] No.45013444{3}[source]
One could also argue that the detour through other hues is necessary in this case to avoid going through grey.
replies(1): >>45013622 #
17. hammock ◴[] No.45013579[source]
Can anyone share some images for those who don’t have dev tools to view them?
replies(1): >>45018642 #
18. layer8 ◴[] No.45013622{4}[source]
Gray is arguably just another color, it’s not clear why you’d want to avoid it. How is going via red and yellow better than going via gray? Varying hue is often perceived as a larger change than varying saturation or lightness. A path going through several distinct hues is visually less uniform than one going through gray once.
replies(7): >>45013704 #>>45014617 #>>45015125 #>>45016009 #>>45018125 #>>45018860 #>>45024190 #
19. the_af ◴[] No.45013704{5}[source]
Is gray perceived as "just another color" or where all colors go when desaturated? I assumed the latter, which would explain why to avoid it if one isn't playing with saturation.
replies(1): >>45014020 #
20. the_af ◴[] No.45013719{3}[source]
Wow, I never thought about bright light red when thinking of undisplayable colors. It makes a lot of intuitive sense, thanks!
21. the_af ◴[] No.45013739{4}[source]
I don't understand why HN sometimes responds aggressively to an honest, puzzled question. It's as if being wrong (or confused) was a sin here, sometimes.

I thought yours was an honest question that warrants an answer (which thankfully Chris answered).

replies(1): >>45023277 #
22. layer8 ◴[] No.45014020{6}[source]
Think of fashion, of smartphone colors, pen and pencil colors and the like. Gray, white, black, are just color choices among all the available colors. A gray T-shirt isn’t a desaturated colored T-shirt. It’s its own color.
replies(3): >>45014920 #>>45014949 #>>45018273 #
23. FuriouslyAdrift ◴[] No.45014196[source]
We already have CIE LAB as a standard that does the same thing... https://en.wikipedia.org/wiki/CIELAB_color_space

[EDIT] Ahh.. The W3C has already looked at this. https://www.w3.org/Graphics/Color/Workshop/slides/talk/lille...

replies(1): >>45015599 #
24. spoiler ◴[] No.45014341[source]
It's not a bug, its a property of the colour space. Which is partially tied to how the colour is represented (RGB). When doing linear interpolation through the RGB cube (for eg a gradient), you normally pick the shortest path. It just so happens that sometimes that path passes thorough some shade of gray as different colour components are scaled.

Usually you fix it by moving your point through a different colour space. Choice depends on your requirements and mediums you're working with (normally different types of light sources or screens).

I had to write a low level colour interpolation librar for a few interactive art projects, so I dipped a bit into this, but I'm no colour expert

replies(3): >>45014491 #>>45015198 #>>45015527 #
25. ◴[] No.45014491{3}[source]
26. brulard ◴[] No.45014617{5}[source]
Let's say you continuously change wavelength of a laser from blue (~480nm) to red (~630nm), you are going through green, not through gray. If in your use case going through gray makes sense, that's ok, there may be many paths from one color to another.
replies(2): >>45015320 #>>45016520 #
27. the_af ◴[] No.45014920{7}[source]
Oh, I understand what you say. But in color spaces, isn't gray the "sink" towards which desaturated colors shift? This would make it a location to avoid (unless you're purposefully desaturating).
replies(1): >>45015668 #
28. cruffle_duffle ◴[] No.45014949{7}[source]
Color is weird like. Gray is “all the visible spectrum in equal proportions”, which is white… just less white than the whitest thing visible but more white than the darkest (blackest) thing visible.

It’s a “color” because it’s useful to describe such a thing. If you had monitor entirely filled with 50% white you’d call it white. Only by comparing it to something brighter do you call it gray. Brown is the same thing. In a dark room if you looked at a monitor filled with red and green pixels you’d call it orange. Only when you start adding in clues like whites and brighter colors would you call it brown.

Anyway, yes grey is a color. But it is not quite the same as other colors. Other colors occupy only parts of the visible electromagnetic spectrum. Whites are the whole thing.

There is actually several very good technology connections videos about this stuff. Color is very cool!

replies(1): >>45015707 #
29. AnimalMuppet ◴[] No.45015125{5}[source]
It depends on how you think about your spread. If, as someone else said, you're trying to represent a tunable laser going from red to blue, going through gray is completely wrong. That is not what a laser will do, ever. It will always be a fully saturated color.

So, depending on what you're doing, you want different things. You may want to view your color space as an RGB cube, and go through gray. Or you may want to view your color space as something more like HLS or OKLCH, and not go through gray.

30. Sharlin ◴[] No.45015198{3}[source]
I think GP is referring to the difference between "normal" (gamma-encoded) sRGB and linear sRGB. Though it's not logarithmic but a power law. In any case linear interpolation done in non-linear sRGB gives you intermediate colors that are darker than they should (though historically it's been so common in computer graphics that people are accustomed to it).
31. Sharlin ◴[] No.45015320{6}[source]
In general people don't really think of color in terms of the spectral progression (or the hue wheel), and I don't think that most people intuitively expect a gradient between two colors to pass through another "unrelated" primary or secondary color. The point is somewhat moot though, given that such gradients (like yellow to blue or red to green) are very unnatural anyway.
replies(3): >>45017636 #>>45018017 #>>45018195 #
32. nkrisc ◴[] No.45015512[source]
IMO in pretty much all cases if the two colors at the end of your gradient are not already very close, you will always get the best results by manually specifying the colors at one or more steps between the two original colors.

Which brings me to point at the crux of the matter: avoid gradients between two dissimilar colors in the first place.

33. Diggsey ◴[] No.45015527{3}[source]
No, sRGB refers to both a colour space and an encoding of that colour space. The encoding is non-linear to make best use of the 256 levels available per channel, but you were never supposed to interpolate sRGB by linearly interpolating the encoded components: you're supposed to apply the transfer function, perform the linear interpolation at higher precision, and then convert back down into the non-linear encoding.

Failure to do this conversion is what leads to the bad results when interpolating: going from red to green will still go through grey but it should go through a much lighter grey compared to what happens if you get the interpolation wrong.

34. ucarion ◴[] No.45015599[source]
For others, I'm sure parent knows: OKLCH is largely a bugfix for CILEAB. Both try to make a color space where even steps feel evenly spaced to a human. But CIELAB had procedural flaws in its creation.

See slide 19: https://www.w3.org/Graphics/Color/Workshop/slides/talk/lille... -- if you ask CIELAB to make "pure blue" (RGB 0 0 100%) become grayscale, the intermediate colors become purple to the human eye. The entire point of a perceptual color space is that that doesn't happen. OKLCH fixes that.

BTW, credit to Björn Ottosson, who basically side-projected a color space into the web standards and more: https://bottosson.github.io/posts/oklab/ ... folks like him are why we sometimes have nice things!

35. ◴[] No.45015668{8}[source]
36. seba_dos1 ◴[] No.45015707{8}[source]
> Whites are the whole thing.

...with varying definitions of "whole". D65 white is almost blue when compared to A white. It stops being either “all the visible spectrum" or "in equal proportions” pretty quickly once you look closer at it.

37. JKCalhoun ◴[] No.45015813[source]
Interesting. In nature, I suppose I am most aware of a gradient from a saturated azure sky above to a much whiter sky on the horizon. This would seem to be a trivial saturation gradient.

For a spot color (from a gel covering a light) the light diffuses further from the center of the projected light — two spot colors (with different gels) then, next to each other, would give a kind of gradient from one color to the next as you walk a line from the center of one light to the other.

I wonder what the closest analog to this is algorithmically?

I guess where I am going with this is: is there precedent in nature as to how gradients are supposed to work (and therefore an analog which we should try to model) or are we going strictly on how the human eye perceives color and what algorithm we think "looks" right?

38. ghurtado ◴[] No.45016009{5}[source]
> Gray is arguably just another color

Only if you're working with additive color.

With substractive, grey is just a darker (or dimmer) white.

39. JKCalhoun ◴[] No.45016520{6}[source]
Shine a red and a green light near each other on a wall — what does the transition look like?
replies(1): >>45017085 #
40. ZoomZoomZoom ◴[] No.45017085{7}[source]
There's no transition, this is color mixing, or overlay in case of light.
replies(1): >>45017746 #
41. runarberg ◴[] No.45017636{7}[source]
Honestly I suspect this is largely a non issue. I have never made a gradient that goes through more than 2 different color (by some vague measure of different) without adding an additional stop. If I wanted to go through yellow and green to get to blue, I would add a stop at yellow and another at green, and I suspect most developers would do the same.
42. JKCalhoun ◴[] No.45017746{8}[source]
Is that not a transition through the color mixing (or overlay). I'm assuming the light sort of tails off as you leave the area of one color and head to the other (and the other color comes on with more intensity then).

I suppose that's different with light than some analog with pigments? (Two dabs of color set apart, a brush perhaps used to blend them as continuously as is possible.)

replies(1): >>45020778 #
43. gowld ◴[] No.45018017{7}[source]
It's funny and a bit sad because we just went througha decades-long effort to migrate away from jet/rainbow gradients to vik/batlow/bi-hue gradients, and now rainbow is forcing its way back.

https://theconversation.com/how-rainbow-colour-maps-can-dist...

https://www.poynter.org/archive/2013/why-rainbow-colors-aren...

44. itishappy ◴[] No.45018125{5}[source]
It's an ugly color. Saturation makes stuff pop; this is often desirable. This is why I think it's important to have both polar (OKLCH) and rectilinear (Oklab) gradients.
45. itishappy ◴[] No.45018195{7}[source]
I disagree somewhat. Color mixing just isn't particularly intuitive. It's not the most intuitive to get a third hue, but that doesn't justify grey (which has an undefined hue). I do think most people are quite comfortable with the fact that between blue and yellow exists green, but is it a saturated green or a desaturated green? Additive and subtractive color mixing behave very differently here.
46. itishappy ◴[] No.45018273{7}[source]
A grey shirt is a desaturated shirt. You cannot resaturate grey.

I think if you buy a tie-dye shirt or phone case and it comes out half grey, despite it being a valid color, most folks will be disappointed.

replies(1): >>45019549 #
47. itishappy ◴[] No.45018642{3}[source]
https://codepen.io/ItIsHappy/pen/dPYjyaV
48. cubefox ◴[] No.45018860{5}[source]
Let's say neither going through gray nor through two different hues looks particularly great. It's pick your poison.
49. stevage ◴[] No.45018962[source]
Making a gradient from two colours on opposite sides of the spectrum is a bit of a pathological case. There's no obvious answer what it "should" look like, and also no good reason you'd really need to do this. If you're using a gradient as a design element, you'd pick your own midpoints.
50. omnicognate ◴[] No.45019530[source]
Edit: The article was updated. Ignore me.

> you should probably default to interpolating in Oklab instead

The article says as much. Quoting:

> This can be a double edged sword. While some gradients might look smoother, you might also see colors that you've never defined. This is because hue in OKLCH is circular and gradients can take unexpected detours.

> To avoid this, many tools use OKLAB for gradients, which interpolates in a straight line and gives more consistent results.

replies(1): >>45019748 #
51. Dylan16807 ◴[] No.45019549{8}[source]
> A grey shirt is a desaturated shirt. You cannot resaturate grey.

Aren't these in direct conflict? If you can't resaturate it, that implies it's not desaturated.

> I think if you buy a tie-dye shirt or phone case and it comes out half grey, despite it being a valid color, most folks will be disappointed.

And if you buy a forest motif, people will be upset if it's pink. That's just doing a tie-dye wrong, not a rebuke of whether it's a color at all.

replies(1): >>45019869 #
52. jayrhynas ◴[] No.45019748[source]
I was going to point that out too until I realized that the author updated the article based on the parent comment!

https://news.ycombinator.com/item?id=45013291

replies(1): >>45019759 #
53. omnicognate ◴[] No.45019759{3}[source]
Ha! Well spotted.
54. itishappy ◴[] No.45019869{9}[source]
> Aren't these in direct conflict? If you can't resaturate it, that implies it's not desaturated.

Kinda. There's a singularity in the math. The problem is that hue is defined as an angle and saturation is defined as distance from the center, but there's no consistent way to define a direction for the origin. Black and white have the same problem because they're also desaturated.

> And if you buy a forest motif, people will be upset if it's pink. That's just doing a tie-dye wrong, not a rebuke of whether it's a color at all.

I'm not arguing that it's not a color, just that it doesn't belong in all gradients!

replies(1): >>45019958 #
55. Dylan16807 ◴[] No.45019958{10}[source]
Of course it doesn't belong in all gradients. It would only be in gradients that go from near-opposite colors. Or if you mean pure gray it would only be in gradients between exact opposite colors, and there are no good options for such a gradient.
replies(1): >>45020281 #
56. itishappy ◴[] No.45020281{11}[source]
I mention tie-dye because it feels like a quintessential example of a color gradient. I think it's perfectly reasonable to ask for a blue and orange tie-dye shirt and perfectly reasonable to not want grey colors simply because they're on opposite sides. I could see white in between, I could even see black, or I could see purple and red or cyan and yellow. I don't think there's a universally right answer here!
replies(1): >>45020311 #
57. Dylan16807 ◴[] No.45020311{12}[source]
Someone asking for those colors doesn't actually want a gradient with two anchor points. So yes there are many answers but because it's not a quintessential example of a gradient.
replies(1): >>45020746 #
58. itishappy ◴[] No.45020746{13}[source]
> Someone asking for those colors doesn't actually want a gradient with two anchor points.

I thought the same until I googled "blue and orange tie-dye." I'll be honest, more white and black than I expected!

> So yes there are many answers but because it's not a quintessential example of a gradient.

We may have to agree to disagree that tie-dye isn't a quintessential example of a gradient. Would you argue that rainbows aren't either?

replies(1): >>45021043 #
59. cubefox ◴[] No.45020778{9}[source]
Your light thought experiment would produce a color gradient via additive color mixing.

A magenta to green gradient would then go through white rather than grey. A subtractive magenta-green gradient would go through black. Not sure what physical setup would produce the latter gradient. But the standard RGB (or OKLAB) gradient goes through grey rather than white or black. This type of gradient is physically created by dithering: Dithering a gradient from magenta to green, by just using these two base colors, would produce a perceptual grey in the middle. This type of color mixing is otherwise better known as alpha blending.

60. Dylan16807 ◴[] No.45021043{14}[source]
> I thought the same until I googled "blue and orange tie-dye." I'll be honest, more white and black than I expected!

Putting white or black in between adds another anchor point.

And looking more around examples of blue and orange tie dye, most aren't really gradients overall, they have big splotches of solid color with small gaps or overlaps in between, and at least half the time the gaps and overlaps don't even have a gradient inside them.

> We may have to agree to disagree that tie-dye isn't a quintessential example of a gradient. Would you argue that rainbows aren't either?

Hmm. How about this. I would say a rainbow is not a gradient between two colors, and the color space discussion is about a gradient between two colors. The exact border of "quintessential" is not something I really want to spend too much time on.

replies(1): >>45021331 #
61. itishappy ◴[] No.45021331{15}[source]
In my mind a gradient is simply a smooth transition between colors with no universally agreed upon definition. The choice of specific curve through colorspace is rather arbitrary. It seems perfectly reasonable to want to include grey and perfectly reasonable to want to avoid it.
62. shrx ◴[] No.45023277{5}[source]
It was an honest question, thank you.
63. anotheryou ◴[] No.45023600[source]
RGB is just allways worst OKLCH usually pretty, which is all I want from gradients most of the time.

I had claude build me a comparison (not sure why 2x the same HSL one) https://i.imgur.com/uziQibR.png

Also super hard in RGB: https://jsfiddle.net/nhgvzm5p/2/ it's just a 2 color OKLCH gradient:

    oklch(0 0.07 279) 66%,
    oklch(0.98 0.09 276) 99%
replies(2): >>45023618 #>>45023969 #
64. anotheryou ◴[] No.45023618[source]
my biggest problems with OKLCH:

- how to easily add "warmth". you can't just add red+green - no good tools for it (e.g. a nice gradient picker ui that lets me specify if I want to allow running out of bounds of teh color space and clip a few colors at max saturation)

65. chrismorgan ◴[] No.45023969[source]
That gradient looks terrible, very bad colour banding, because you’re starting and ending at points that are way out of gamut, and the technique used to bring it in isn’t smooth. For a gradient like that, you probably want at least five points.

That is the biggest problem with these colour spaces: the edges are unclear, and overflowing them has bad effects.

replies(1): >>45024628 #
66. DemocracyFTW2 ◴[] No.45024190{5}[source]
Gray is arguably not just another color; I don't know about English but in German you have 'bunte' and 'unbunte' colors; 'unbunte' colors are white, black, and the grays in between
67. anotheryou ◴[] No.45024628{3}[source]
you think I can get the same OKLCH style colors but without banding?

if I sample 5 colors and throw them in as rgb?

the 3 color rgb one has very similar banding

68. animal531 ◴[] No.45040825[source]
>During its beta period, Tailwind v4 tried shifting from sRGB to Oklch for gradient interpolation; by release, they’d decided Oklab was a safer default.

I recently implemented both, first I started with OKLab which turned out really well, the gradients you get from it are amazing and the usual color sets (analogous etc.) produce really pleasing sets.

However I quickly ran into the main problem with it, which is that fiddling with its Lightness, Chroma and Hue dials doesn't produce human understandable results. For example sometimes changing L or C induces a color shift, or for some given values changing L only gives midrange values that doesn't go up or down all the way.

I then implemented OKLCH on top of that, which was the way I assumed everyone was doing it. Just have it act as the controller for the human layer, then convert to OKLab for creating gradients etc. The article doesn't really go into it, but having OKLCH as the frontend controller fixes the LCH sliders such that they produce values that make sense to us humans, while still having the superior OKLab setup in the back.