150 comments

[ 2.2 ms ] story [ 213 ms ] thread
It would be convenient if gradient calculations would be hinted by the color space used to define the start/end colors.
Because Hue is a degree, you can walk either clockwise or counter-clockwise. That is why in the Javascript widget (the one to select midpoints and color spaces), HSL v.s. Lab v.s. HCL acted quite differently. You probably also need a tweak for that in the "Gradient Generator" widget too.
> Because Hue is a degree

A bit nitpicky but: Hue is an angle, degree is it's unit.

Like the width of a football field is a length, meter is it's unit.

Otherwise, good point!

For Americans: it's football (the one with your hands) and measured in yards
American football is called football because you play it on your feet, as opposed to on a horse.
This doesn't seem to be a very well-supported theory.

https://en.wikipedia.org/wiki/Football#Etymology

> It is widely assumed that the word "football" (or the phrase "foot ball") refers to the action of the foot kicking a ball. There is an alternative explanation, which is that football originally referred to a variety of games in medieval Europe, which were played on foot. There is no conclusive evidence for either explanation.

https://en.wikipedia.org/wiki/Football_(word)

> In some cases, the word has been applied to games which involved carrying a ball and specifically banned kicking. For example, the English writer William Hone, writing in 1825 or 1826, quotes the social commentator Sir Frederick Morton Eden, regarding a game – which Hone refers to as "Foot-Ball" – played in the parish of Scone, Perthshire [in which kicking the ball was prohibited]

> Conversely, in 1363, King Edward III of England issued a proclamation banning "...handball, football, or hockey; coursing and cock-fighting, or other such idle games", suggesting that "football" was in fact being differentiated from games that involved other parts of the body.

It seems unlikely that King Edward III meant to ban games that involved walking on your hands, or perhaps brachiating.

> It seems unlikely that King Edward III meant to ban games that involved walking on your hands, or perhaps brachiating.

But this argument assumes that the etymology of 'handball' must be the same as 'football'. Football could be called that because you play it on foot, and handball could simultaneously be called that because you use your hand to strike the ball. There's no contradiction there.

No, all the argument assumes is that handball (and hockey) are played on foot. That would be enough for them to be called "football" under the theory that football is a class of games that aren't played on horseback.
> That would be enough for them to be called "football" under the theory that football is a class of games that aren't played on horseback.

If you followed this argument you'd be confused why we have basketball when netball already covers games that involve a net and a ball. Not all games are named by the same person with the same naming ideas.

Shouldn't it pick the way with the shortest distance? Otherwise you'd get an entire rainbow between green and yellow! (Or is it already doing that but which distance is shorter depends on the color space used?)
In GIMP, there are beside clockwise and counter-clockwise two more options, near and far, which map to cw or ccw depending on start- and end-hue.
I really, really like Mr. Comeau's "Me" avatar. In fact, his whole site is quite beautiful and pleasing.
I agree, most sites are very aggressive with popups and modals, that having a small pleasant avatar peak out at you is a nice change.
No, it's still bad. For example, it hijacks the space bar. You're spacing/pgdwning like normal when it pops out, then it hijacks the space to open up a nag modal. It was terrible when it was Clippy, it's terrible when it's a Bob the Builder avatar. Comeau's website never sparks joy in me because I'm always wondering what the next bullshit will be (was this the one which for a while was doing sparkles after the mouse?).
I seriously wonder if a person exists that likes being bothered when they're trying to read something? If that's not the case, and in fact nobody likes this, why anyone would think that this was a good idea?
I personally don't find this particular popup bothering. I can continue to read the page without interruption. I also understand that they want me to subscribe or whatever so I know when their next article is up.
Can you give examples of sites that do spark joy for you? Whenever I encounter hate for certain design decisions online I like to know the alternative I should strive to follow instead.
The person who complained, Gwern, has their own site at https://www.gwern.net/. It’s another article-focused site, so the designs should be mostly comparable. However, Gwern’s articles are much longer, so their design choices might reflect that.
For me Page Down does not trigger the click on the "Sure" button of the small popup. That would be a really weird thing. Space does, because the element is focused automatically (which is kinda bad imo).
Heh, I didn't like it, I never like when something pops up and animates on a website after a timer while you're reading, I never like when something overlays any part left or right of the text you're trying to read, and I never like when you have to close something to continue distraction free. This thing is exactly an aggressive modal popup.
When it showed up, I gasped and jerked my hands away from the keyboard. It felt like a jump scare.
It honestly scared me too when I saw it pop out of the side of the screen. I've viewed this blog before and had the same reaction. It's cute, but I'm sure you and I aren't alone.
I like how the little w and 人 make a big W in negative space.
Every once in a while you come across something on the internet that makes you stop and go "whoa, that is cool". This is one of those for me.
The gradient generator Josh introduces here is pretty nice [0]! And the HSL vs RGB theory is also pretty interesting. I'll give this generator a try next time I want one.

