@donnie @rgadellaa

Hello, I've seen your posts about automatic CSS contrast color using relative color syntax.

I arrived at my own solution, here is something that is more useful with arbitrary magic numbers which seemed to be alright to my eyes:

https://codepen.io/vkcube/pen/yyYEXKL

Worth noting as you can see that `min(1, max(0, foo))` part isn't needed as numbers are between 0 and 1 and rounded up anyways.

CSS only contrast color

...

Yeah, I've been using the XYZ method recently and I've been modifying it also. Namely, the rounding isn't really necessary since we can go past the 0 & 1 and still produces black and white. Also, the .18 used is meant to relate to the WCAG expectations and how they calculate acceptable contrast.

@donnie

Without any rounding it would be possible to produce grey values, for example in your original demo using clamp function it sometimes does that, when it is on the edge of contrast.
And with the existence of HDR I wouldn't trust putting values over maximum anywhere.

Yes 0.18 threshold more closely aligns with WCAG but their way for calculating contrast is weird anyways and it doesn't matter really in the end.

Do you have an example that produces grey?
@donnie
RGB 139 107 206
Yeah, I'm not using that approach any longer. I'm using the XYZ approach instead found later in the post. And that doesn't produce gray with that value.
@donnie
Yes, as that second example rounds the color to a discrete value instead of just clamping it, and color spaces are different too so the point at which it changes from black to white is different.
In the first example that change is not discrete as it is just multiplied by a "big number" and then clamped, so it looks like you discretize the component to 0 or 255 for most values but in fact anything between can occur.
In my demo you can see the same function but it uses round instead, which doesn't have that artefact.
Hope that helps.
Yeah, I'm saying you don't need to round.You can just overflow.
@donnie You can't just overflow exactly for the reason mentioned above.
Overflow works like a clamp, if you have
clamp(0, 0.5, 1) it will produce 0.5
0.5 is the same as a component of grey in the above screenshot.
And you want something like round(0.5) so that no values between 0 or 1 occur, so it either black or white.
You can try to mimic the behaviour of round by subtracting the value and multiplying it by a very large number, but that is just an awful way of mimicking round that can produce wrong results anyways.
Take clamp(0, (y - 0.5) * -1000, 1) as an example, if y has a value 0.4999 the resulting value will be between 0 and 1, and so will be slightly grayish.
That is what you do in the first example of yours, but instead of 0.5 it is 128 there, it is just a way of mimicking round. Such hack can work if you increase that multiplicator by a lot, as floating point numbers and colors don't have infinite precision in them and some numbers are rounded to the nearest representable one, but it is better to just use round function and save yourself from possible troubles.

Overflow does not work like clamp. Clamp doesn't overflow, that's the main feature of clamp.

calc((.18 - y) * 10) is overflowing. There's no clamping in this function. It causes the result to be larger than 1 or under 0.

@donnie It will be clamped while calculating what color to actually display on the screen.
when you write something like
rgb(1000 1000 1000)
components are clamped between 0 and 255 implicitly for you, so you see white and not some impossible color which your device can't display.
> we can go past the 0 & 1 and still produces black and white.
^ here you describe clamping between 0 and 1.
I don't define "going past" as clamping.