color-api icon indicating copy to clipboard operation
color-api copied to clipboard

[Color.parse()] What is the space of accepted CSS color strings?

Open LeaVerou opened this issue 1 year ago • 3 comments

What happens if authors try to parse things like

  1. "oklch(50% 10% var(--hue))
  2. "oklch(50% 10% calc(0 + 20))
  3. "color-mix(in oklab, currentColor, red)"

The Color API is not Typed OM, so the internal representation of the color needs to be concrete numbers. However, it can still accept color strings that are not just a color space function with specific coords, and resolve them to numbers.

Each of these examples brings up different questions around this:

  1. Should the API provide some way to specify what the context is, so that variables and things like currentColor or system colors are resolved? (an object literal, or even a DOM element)
  2. Should the API follow calculations in calc() if they can be resolved?
  3. Should color functions like color-mix() be accepted if they can be resolved?

And when a color is valid CSS, but not something the Color API can handle, what should happen? We throw an error or do something else?

LeaVerou avatar Mar 20 '24 19:03 LeaVerou

Ideally it accepts the full range of CSS syntax, so you can feed it a CSS value and get a color out.

This means I think it should accept calc() and friends, at least.

But if given something that relies on information it doesn't have access to (non-absolute dimensions, currentcolor, variables), it should either fail to parse (probably the most reasonable) or resolve based on initial values, like MQ does (but this doesn't guarantee predictable evaluation, since, for example, the initial value of color depends on the page's color scheme, the initial value of 1em depends on the user's default font size, etc).

And when a color is valid CSS, but not something the Color API can handle, what should happen? We throw an error or do something else?

Throw, just like a straight-up invalid value. It's essentially the same error path. We can throw a different error message, perhaps - either they're both SyntaxErrors, but with different messages, or invalid syntax is a syntax error, and valid-but-unhandleable syntax is, uh, a DataError? https://webidl.spec.whatwg.org/#dfn-error-names-table

tabatkins avatar Mar 20 '24 20:03 tabatkins

But if given something that relies on information it doesn't have access to (non-absolute dimensions, currentcolor, variables), it should either fail to parse (probably the most reasonable) or resolve based on initial values, like MQ does (but this doesn't guarantee predictable evaluation, since, for example, the initial value of color depends on the page's color scheme, the initial value of 1em depends on the user's default font size, etc).

I agree that parse failure is more useful here than initial values which as you say are context dependent.

By the above, do you mean "variables are not available" or "if that variable is not available"?

svgeesus avatar Mar 20 '24 22:03 svgeesus

I agree that throwing is better than resolving with initial values, which is rarely what you want.

I think it would be illuminating to concretely enumerate the cases in which we don’t have enough information to resolve the color. So far we have mentioned:

  1. CSS variables
  2. currentColor
  3. system colors
  4. non-absolute dimensions (mainly via division between them)

Is this an exhaustive list or are there others too?

I would love to explore ways to have our cake and eat it too, i.e. provide the necessary context (possibly not in v1). Ideally in a way that does not exclude JS runtimes from implementing this API, which is going to be tricky (if that was not a consideration, we could simply provide a DOM element reference and poof, all problems are gone). This would make it so much more useful for e.g. use cases like code editors, code playgrounds etc. (which currently fail miserably at showing a color preview in these cases). In some ways it seems similar to the URL constructor, which accepts either an absolute URL, or a relative URL and a base. But to figure out the best API shape for that, we need an exhaustive list of these cases.

LeaVerou avatar Mar 21 '24 03:03 LeaVerou