But my favorite gradient generator at the moment (most pleasant gradients IMO) is still [1].

[0] https://www.joshwcomeau.com/gradient-generator/

[1] https://mycolor.space/gradient

I like [0] better as it gives you faster feedback. My only complain is that the web-app background is a png (should be gradients).
As a (web/app) developer, I'd really wish I had any sort of talent do beautiful things, this person clearly has a sense of aesthetics that I don't, while I know that practice would make it better, I just don't feel that I'd get there.

Congrats to the author for such a cool product!

It's always possible to convince yourself that you couldn't do something.

But everyone that ever did achieve it only did so with practice.

Red pill: truely accept that design is very important, make the hard effort to improve your aesthetic work over time to improve your personal taste, listen to graphic designers and learn their taste from them. Become the master of both aesthetics and engineering, reap the significant rewards as one of the few that can navigate the compromise between the disciplines. The cost is that the world slowly becomes terrifyingly ugly, because you have to opened your eyes to hideous monstrous graph everywhere; even a simple sign on a road can make you physically ill. You are surrounded by evil, currently your mind is just closed to it. One friend of mine struggles to go to shopping, because the screeching noise of barbaric design hurts their psyche. You already struggle against the cesspit of bad engineering that surrounds you everyday: take the red pill and more than double your suffering.

Blue pill: keep ignorant of graphic design, enjoy mocking the trivial and meaningless exploits of designers, laugh at their talk of the energy or feelings of a font (idolising even just one minute part of a single character), remain happy in your ignorance. The cost is that you will always feel something is missing in your life and work. There is a worthwhile struggle for meaning in the dark arts, you will miss out on the pleasure of creating form from the void.

There are profound joys of creating something beautiful. Engineering is easier but more restricted because the definition of engineering is compromising to meet limitations: design has fewer limits and they are mostly created by your society within your own mind. A aesthetic sense will get you widespread respect, because people can appreciate it. Great engineering is a lonely vice that is usually not even appreciated by your fellow engineers. As an engineer you can subversively affect graphic design and you often have massive control over aesthetics. Comparatively, graphic designers are chained artists that often bleed away their soul slowly until they become corporate zombies with minds of mush.

There is also a third place to go where you respect good design, designers, and their work. You learn enough about it to enjoy it, but maybe not enough to do it well yourself. You accept that because you invest time in other things.

You can enjoy music without being a professional musician.

For all the hate Apple gets, they definitely took the red pill when it comes to UI/UX.
Some pieces are great, but others are infuriating, like the fact that I can't disable pointer or scroll wheel acceleration without installing 3rd party software.

At least they let me invert the scroll wheel so that its behavior matches everything else in the world.

> At least they let me invert the scroll wheel so that its behavior matches everything else in the world.

Everything else in the world has largely inverted, too :P

My day job is "artist" and the "everything looks terrible forever" scenario depicted here is rather exaggerated, IMHO. I can enjoy something pretty when I see it but I can also let ugly things slide by without worrying about it.
> As an engineer you can subversively affect graphic design and you often have massive control over aesthetics.

For most of my career I was a hybrid designer/developer. There's definitely a dialog between them, and engineering enables and constrains some elements of the esthetics, but in general I would say it works the other direction more often than not.

That's why when I read about von Tiesenhausen’s Law of Engineering Design, it really rang true for me: "If you want to have a maximum effect on the design of a new engineering system, learn to draw. Engineers always wind up designing the vehicle to look like the initial artist’s concept."

We're just talking about esthetics, rather than functionality or purpose or process, which are much more of a give-and-take.

This is why I eventually just moved straight over to design: so much of product development is path-dependent, and designers exert a ton of leverage just by creating documents upstream of engineers.

