Re: [css-houdini-drafts] [css-typed-om] Inputs for the CSSColorValue constructors (#1014)

> And that's not a good solution. As I said before, the goal of the CSSTypedOM is to represent CSS constructs accurately and faithfully. A class to represent a CSS rgb() function should take the same arguments in its constructor as a rgb() function does. Doing anything else is not solving the goals of the CSSTypedOM. These classes should be focused on modeling CSS syntax first and foremost.
> 
> The design question here isn't "which range of numbers do we take in this one constructor", it's "what's the purpose of this API". It's the second question that should be informing the answer to the first.
> 
> Trying to combine CSS OM with a generic Color class at this point (i.e. without having a well-designed API surface of a generic color class, or even a fully-formed CSSTypedOM API), is a premature optimization that leads to bad design decisions. Those are two very different beasts. Combining them without the big-picture of the best API surface for each is a mistake.

I strongly disagree on several of these points.

The Typed OM needs to reflect CSS, yes. That does *not* mean it needs to be perfect 1:1 direct translation of CSS syntax into JS constructs; I'm explicitly *not* doing that in several spots, and expect to continue not doing that for the future. When possible, I'm simplifying and following canonical JS practices more closely, because sticking closely to CSS would be a net loss for the API; direct translation helps in a theoretical purity sense only, but harms authors in practice.

Directly: my goal with Typed OM is not and never has been to be a 100% reflection of what authors typed into their CSS. It needs to be able to represent equivalent values, but where JS and CSS idioms clash, or where I can make some minor useful changes that faithfully reflect the underlying value but fold away some aspects of the surface syntax, I will do so. This should be, as much as we can make it, a *convenient* API to use for authors; "faithful" is not a goal beyond the minimum that needs to be maintained to make it worthwhile at all.

This precise case is a great example. Currently, `color()` accepts %s and 0-1 numbers, mapping them together; a number of functions accept %s only; and rgb() accepts %s and 0-255 numbers. I've got a few possible ways to represent this:

1. All %s can be given as a `CSS.percent()`, *or* as a JS number. This directly matches `color()`; is a slight expansion (in a reasonable way) for the other color functions; and is a diversion from rgb(), where CSS numbers have a different range and interpretation.

2. All %s can be given as a `CSS.percent()`, *or* as a JS number in everything but rgb(), where JS numbers are instead accepts in the 0-255 range. This maps more closely to rgb()'s CSS syntax, but means that you can't use JS numbers as a generic way to represent % values across the color functions; it works for *everything but rgb()*, which is a different source of confusion.

3. JS numbers are only ever interpreted as `CSS.number()`. color() and rgb() accept them, with their correspondingly different ranges (0-1 and 0-255), but the other color functions can only be interacted with using `CSS.percent()`.

4. JS numbers aren't allowed at all; you *must* pass in a CSSNumericValue to interact with any of the color APIs.

I think #4 is immediately a no-go. The TypedOM already allows raw JS numbers and strings in several places, and translates them into the appropriate TypedOM objects (CSSKeywordValue and CSSUnitValue). Disallowing it here would be inconsistent and author-hostile.

I think #3 has theoretical consistency going for it, and nothing else. Forcing people to write `CSS.percent()` to set a Lab function's saturation, vs just saying `color.s = .5;` like you'd do in any purpose-built color library, seems excessive. Again, this hurts authors and benefits only spec authors, which is a no-go.

#2 kinda works, but it means authors have to remember that they can use JS numbers for %s in all the color functions *except* rgb(), where JS numbers mean something completely different. On the other hand, it means that it's easier to mentally translate back and forth between CSS and Typed OM - you see an `rgb(0 127 255)`, you'll get `CSSUnitValue`s that have 0, 127, and 255 as their value. This is at best a toss-up, imo, and I think the "useful, not faithful" principle leans strongly against it.

#1 is what I went with, because tho it means `CSSRGB` is a less direct translation of the CSS syntax, it gives a more consistent JS API to authors overall - in all the color functions, if you use a plain JS number, it's interpreted as a %. That's easy to learn, and easy to use.

> Adding color manipulation functions to the CSSTypedOM color classes may very well be a nice convenience for authors, it also might make an API surface that's not performing either job well because it's trying to serve two different functions. As I said, I'm not opposed to combining the functionality in principle, but I am very much opposed to starting with the premise that we must do so. And any compromises we make now trying to serve that end are a mistake.

I'm not starting from the premise that we must do so. Many parts of Typed OM will be specialized for CSS and not suitable for generalization; earlier in this thread matrix APIs were mentioned, which is definitely one such case.

I am, instead, affirmatively stating that I think the Typed OM color APIs *are* reasonably suitable as a general-purpose color library for the web, and while we'd make slightly different decisions if we were designing a JS color API from scratch, the differences between our real and ideal library are small enough that it won't be worthwhile trying to make a second color library.

If we tried to make second dedicated color library for the web, either it'll duplicate the large majority of functionality that TypedOM's color types will have, *or* to avoid that duplication we'll have to hobble the TypedOM classes to be very strictly about solely producing CSS values, such that authors will have to do a two-step converting between TypedOM and the JSColor objects.

If someone wants to prove me wrong, and make a Color library proposal that has tons of bells and whistles that we won't want to put into TypedOM, and can get implementor interest behind such a thing, feel free! But I won't be spending my time on it, and in the meantime various APIs on the web want to be able to use something other than strings of CSS text to work with colors, and TypedOM will be here for that.

>  the distinction between color(srgb 0 1 0), #0f0, and rgb(0% 100% 0%) is meaningless for a Color object, but needs to be preserved for the CSS OM.

Not quite. I think it's useful to preserve the distinction between the first and the other two (for some usability and forward-compat reasons), but I don't think the latter two need to be distinguished by the Typed OM. They're definitely not currently preserved; both get represented as a `CSSRGB` in the current spec.

> Nobody is complaining that we have CSSNumericValue in Typed OM and numbers in JS, or CSSImageValue in Typed OM and Image in JS, or CSSResourceValue in Typed OM and URL in JS. I don't see how this is any different.

That first pair is actually *conflated* in the TypedOM; in several places a plain JS number is allowed and auto-converted into a TypedOM value. The rest are *significantly different* from each other, in use-case and desirable API. We definitely wouldn't want to try and combine them.

I don't think colors are the same, as I argue earlier in this message. This is something that varies case-by-case, and I think trying to draw a general principle out will result in a worse API for authors for minor theoretical purity benefits.

-- 
GitHub Notification of comment by tabatkins
Please view or discuss this issue at https://github.com/w3c/css-houdini-drafts/issues/1014#issuecomment-840181927 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 13 May 2021 00:09:29 UTC