New alternatives to HSL and HSV that better match color perception
bottosson.github.io
bottosson.github.io
My biggest complaint about perceptual colour spaces has been that they make working with colours near gamut boundaries really hard. For example, with #ff0 (yellow) in LCH, you can’t tweak any of the three parameters in either direction without going out of gamut (play with it at https://css.land/lch/ to get a vague idea of what I mean, though it doesn’t handle going out of gamut well). Yet such colours have plenty of practical value, and it’s a shame that many things eschew them because they’ve drunk too much perceptual uniformity kool-aid. Colour palettes often just don’t have any decent yellows at all. (To be sure, you do need to use such colours with care, but to remove them altogether is distressing.) For colour pickers especially, perceptual colour spaces have just been no good, because of their weird shapes and because you’re more likely to want to pick interesting colours nearer gamut bounds.
So I’m really glad to see this, because it’s just what I’ve been grumbling about the absence of. Thank you Björn, I continue to enjoy your work!
The only time I think it's really necessary is making color palettes for data visualizations.
Otherwise, if you're e.g. designing a color palette for a webpage, you probably do want some variation in perceived brightness. Heck, I could think of plenty of valid data visualization scenarios where you'd want this.
As someone who deals with color pickers a lot, it is just nice to have multiple options. Sometimes I just wanna punch in a hex number, sometimes I want a SV+H square, sometimes HS+V works better, etc.
I see value in having a color picker that allows you to pick colors without changing brightness. E.g. imagine you let users pick colors that should work on a background that you designed. giving them a color wheel that stays perceptually at the same brightness has value here, because no matter which color they choose the brightness-contrast on your background will work.
Compare it to waiting for a compiler: Sure, you can use the time off to stretch and take a sip of tea but there would be no serious opposition to compilers working at double speed tomorrow. It's simply better to not have to wait (all else being equal). But it's something you accepted and you deal with it, so wait you will.
The current color pickers are an annoyance that we have lived with since, well, always, but an annoyance nonetheless. Happy to adopt these pickers if they gain adoption. OKHSL and OKHSV look spiffy.
Hint to people trying to reproduce this: start by clicking the input button at the top and typing #ff0
I agree, this can be awkward. I like using perceptual spaces because they are self-evidently a “neater” starting point for colour work than something artificially distorted like HSL or (horror!) RGB, but it’s important to recognise that they offer an incremental improvement and don’t magically solve all problems. In particular, producing a useful and/or aesthetically pleasing result still isn’t necessarily as simple as varying one axis in isolation, because you can quickly fall outside the available gamut that way.
As a practical example of this, I recently needed a scheme for a variation of syntax highlighting in a structured document. My requirements were:
1. around 10 clearly distinct hues
2. all colours maintaining good contrast with a white background
3. no colour appearing too bright relative to the near-black unhighlighted text
4. all colours at a similar level of perceived lightness to avoid unintentional bias or emphasis.
My starting point was to choose evenly spaced hues within a perceptually uniform colour space, pick a medium-to-low value and look for maximum chroma in each case. This wasn’t a bad start, but it still needed significant practical adjustments like increasing the value for colours around the yellow/green area and dropping a hue entirely so I could space others around the blue/purple area more widely. Otherwise, however perceptually uniform the scheme might theoretically have been, in practice it would have ended up with the yellow/green area colours looking washed out and the blue/purple ones not distinctive enough under some realistic viewing conditions.
The blobs attempt to spread out in a perceptual color space. You can add more blobs with + and remove them by clicking on their pie slices or on a blob directly.
Code is based on an older perceptual color space: https://github.com/neolefty/hexerals/tree/master/src/color
A 'target' was a set of densities we would calibrate the machine to reach for a particular RGB value. 0,0,0 = 3.4D and 255,255,255 = .04D (for transparent material).
One group in the company insisted on a simple cube root density drop off, based on a reading of the L* formula. However, when the customer printed a large gradient with it, they rejected it. It looked like the 'linear' gradient on your site. However, when we put the test pattern (a small 4x8") pattern on the light board, it looked perfect.
So we tried an experiment, we printed 3 gradients on a full sized sheet, (50 inchesx50 inches), one with a 'clear' background, one with a 50% grey and one with a black background.
I was in the field, so I found a gradient that looked good, but did a bunch of study when I got back, I felt that some of the newer CIE models at the time did take into account background.
Tldr; I was curious is your page and those models included into its gradient calculation what the surround is? Also, it would be interesting to display these with an adjustable background. (dark, light, grey), or with colors.
Tailwind.ink
They really, really aren't good for picking useful colours. People don't keep using HSV because they are idiots, and have remained idiots for the last thirty years, they are using HSV because it lets you pick usable colours.
The article goes through a lot of deep, thoughtful work only to arrive at an end result of this: https://bottosson.github.io/img/colorpicker/okhsl_circle.png
A circle of different muds and a little bit of hot pink.
This is a good thing: it teaches you the shape of the gamut, and gets you working with colors consistently.
#FFFF0O does not have “plenty of practical value”. It is a very niche tool with an extremely small range of uses, and should be avoided almost all of the time.
> For colour pickers especially, perceptual colour spaces have just been no good,
Just the opposite: for color pickers especially, using anything else makes it much much harder to get good results.
https://bottosson.github.io/misc/colorpicker/
OKHSL works a lot better than the alternatives. It's really nice!
OKHSV doesn't seem as good, and neither do the other new ones.
HSV (and Okhsv) more closely match my painterly intuition.
I'm not sure what the solution is. A purely algorithmic color picker probably isn't the answer because it's not just our color perception that matters, but also the way colors are formed in our environment (which is what gives us so many browns).
The solution would probably be pallettes that let you pick arbitrary axes to move through color space.
1 - https://youtu.be/wh4aWZRtTwU
2 - According to Neil Harbisson, the guy with the color-sensing antenna, in-person conversation, but you can also verify with photoshop.
That's why the original commenter was having difficulty finding brown, because we do not necessarily associate it with a dark orange or flesh color with de-saturated red or orange.
But if we were trying to paint something like dark teal water. The brain would immediately go straight to blues/greens.
These "color categories" that we form in our brains can be different in every culture or language. That is issue with what was suggested.
Not sure if you’re replying to the right person? I didn’t say anything about finding brown being difficult.
I don't even know what that would mean for it to be difficult to find a colour?
> because you do not necessarily associate it with a dark orange
That’s what brown is - a dark orange. The same way navy is a dark blue. But nobody makes videos claiming that navy is a weird colour because it’s actually dark blue.
(Not that I deny the link exists; but when I look at e.g. an orange next to a dark brown tree branch, I don't see them as versions of the same colour in the way I do with, say, a lime and a dark green leaf. That's not a great example but hopefully you see what I'm getting at.)
My theory is that many people have a mental model of colors that maps roughly to the hue and value in HSV, so for example terms like "dark orange" is a value followed by a hue. Now suppose you understand brown as a "dark beige", that's suddenly confusing because beige introduces saturation and you cannot map beige back to orange without thinking about saturation.
I think my point is brown is dark beige, and beige is light brown. Neither is canonical. Is orange canonical? Maybe it's high frequency red? Or low frequency yellow? That's what Newton thought! It's all relative.
Emergence of names of colors in languages usually goes black, white, red, yellow, grue, then blue forks from blue, brown, orange, then "specialty" colors like pink, purple, indigo, teal. It's the only partially saturated shade that gets a name before its saturated variant (orange). Being able to name things brown is more important than orange, so that mental link is weaker. Hence why we have "dark blue" but brown is not "dark orange." (though I think some languages call it "dark red"? I'm a bit hazy on that detail)
30 degrees hue, 50% value, 100% saturated, looks exactly brown to me?
> brown is not "dark orange."
I think it is. In fact, take my 30 degrees hue, 50% value, 100% saturated, then gradually increase the value and see where you get to!
This isn't meant as a trick question or anything -- if I'm getting at anything specific, it's that maybe part of the reason the orange-brown link seems more obvious to you than to me is that when you think of a central example of brown, you think of something brighter (and thus more obviously orange) than I do.
Hmm not really. But we're not going to resolve what seems like a subjective question!
You can load common name sets (e.g. X11 color names, CSS names, Munsell names, Behr) and they map their values into your color pickers.
This works well especially with paint pigments as every manufacturer has their exotic names that they hype for that year. "Oh, 'Ice Blue' is really just a slightly blueish white."
RGB is likewise for fixed wavelength three-color lights/filters, and CMYK is for prints. I think it's the same situation as units of measurements in aviation[1] being all over the places; the measurements are tied to specific devices, principles and usages of them.
1: Altitude in feet measured by pressure altimeters, distances measured in nautical miles defined as one minute of latitude, fuel in pounds and dimensions in inches, but never altitudes in miles or distances in feet, except for runway lengths which is always feet or meters.
This doesn't work, because "https://en.wikipedia.org/wiki/Magenta is an extra-spectral color, meaning that it is not a hue associated with monochromatic visible light."
Hue is the angle on the color wheel. Which somewhat translates to wavelength if you ignore the fact that we see chords of high blue + low red as the colors we give names like purple, indigo, violet, and magenta.
Saturation is how intense the color is. Lower the saturation and it turns grey, or pastel. We have a few special names here; "pink" is a low-saturation red, for instance.
Value/lightness how dark/light a color is. Lower the value on that "pink" and you might get something you'd label "brick red": it's darker, it's still definitely reddish, but it's not the most intense red you can get while still being kinda dark.
Saturation collapses as you go to the extremes of value/lightness, it's just pitch black at one end and pure white light at the other.
Yes, and since we use color models in development primarily to model RGB light as displayed by machines, these are less than useful indeed.
For anyone looking for a neat color model that is novel and is a bit more intuitive (arguably), look up HCG.
HCG
https://github.com/helixd2s/hcv-colorHCG = Human Chorionic Gonadotropin, which will dominate your search results.
https://developer.mozilla.org/en-US/docs/Web/API/Location/re...
UI examples: https://twitter.com/kdrag0n/status/1427822417313898498 (using ZCAM, not Oklab or the new Oklab/Okhsv) / https://www.figma.com/file/ZeqPgO1RgA6eg8TMm7r8Ae/kdrag0n's-...
Full generated palettes: https://twitter.com/kdrag0n/status/1431100523894083589 / https://www.figma.com/file/mZ6VxvsC2yN4zD9rDR4S2I/kdrag0n's-...
Yes, it's very easy to create colors outside the sRGB gamut boundaries, and you have to compromise something in order to bring them back in gamut. However, when working with colors programmatically, I'd still recommend considering perceptually-uniform color spaces instead of HSL/HSV-style models that are made to simplify interactive color picking.
But I think for color pickers, there are cases where "constant lightness" is not the most important constraint. For instance, you might really mean "the most saturated primary in each hue" and then - you may want the most saturated colors to appear on a line (saturated red, saturated blue, etc.). A constant lightness constraint makes these appear in a really unpredictable pattern.
In less saturated colors, this constraint is very useful and feels right, but I think at the extremes it may reduce usability.
It's like fitting maximum saturation into a palette that's more linear. From canary yellow you don't HAVE a lot of room to go to pure white: there's very little difference. And it translates to very little linear space between the points. So nice.
I have an office which has huge windows facing (mostly) away from the sun so I have bright light from either clouds or blue sky. Reproductions of renaissance paintings and photographs on ‘bright white’ paper look great, but at home the color temps are in the high 2000s usually and I need coated papers for the images to be compelling.
So I am always thinking about what environment a print is in and would love to have more tools to tune up the appearance.
To some extent one learns that something that looks like this in one environment will look like that in that environment.
If your desk doesn't move, you could always have a cron job that loads different color profiles based on time of day and possibly weather if you really want to make a project of it.
[1] https://bottosson.github.io/img/colorpicker/hsv-picker.png
On these slightly squished and stretched ones… I think converting back to OKlab is the better idea. You can just turn the polar stuff into Cartesian directly too, but it will be distorted.
I don’t think this is a problem with the color space, I think the JS source wasn’t designed to be used by humans.
The figures directly under the sentence ‘Here is the sRGB gamut plotted for set of hues…’ have real utility which the author may have missed. They clearly show that the peak saturation value has a different lightness value for each hue. For example, a peak saturated yellow is required to be brighter than a peak saturated blue.
Explaining this to designers can be a real grind. These figures would make the task a lot easier.
I really wish for a color picker that did not normalize the color space (as in the figures that follow).
https://austingwalters.com/chromatags/
In almost every computer vision class I took, switching to the LAB color space and rerunning algorithms also still always led to improvement.
The real trick in my mind is trying to do this via sensors and / or hardware.
IIRC author of the TFA has retweeted some shader implementation of OKlab for color interpolation.