Find closest match for a given color?
Hi, I just had this idea pop into my mind but I'm not sure how I could approach this problem, and before I go spend a few hours, days... or weeks researching this I wanted to ask around for some pointers. Probably some tool already exists as well but I don't know how to even search for it, although I'm still interested in learning how to build it myself as practice.
So, the goal is: provided a valid CSS color, determine the closest it gets to other two color values. For example, say I have this value
#eebebe
, and I want to find out which of these other two values it approaches the most; #e5c890
or #ef9f76
?10 Replies
That's the general idea, later it can be extended to include other color formats (rgb, hsl, ...) and multiple options to compare to.
I dont have an immediate answer yet, but you also have to question "closest to what?"
Just the hex value itself (as a number), a specific rgb-channel, hue or saturation or lightness?
I'd recommend starting with HSL, cause it most closely mimics our experience of colors. But yeah, what Mark said, you need to specify a distance function, there's not one simple answer to "closest"
I think I would use distance in 3D space, but do it with the HSL values rather than RGB.
If we let out x axis be saturation, y be lightness, and z be hue, we can just plug the numbers in and be done with it.
But this approach will result in a hue of
359
and a hue of 0
being maximally distant, whereas realistically they're right next to eachother.
To solve this we could mess around with 3D polar coordinates or fancy math but a simple solution is to just have it max out at 180 and anything above counts backwards (eg 185 -> 175, 200 -> 160, etc);
There's probably a simple math expression which will do this but I'm not the guy to figure it out. You could also have this scale from 0-180 to 0-100 for consistent boundary sizes on all three dimensions, but that's down to what works best in experiments/tests.
Then it's a case of using 3D distance formula
I'd recommend experimenting with various different color spaces to see which works best for you. Maybe using RGB as XYZ works best - maybe CMYK (probably not but you get the idea)@markboots. @jochemm Right, I thought about how to define closest but couldn't really come up with something. Based on a few examples I remember from the sass documentation, I would probably start with things like lightness, etc. But I'm absolutely clueless about it.
This looks great! I'll have to take some time later to take a look at it more properly
Thanks for the suggestions, any ideas are more than welcome
Also, to make things even more challenging, a scss option is preferred Though I'm not sure if this is even possible 😄
if you know the colors at build time you can do it in SASS, but if not I don't think it's possible (unless there's CSS magic it compiles to that can do it?)
And if you know the colors at build time... well, compute it ahead of time and then use the result instead of a calculation
Mmm well, one thing where I thought this could be useful is when selecting themes on a website. For instance being able to select not only light/dark themes but also accent colors. So I guess there's a case for JavaScript right there, but I would also like to have that as a sass function. The question is how to calculate this
how to calculate it is a very complex question that no one seems to be able to agree on, lol.
If you look at the contrast checkers online right now, they use a formula created by WCAG (I think they made it anyway, don't quote me on that) that basically no one actually likes.
CSS is looking to add
color-contrast()
where you can give it a base color, and then a list of other colors, and it'll take the highest contrast one.
It's hit a roadblock because of all the arguing over what algorithm to use to calculate the highest contrast.I see, so this is an even more fundamental issue with colors? maybe I should just drop it... which is why I wanted to ask first 😂
what algorithm to useLet the vendors decide the default, but require that several be available and selected by an optional first argument to
color-contrast()
.
easy!