Re: [css-houdini-drafts] [css-typed-om] Do we need separate classes per color space? (#1034)

> In terms of Typed OM, they are all CSSNumericValue, aren't they?

Yeah, I meant CSS types. (Sorry, the terminology gets confusing since there's not a 1:1 relationship there.)

> That's a strawman, I wasn't suggesting color.coords[0] to be the only way to get a coordinate, but color.coords to get all coords as an array is useful.
> In terms of getting coordinates by name, there can be convenience syntax, e.g. color.get("r"). 

Its not a strawman, it's literally what you suggested, according to your sample IDL. ^_^ If you meant to imply that there'd *also* be some sort of maplike interface to interact with the channels by name, it didn't come thru in your message, sorry.

> But right now, if authors want to get the list of coords generically, the only way is to manually check all possible getters, which is ...not great DX.

I'm not sure I understand the concern here. What sort of code is being written that wants to interact with arbitrary color objects and manipulate their channels without any knowledge of what the color space is? I don't think there's any math you can meaningfully perform using an arbitrary list of channels, which might even be a mix of percentage and angle values.

Could you elaborate?

> Also note that this design does not allow for named getters for custom color spaces even if they are named in the @color-profile rule, since we are moving away from exotic objects in the Web Platform. Whereas a maplike design would allow for named getters for any supported color space via .get() and .set(), and you could even allow setting/getting coords of different color spaces (e.g. color.get("lch.l") without the overhead of converting to that color space and back.

Yeah, a maplike interface giving a way to address the coords of a `color()` function by name (when there's an appropriate @color-profile providing names for them) definitely makes sense.

I could see us potentially moving that method to the superclass, I suppose. I think it'd need a little more justification.

> a) It's currently very difficult to find out the color space of a color:

Ah, that's reasonable to fix. I already do this for CSSNumericValue - the operation subclasses are separate subclasses, but *also* expose their corresponding function name in a property, to make it easier to respond to. I can see moving ".colorspace" to the superclass as a readonly property, and making it writable in `CSSColor`.

I just filed #1036 to remind me to take care of this.

(Maybe we should do this for the transform subclasses too...)

> d) It privileges the color functions over color() (see also my point above about named getters and custom color spaces)

I don't think it does - the color() function is inherently more arbitrary and less well-defined in its author-exposed interface, because it has to be generic over all possible color space definitions.

*That said*, you're right that CSSColor is somewhat anti-privileged - it should really be using indexed properties, rather than a separate `.channels` property. That's my bad; I was just converting the old/weird design I needed for the earlier fallback ability down to a single variant, and what I wrote was the most straightforward way to do it. I've filed #1037 to fix this.

> c) It makes it harder for authors to polyfill Typed OM for future color functions since they cannot create objects that have a custom [[Class]] property.

In general, the Typed OM isn't currently being designed to be author-extensible. You can't add new units, etc. either. Nobody seemed to like my efforts to design an author-extensible set of color classes back in Color 4, either. :(

That said, there's definitely room to improve here. I think color functions definitely are a good excuse to be author-extensible. I wonder if we can get away with something quite simple, actually - I filed #1038 to explore this topic.

> b) It makes it very clunky to make manipulations of colors without changing a color's color space:
>
> This should really be one line, and is one line in literally every color manipulation library out there.

I explored this in my earlier attempt in Color 4, and thought that implicitly invoking a bunch of colorspace conversions wouldn't be a great idea. And since this *is* a CSS API, which color function you "really" are is important to preserve.

> Also, converting to an arbitrary color space is really clunky too, as we can see from the example above.

Ooh, that's fair. If I fix #1036 as I want, then we can change the conversion method to a generic `.to()` that can spit out any of the color subclasses. I've added a comment along those lines.

If we do that, then your code collapses down to:

```js
let space = color.colorspace;
color = color.to("lch");
color.l.value *= 1.2;
color = color.to(space);
```

which seems straightforward and simple while maintaining the important invariants.

Is this sort of "temporarily switch to another colorspace for modification, then switch back" a common thing in your experience? If so, we can make it easier - say:

```js
color.modifyIn("lch", ({l})=>{return {l:l*1.2}});
```

That is, specify what space you're going to do the modifications in, then give a callback function that takes the color in that destination space, and returns an object with the properties you wanted to modify. (Unspecified props are left alone.) It then converts back to its original color space.

I'd want at least a little evidence that this is something common enough to be worth the additional API surface area, tho.

-- 
GitHub Notification of comment by tabatkins
Please view or discuss this issue at https://github.com/w3c/css-houdini-drafts/issues/1034#issuecomment-840648641 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 15:43:38 UTC