I can recommend The Non-Designer's Design Book, by Robin Williams, as a great way to dip a toe into the world of design. It won't make you a designer, but it will help you fake it a bit when you don't have one. I found the suggestions surprisingly effective in my own work.
Since this is posted by you, Josh.. is the date in the article inaccurate (should the year be 2022?) or did you just decided to push to HN on the one year anniversary? (Title might benefit from the year)
Personally, when it's so recent (like within last year or three) I don't really care if the title is missing the year on HN. It becomes more useful when it's clearly a dated (i.e. maybe incorrect or no longer relevant) article.
Well, I reckon it's a typo rather than an old article.. I can't believe that a joshwcomeau.com article would only have 2000 visits in a year, and most of us type/write/speak the wrong year in early January :D
Love the article. Small UX gripe: it took me a while to figure out how to use the gradient sliders. The box at the top looks like a handle, and I was trying to interact with that. But it looks like I have to click the bar to move the box, but there is no visual indicator that the bar itself is a point of interaction other than a cursor change (which is really subtle).
It looks like a note has been added describing how to use the control.

But obviously this is admitting that this control isn't intuitive enough.

Yeah I see that now. Having different parts be focusable versus clickable isn't a great choice imo.
Yeah, I would have considered adding ball with the same styling as the other drag handles at the tip, and remove the ball at the center pivot point. Mimicking the affordance elsewhere, behavior can stay the same as is.
I didn't even notice they were interactive.
Always psyched to see a post from josh.

Really insightful deep dives into a very misunderstood technology, presented with a fun, lighthearted writing style that I find myself trying to emulate in my own technical writing.

Is there a primer to colour spaces for a beginner?
For those who didn't realize, there's a ton of interactive sliders on that page.

