brandonaaron / jquery-cssHooks

Collection of cssHooks that work with jQuery 1.4.3+
Other
478 stars 80 forks source link

Color value formatting #22

Open pdokas opened 13 years ago

pdokas commented 13 years ago

Browsers frustratingly deliver all sorts of different results for color properties in CSS.

Webkit returns rgb/a() values no matter what the CSS specifies. red, #f00, they all come back as rgb(255, 0, 0). I can't see any native way around this. Even worse, webkit gets opacity values off by a frustratingly miniscule value. E.g. what should be rgba(0, 0, 0, 0.3) is reported as rgba(0, 0, 0, 0.296875). Firefox reports it correctly as 0.3.

jQuery itself suffers the same problems and a fix has been long deemed out of scope. I've begun a normalization library that can break down any valid format into an [r,g,b,a] tuple but it'd be nice to not coerce users CSS color values into rgb/a. For instance, all my test cases have expected values in rgb/a format even though I'm explicitly setting values in other formats.

Any ideas on how to work around these inconsistencies? Especially those absurd opacity values?

burin commented 13 years ago

For setters, I'll usually just pass the values as-is to let the browser handle it, i.e. hex, rgb, etc, without too much manipulation. Mostly because the browser could probably do it better than I could anyway ;)

Normalizing the returned values is a pain and the format you expect back is a matter of preference I think. If I set a color as red in the CSS and later ask for it via cssHooks, it would be nice if I could know that the rgb(255, 0, 0) is actually red. But at that point, it depends on what I'm going to do with that returned value.

Am I checking it as a human? In that case I would like the more "human" format of red or even #ff0000.

Am I performing some calculation on it and animating it to a darker shade? In this case I would prefer rgb so I can just calculate numbers and set the value appropriately (maybe).

I think a good approach may be to normalize the return values to rgb/a(), and trim or round to the nearest hundredth? Then provide the option of human readable return values as a separate cssHook? I really don't know what the majority of people would use this for, but I'm making the assumption that it'll be mainly calculations or manipulating values that someone would use this for, where readability may not even be that important.

You've built a demo using the colors, did you need to know what format it was returned as?

I've wondered about the same question for transitionTimingFunction return values as well.

pdokas commented 13 years ago

Good points, I need to consider it a bit more before writing more. But briefly to answer your question, I didn't need to know the colors in any format other than rgb/a() but for the test cases I cheated by saying that the values returned were expected in rgba() format. I still feel a little uncertain about lines like this:

equals( jQuery("#test").css("color", "hsl(75%, 50%, 25%)").css("color"), "rgb(63, 31, 95)", "sets the color properly" );

due to how unclear the translation from hsl → rgb is under the hood.

burin commented 13 years ago

Yeah, I felt kinda weird about how we were testing too. I was going to go down the route of testing for one of many possible correct values, e.g. rgb or the hsl equivalent, but that started feeling odd too.

louisremi commented 13 years ago

Developers expect $(elem).css('color') to return a computed style, always in the same format, because that's what happens for every other properties. So normalizing everything to rgb/a should be fine.

pdokas commented 13 years ago

I wonder if the deal with the very slightly off floating point values has to do with the details of floating point arithmetic. If that's what's happening, wouldn't it occur in every browser?

louisremi commented 13 years ago

0.1 + 0.2 == 0.30000000000000004 The difference should not be that big. Could you provide a test case?

pdokas commented 13 years ago

tests/index.html's color section illustrates it in Webkit browsers.

6 sets the color properly, expected: "rgba(0, 0, 0, 0.3)" result: "rgba(0, 0, 0, 0.296875)", diff: "rgba(0, 0, 0, 0.3)" 0.296875)" 7 sets the color properly, expected: "rgba(0, 255, 0, 0.5)" result: "rgba(0, 255, 0, 0.496094)", diff: "rgba(0, 255, 0, 0.5)" 0.496094)"

The differences there are much smaller than the canonical 0.1+0.2 example and FF4 doesn't exhibit the issue so I doubt it's floating point math that's the culprit.

Results above from Chrome OS X 12.0.733.0 dev, but these results have been the case since I first committed the color framework last October.