(it didn't dawn on me until I accidentally bumped a slider and realized the page was interactive)

its in the site's defense there is a note that says

> How to use: Click and drag within the color gradient, or focus the color square and use the left/right arrow keys.

I enjoyed this one very much. Thanks for creating such high quality content.
Nice. Things ending up being gray is a common problem on the web.

I took a deep dive into gradients some time ago. Not CSS but custom calculations that evened out things like brightness, luminescence, contrast and so on. My key takeaway was that my preferred way of doing gradients was to use similar hues and also play around with the saturation of the colors. One does not need complimentary colors to get that gradient feel.

This discussion thread already has an unusual number of posts specifically praising the author by name. It's very weird and unusual on HN. But he's just a really popular guy?
Why are there two popovers in a row when paging through the page?
Some uBlock filters to block them:

    ##[class*="ToastySubscribe" i]
    ##[class*="FloatingSidebar" i]
Just before Christmas I got an urge to add a dither filter to my JS canvas library. The past few weeks have certainly been a very intense adventure through a very deep rabbit hole involving color spaces, color distances and discovering how to generate a best-fit reduced palette of colors and then dither it (hello, blue noise!)

I finally managed to complete the work last week and I'm quite happy with the results. Using the library people can set the colors of graphical objects or gradients using any CSS color space string (RGB, HSL, HWB, LAB, LCH) and the color should render as expected. The reduce-noise filter uses LAB internally to calculate color distances, but in the end I compromised and used euler distances for the algorithm rather than one of the more modern algorithms.

Work is still on a branch in the library[1] but I'm hoping to merge it into the main code in the next week or so (after testing across devices/screens/etc).

Aside: Safari has gone ahead and introduced support for HWB, LAB and LCH color strings in CSS. Sadly, they're not recognised by Safari's canvas engine (yet). Also, their HSL and HWB gradients seem to be the same as the RGB gradients; their LAB/LCH gradients seem to dodge the dreaded Gray Zone.

[1] - https://github.com/KaliedaRik/Scrawl-canvas/tree/dec-21-dith...

I highly recommend reading Human color vision / Peter K. Kaiser and Robert M. Boynton. It's a great read if you've gone down the color vision rabbit hole as it has nearly every single topic in regards to human color perception. The biggest surprise for me was that there's still a bit of debate about how exactly neurons in the eye are wired together to produce the color signals that go to the brain.
I read an amazing article once that described the representations of color at different processing levels in the human brain. For example, the 3 types of rods in the retina sense R/B/Y intensity, but at some point it is transformed into a different 3d representation with a R-G axis, a B-Y axis, and a greyscale intensity axis. There was some implication that this is information-theoretically optimal in some sense for representing images sampled from the natural world. Anyone know what I'm talking about?

The book you mention seems to cover similar ground: http://www.yorku.ca/eye/toc.htm

It seems the article you're talking about is the opponent color process, which here's some great articles about it: https://www.handprint.com/HP/WCL/color2.html https://blog.asmartbear.com/color-wheels.html

I had some fun modeling the color space in 3d on codepen: https://codepen.io/torleifw/pen/jOwjPxp

(or a more boring slider option here: https://codepen.io/torleifw/pen/OJgdyPJ)

One of latest papers I've read recommended using a matrix to transform color spaces, which i've also done a codepen for.

Interestingly the opponent process mirrors the LAB color space, which is soon going to be available in Safari. This is pretty cool and can enable developers to color coordinate easier.

I'm going to give the webpage you linked a good read, looks very interesting.

It was your first link, thank you! What a great site.
Firefox just released version 96 today and it comes with HWB() as well.
I am very interested in the "best-fit reduced palette of colors" approach, but then to create mosaics. Say you have lots tiles/beads/bricks/marbles whatever in a handful of colors (and not covering the entire color space, but say three shades of blue, brown and bright pink) how can you represent a full color image as accurately as possible using only that very limited palette (and in a fairly limited resolution, as placing 10k tiles is not fun).

I have had some success manually using Photoshop to generate a reduced color space image to only 5 distinct colors (probably optimally chosen by the algorithm) and then remapping those 5 colors to 5 the 5 colors I actually have. There must be better ways

The approach I finally settled on was: check each pixel in the image to build up a list of (RGB) most popular colors and to memoize new colors into LAB values; sort the color data into commonest first; then build up the required palette from commonest downwards, excluding colors that were too close to each other based on a distance measure. Then you can go back to the original image and measure its color against the palette colors, from which you can determine the 3 palette colors closest to it. From that you can give each pixel a propensity range of the likelihood of it taking on one of those 3 colors and run it against a randomly generated value, or a set of preset values for blue noise.
Following up on my comment (for posterity). I've now released the new code to my library. Includes a demo of using the full range of CSS color strings to set color in the canvas[1], and also a demo of my reducePalette (with dithering) filter[2] - I've no idea if the filter's output is 'Good Enough' for Image Engineering work, but I'm happy with the results.

[1] - https://scrawl-v8.rikweb.org.uk/demo/canvas-059.html

[2] - https://scrawl-v8.rikweb.org.uk/demo/filters-027.html

What is the LAB color space that is provided in the tool but not discussed in the article? For all the hubbub about HSL and HCL, LAB looks the best to me.
It’s a color space designed to be perceptually uniform. So as you blend through colors the saturation appears to stay the same. Check some of the reds and greens in the other color spaces and see how they get really saturated.

https://en.m.wikipedia.org/wiki/CIELAB_color_space

(comment deleted)
(comment deleted)
(comment deleted)
This is another cool tool: https://leonardocolor.io/

You can compare monochromatic scales between various color space interpolations and order them by contrast (great for accessibility work). Lab is from the 70s, the newest one there is CIECAM2 from the 2000s, also looking most natural to my eyes.

LAB is one of the better ways to to start with perceptually uniform spacing of the colors. Also if the path through the color space avoids A and B being near 0, then the gray dead zone problem that this talks about goes away.

There are multiple ways to look at differences in LAB space unfortunately. Each one more mathematically complex, yet more perceptually accurate: http://zschuessler.github.io/DeltaE/learn/

For a ton of useful equations and calculators: http://www.brucelindbloom.com/index.html

HCL is also perceptually uniform and easier to interpret and predict what any given change is going to do.
As the article says, the core problem is CSS interpolates in RGB colorspace. CSS Color 4 seems to have adapted a color space parameter for interpolation in its drafts. See discussion here: https://github.com/w3c/csswg-drafts/issues/5833
(comment deleted)
This also addresses an issue when you transition from black to transparent to emulate a shadow, and end up with a "cliff" where the gradient abruptly changes. You can see this in the tool when you transition from black to white with LRGB. Any of the other color spaces avoid it. Very cool!
This article seems to give RGB a bad rap but I think it makes the most sense for gradients. I wouldn't want a yellow to blue gradient to cycle through a (partial) rainbow of colors. But I also wouldn't really ever choose to make a pure yellow to pure blue gradient. Most pleasing gradients you see in the wild use colors that are more similar to begin with, so it's a bit of a strawman. It's really just about carefully choosing your start and end (and optionally intermediate) colors.
I agree that hue rotation makes for some weird gradients. Linear RGB is an acceptable color space for gradients, because gamma correction is accounted for. But performing a linear interpolation in sRGB or the like leads to a linear gradient which appears to ramp steeply from one color stop to the next. However, if you compare Linear RGB with CIELAB then you'll notice the same thing, the CIELAB gradients look smoother as linear movement through the color space more closely mirrors linear movement through our human perceptual system.
LAB is good but not great. If you do a gradient from pure green to pure blue, you'll see some purples and other color oddities in the mix.
(comment deleted)
I think this is for those cases where you'd like to create a striking gradient but RBG falls kind of flat. For a lot of us it wouldn't be apparent why that is, just disappointing. This tool remedies that by giving you a vibrant and striking gradient regardless of what you feed it.

I do agree about the rainbow of colours though. As someone who understands how RGB works and has worked with colour a lot for decades, this tool is kind of un-intuitive at a glance. That's probably alright though. I can continue hand-crafting gradients because I know how to. Most people using a generator likely don't know how to.

Otherwise it's also a great exercise in learning about and then teaching these things, which Josh is great at.

This comment sheds a little bit of insight here: https://news.ycombinator.com/item?id=29895421. The original article chose to always go "clockwise" around the color wheel, picking up lots of different colors and giving the appearance of a rainbow, instead of taking the shorter, more naturalistic route of blending through teal & green.
I agree re HSL, HCL, and HSV, however the LAB gradients do tend to look nicer than RGB ones, without passing through random other hues in the middle.
I know nothing about gradients, but wouldn't dithering provide the best results? That way you're truly mixing those two colours and not going through completely different colours based on some arbitrary numerical representation of the colours.
Only if you want a dithered look, which oftentimes you don't.
I guess it depends on the size of your pixels. But as long as your pixels are small enough, I think this is the only way to have a gradient go straight from one colour to an opposite colour without going through either grey or a multitude of other colours.
RGB mixing doesn't seem very natural though. In physical reality you do end up with that rainbow, a random example mixing paints https://www.justpaint.org/wp-content/uploads/2015/11/JP26.pd...
Subtractive colour mixing in pigments is way more complex than the light on a monitor. Each pigment has its own distribution of absorbed and reflected wavelengths so mixing any two colours is mostly try and see in practice.
Ultimately it’s about perceptual color versus actual light. A red/blue gradient should be almost entirely transparent (ahem, grey if that’s what you’re getting from lack of data in RGB), but it too will “cycle through” and produce colors that don’t exist between red and blue. You’re expressing preference for a particular substitution approach that makes sense to you, which is perfectly fine as a preference but that’s all it is.

Edit: or it will produce the full spectrum between red and blue but that’s obviously not your preference.

It's actually also about the interpolation path as well. Creating gradients in 3 component colorspaces is totally analogous to creating interpolation splines in 3d euclidean coordinates.

The fixed points define only the end points of the splines. The space between the end points corresponds to the color value along the interpolation curve.

If we are in an rgb cube, we notice the "gray zone" is along the diagonal from (0,0,0 to 1,1,1).

If we take two colors opposite of this diagonal (say color_a={r=0.5, g=0.5, b=0.0} and color_b = {0.5,0.5,1 0} we notice if we linearly interpolate we go through gray (0.5,0.5,0.5) in the middle.

If in stead we move along a curved path that avoids the diagonal, trying to maintain the saturation we get a much nicer result.

This "curved path of roughly equal saturation" is easier to define in a colorspace such as HSV where the saturation is one of the spatial coordinates.

But as I always say, there is no theoretically "correct" way to define a gradient, only techniques optimized for some specific use case.

My personal opinion is that generally linear interpolation in RGB results in the least satisfying gradients but that is just my _taste_.

I was expecting the article to eventually explain how to make a gradient between two colors, without passing neither anything looking like "third hue" nor gray.

This is perhaps not possible in theory, but just adjusting the gradient curve so that the effect is minimized should be possible.