design-tokens / community-group

This is the official DTCG repository for the design tokens specification.
https://tr.designtokens.org
Other
1.56k stars 63 forks source link

Legacy color #137

Open o-t-w opened 2 years ago

o-t-w commented 2 years ago

From the part of the spec about color types: “Represents a 24bit RGB or 24+8bit RGBA color in the sRGB color space. The $type property MUST be set to the string color. The value MUST be a string containing a hex triplet/quartet including the preceding # character. To support other color spaces, such as HSL, export tools SHOULD convert color tokens to the equivalent value as needed.”

Chrome is currently working in implementing LCH, LAB, OKLCH and OKLAB color. Safari already supports them. Although support is currently rarer among design tools it still seems sad and backwards-looking to standardise and require a legacy color format.

It is impossible to transform a hex color into a modern color. It is overwhelmingly likely that the modern color formats will become ubiquitous on the web within the next year or two. I'm sure design tools will quickly follow along.

My suggestion would be to standardize on OKLCH already and have design tools that don't yet support modern color transform the color into hex.

I'm already using LAB and LCH on a large web application with hex fallbacks. Standardizing on hex would make design tokens unusable for me.

romainmenke commented 2 years ago

The only format that makes sense to me is something like this :

{
  "colorSpace": "sRGB",
  "channels": [0.1, 0.1, 0.1],
  "alpha": 1.0
}
{
  "colorSpace": "lab",
  "channels": [0.1, 0.1, 0.1],
  "alpha": 1.0
}

The different representations of a color space (hsl for rgb, lch for lab, ...) are less important in a transfer format like design tokens.

sebfriedrich commented 2 years ago

Fully agree @o-t-w , I don't use wide gamut color but have my thoughts sorted on how I would want to have it.

For the ones who aren't convinced here: What Chrome and other browsers implement there right now dates back 90 years from now to color theory research about human perception. Also design systems are not meant to cover a subset of what CSS can help one to build, it is the other way around. It is also worth noting, that a design system shall help manage media breaks more reliability than without such a system in place. Delegating color conversion, which shall be assumed lossy by default, to a random tool at sort of runtime is accepting that applying color via tokens will have different and unforseeable deviations.

CieLCh or similar might be a good start for thinking. Ultimately I would hope for the ability to describe any custom color space by an 3x3 conversion matrix and for better usability hard code the most common ones as named presets to use out-of-the-box.

The work of Bruce Lindbloom might be a good read to get into the math of the topic: http://www.brucelindbloom.com/

NateBaldwinDesign commented 2 years ago

I agree that there should be more flexibility built-in. Considering tokens are an interchange format I would not necessarily expect them to house transformations. But as a way to express "design decisions", it seems backwards or outdated to not support a method for defining decisions as decisions are made. In other words, I as a designer should be able to specify a color like

{
  colorSpace: 'CAM16',
  channels: [76, 100, -56],
  alpha: 1
}

Then it's a matter of tools being able to support a color space or not. However, looking at a bit more likely scenario, we can see how a fallback may be necessary for non-24bit sRGB colors, like with DCI-P3/Display-P3:

{
  colorSpace: 'Display-P3,
  channels: [1, 0.5, 0],
  alpha: 1,
  fallback: "#FF8800'
}

At which point, forcing the fallback value to meet the earlier requirement makes sense.

kaelig commented 2 years ago

tl;dr – IMHO the proposed solution (in the Second Editors' Draft) satisfies most of today's needs – later on, we can work on getting a commitment from the entire toolchain to support more color spaces.


Some personal views / notes / insights (hope this helps understand how the spec was written):

  1. While I agree with the points made in this discussion, please be mindful of current toolchain capabilities.
  2. In our quest to write an acceptable "v1" of the spec, we reached out to folks who work on the CSS Color Module specification, and their willingness to see progress from design tools and browsers was palpable.
  3. IMHO it's too early for the DTCG to push for toolchain-wide changes.
  4. Eventually, I'd love for the DTCG to be in a position to influence the entire toolchain!
romainmenke commented 2 years ago

While I agree with the points made in this discussion, please be mindful of current toolchain capabilities.

IMHO it's too early for the DTCG to push for toolchain-wide changes.

This I do not fully understand. Storing colors in a format that supports wide gamut color spaces does not require tools to actually adopt wide gamut color spaces.

Every design tool can keep using sRGB (or no color space as some do). The only reason to chose non-hex is so that the design token file format doesn't require a spec change later.

It could be part of the current specification to limit this to the sRGB color space to ease adoption.

Choosing hex color notation will make it considerably harder to do this later.

#808080 is equivalent to :

{
  "colorSpace": "sRGB",
  "channels": [128, 128, 128],
  "alpha": 1.0
}

The only difference between these two is that the latter is compatible with future additions (color spaces).

A variable number of channels is also very handy for print applications.

NateBaldwinDesign commented 2 years ago

I also don't quite understand nor agree. Hex/sRGB is a fine fallback for legacy or small gamut support, and can simply be a required field of the token. Display-p3 is already supported by Safari, and used in all retina displays. Design tokens capture design data that align with intent. Intent, as a designer, is not always to define the lowest common web-friendly denominator. Considering the spec already supports fallback notions (an array for fontFamily), this decision seems a bit off base.

My position on this is not that the tool chain should support these formats. They should, but it's not the design token spec's purpose to influence that. Tokens are codification of design decisions, I can't repeat that enough. Some people choose fonts that may fail to load on the browser (so fallbacks are recommended). Similarly some people choose colors tailored for wide gamut displays or based on a specific device-independent color space because of relationships between parameters in a perceptually uniform space.

nesquarx commented 2 years ago

I would also prefer a more future-proof spec that can default/fallback to hex today while allowing for other color spaces/processes to be used tomorrow.

That is what CSS itself is doing in its latest color spec. The move from v1 which is a trendsetter to the v2 is always chasing the industry ad hoc. Hence a little bit of foresight goes a long way at least for the skeleton.

On Wed, 15 Jun, 2022, 8:15 pm Nate Baldwin, @.***> wrote:

I also don't quite understand nor agree. Hex/sRGB is a fine fallback for legacy or small gamut support, and can simply be a required field of the token. Display-p3 is already supported by Safari, and used in all retina displays. Design tokens capture design data that align with intent. Intent, as a designer, is not always to define the lowest common web-friendly denominator. Considering the spec already supports fallback notions (an array for fontFamily), this decision seems a bit off base.

My position on this is not that the tool chain should support these formats. They should, but it's not the design token spec's purpose to influence that. Tokens are codification of design decisions, I can't repeat that enough. Some people choose fonts that may fail to load on the browser (so fallbacks are recommended). Similarly some people choose colors tailored for wide gamut displays or based on a specific device-independent color space because of relationships between parameters in a perceptually uniform space.

— Reply to this email directly, view it on GitHub https://github.com/design-tokens/community-group/issues/137#issuecomment-1156567482, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEKS36HQILX4ZZ2SE44BGZDVPHUB5ANCNFSM5YYUJBRA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

danvpeterson commented 2 years ago

Very much agreed on hoping for support for colors beyond hex values, this is the primary thing that jumped out to me as dangerous when reading the newest proposal. I already use LCH wherever I can in our system's documentation, even though it means more work for me because Figma doesn't support it yet. But it makes it much easier to control perceptual color contrast across a palette, make adjustments to colors while keeping them in the same family, and "lightness" actually means something unlike others where a yellow and a blue with the same lightness or brightness value are so obviously different. Not to mention that it gives us access to so many more colors.

Having to set these in hex is incredibly limiting. We can pretty easily convert from a larger color space to a smaller one, but once it's moved into the smaller space you can't get those additional colors back. Limiting this to hex and sRGB only means that tools that use a larger space are going to necessarily have their colors altered when exporting into a token. And whichever format we go with in the token format can be converted to whatever format is needed by the tools that use them, without them having to actually support that larger color space in the tool. So shouldn't we try to go with a less limiting structure here so those of us that care to can use something that is easier to understand, supports a wider gamut (that can be restricted where necessary during conversion), and provides additional benefits like easier setup for perceptual color contrast?

marcedwards commented 2 years ago

The different representations of a color space (hsl for rgb, lch for lab, ...) are less important in a transfer format like design tokens.

I wholeheartedly agree with this. RGB floats with support for popular colour spaces (sRGB, Display P3) makes a lot of sense as a base requirement. HSB, LCH, OKLAB etc are nice to have, but with the correct precision and colour space, those conversions can always be done at display time, and support for them may be better served by the design tool or colour picker.

HEX is very limited in terms of precision, and rounding errors can be a significant issue when doing conversions. The future is floats!

c1rrus commented 2 years ago

Really interesting points. The syntax & permitted values for color tokens certainly seems to be the most controversial part of this spec! Some of the concerns raised here feel similar to the ones in issue #79.

I must confess my knowledge of the theory and terminology around colors is a bit limited compared to some of the posters here. In case it helps others, I've found this article about "Improving Color on the Web" on the Webkit blog useful as it has a handy "Definitions" section that explains things quite well IMHO. (If you know of other good learning resources on this stuff, please do share some links here!)

Based on my (limited) knowledge of this topic the main concern being raised here is that the current draft spec restricts colors to:

Safari, soon Chrome and perhaps other browsers, platforms and tools support wider gamuts (i.e. more colors that don't exist in the sRGB space) and/or higher color depths (the precision with which colors within a given color space can be specified). Design systems wanting to use such wide gamut and/or higher depth colors therefore cannot accurately represent them using the DTCG format.

The syntax for color values proposed by @romainmenke could resolve these issues because:

Questions to y'all:

  1. Is it possible to do a lossy conversion from a higher color depth to a lower one?
  2. Is it possible to do a lossless conversion from one color space to another for colors where their gamuts overlap?
    • I'm assuming if a color in space A does not exist in space B's gamut, the conversion would necessarily be lossy. Right?

Assuming the answer to 1. is "yes", then any tools that only support 8bits per channel could simply do the lossy conversion from the token's "raw" floating point value. Depending on their needs, this could be done at the point at which they load a tokens file or at the point at which the value is displayed in the UI.

Going the other way around is fine too. A tool that can only generate 8 bit per channel colors can easily write out those values as floating point numbers. Such tools are just a bit limited in terms of the range of values they can produce.

The use-case that requires some further thought would be a tool that can import, manipulate and then export token files. Ideally any tokens in the original file that were imported, not modified and then included in the exported file would be perfectly preserved. However, if the import process inluded a lossy conversion, then the corresponding exported token would no longer be the same. I think that's a broader topic as it applies to other kinds of tokens too. For example dimension tokens with rem values. If they were to travel through a tool that internally only supports px values, there's the same kind of challenge. I think I'll therefore open a separate Github issue for this specific topic.

However, aside from that "preserving tokens when travelling through a tool" issue, I see no problem with adopting an array of floating point numbers instead of a hex string. As others have pointed out, this would not impose any obligation on tools to internally support higher depth colors. It therefore shouldn't be a blocker to existing design tools (or indeed any kind of tool) adopting the DTCG format.

If the answer to my 2nd question above is also "yes", then the same might be true for supporting additional color spaces beyond sRGB. Let's imagine the spec supported the Display P3 color space which, if I'm not mistaken, has a wider gamut than sRGB. If someone's specified a color token using Display P3 and a tool that internally only supports sRGB uses that token, then there are 2 possibilities:

The latter doesn't strike me as any different to a tool doing a lossy conversion from a higher color depth to a lower color depth. A nice to have might be to display a warning message to the user to inform them that the color they see in the tool's UI is an approximation of the actual color specified by the design token. But, I think that's quite acceptable.

Again, going the other way is fine too. Any color tokens generated within the tool, which are therefore necessarily confined to the sRGB color space, can be exported to the DTCG format without issue. Just because the spec can represent more colors than the tool, doesn't mean the tool needs to be able to generate all of those possible colors.

It seems supporting the sRGB space is a no brainer as that seems to be the de-facto standard one most current design tools support. It's also what all browsers support. I presume the same is true for native apps on various OSes (but please correct me if that's not the case).

The question therefore becomes, if we were to go down this route with the spec, which other color spaces should we support?

Bear in mind that every tool that supports the DTCG format would be expected to at least be able to convert from all of the specced color spaces to whatever it uses internally. So, the more spaces we require in the spec, the more complexity there might be for implementors.

Question: Is there a color space that has a gamut wide enough to encompass all other color spaces? If so - and assuming you can convert in gamut colors losslessly between spaces - then would it not suffice to only add that?

Btw, @NateBaldwinDesign, if the spec required tools to be able to convert incoming tokens to whatever (lesser) color space they support internally, wouldn't an explicit fallback color value as you've suggested above be redundant? Or, are there reasons why authors might want to specify one themselves rather than relying on automated conversions?

c1rrus commented 2 years ago

Another thing: While I do like @romainmenke's proposed syntax for color token values, it doesn't have to be mutually exclusive with the current spec draft's hex triplet or quartet string syntax. We could theoretically permit both. For example:

{
  "color-token-1": {
    "$type": "color",
    "$value": "#ff7700"
    // new rule: When using hex string, sRGB color space is assumed
  },
  "color-token-2": {
    "$type": "color",
    "$value": {
      "colorSpace": "sRGB",
      "channels": [1, 0.5, 0],
      "alpha": 1
    }
  }
}

In this example, both tokens have the exact same color value, just expressed in the different syntaxes. This would add a little bit of complexity to parsers as they'd need to add some logic along the lines of:

if (tokenType === "color") {
  if (typeof tokenValue === "string") {
    // it must be a hex triplet or quartet
    // (and therefore color space is sRGB)
    // ...
  }
  else if (typeof tokenValue === "object") {
    // it must be the object style
    // ...
  }
  else {
    throw new Exception("Invalid color token value");
  }
}

IF we decided that this was acceptable, then that might afford us some flexibility about when the format needs to support higher color depths and/or additional color spaces:

  1. We continue as is meaning that v1 of the spec only supports the hex strings (and is thus limited to sRGB and 8bits per channel). Later versions introduce the object syntax as an alternative way of expressing color values, including colors that use higher depths and other color spaces.
  2. We introduce both syntaxes right now, so v1 of the spec has them.
    1. For v1 we could restrict ourselves to only the sRGB space to keep things a bit simpler for implementors (in which case, perhaps we don't need the colorSpace property right now. That could be introduced in later spec versions when we add support for more color spaces. In that case, when that property is absence, parsers must assume the sRGB color space)
    2. OR, we go all the way and support multiple color spaces in v1

Personally, I'm leaning towards Option 1. or 2.1. I think adding the object style syntax sooner rather than later might be a good thing (and if we decided to do that, we might also want to consider ditching the hex strings altogether and making it the only syntax we use). While I'm totally sold on adding support for more color spaces eventually, I don't think their use in UI design is widespread enough today to make it a necessity for the v1 spec.

Bear in mind that $extensions could serve as an escape hatch for teams needing them sooner. You could, for example, do something along the lines of:

{
  "color-token": {
    "$value": "#ff0000", // sRGB 8bit-per-channel fallback color
    "$type": "color",
    "$extensions": {
      "com.example.originalColor": {
        "colorSpace": "displayP3",
        "channels": [1,0,0],
        "alpha": 1
      }
    }
  }
}

Btw, I know it's taking the DTCG quite a long time to get to a v1 spec. However, that doesn't necessarily mean subsequent versions will take as long. Especially, if they're mostly adding features. So, starting with just sRGB colors now, doesn't mean it has to be a really long time before support for other color spaces is added.

Also, if the v1 spec only supported sRGB teams wanting to use

romainmenke commented 2 years ago

@c1rrus Thank you for these insights!

Is it not better to start with a data format that can support larger color spaces but limit this to srgb in v1?

That would create a much easier upgrade path.


{
  "color-token-1": {
    "$type": "color",
    "$value": "#ff7700"
    // new rule: When using hex string, sRGB color space is assumed
  },
  "color-token-2": {
    "$type": "color",
    "$value": {
      "colorSpace": "sRGB",
      "channels": [1, 0.5, 0],
      "alpha": 1
    }
  }
}

This feels like a very slippery sloop. It seems to confuse "property color" with "type color".

A color property in a program might take one of more possible types for it's value but a color type should be unambiguous.

If type ambiguity is introduced the spec also needs to have a way to define type aliases.

The example above hints at these types :

It also makes implementations in typesafe languages much more difficult.


In my opinion this favours short term convenience while introducing long term complexity. One of the benefits of creating a brand new spec is that we can avoid these things and choose the best possible format from the start.

romainmenke commented 2 years ago

Is it possible to do a lossy conversion from a higher color depth to a lower one?

Yes, this is possible and mostly trivial.

One of the effects of a lower color depth can be banding in gradients.

Is it possible to do a lossless conversion from one color space to another for colors where their gamuts overlap? I'm assuming if a color in space A does not exist in space B's gamut, the conversion would necessarily be lossy. Right?

This is possible and css-wg is working on non normative sections detailing how you might convert out of gamut colors.

https://drafts.csswg.org/css-color-4/#gamut-mapping

marcedwards commented 2 years ago
  • sRGB color space (or is that color profile?)

Essentially the same thing. A color profile usually refers to the file that describes a color space.

Safari, soon Chrome and perhaps other browsers, platforms and tools support wider gamuts (i.e. more colors that don't exist in the sRGB space) and/or higher color depths (the precision with which colors within a given color space can be specified). Design systems wanting to use such wide gamut and/or higher depth colors therefore cannot accurately represent them using the DTCG format.

It’s complicated. Support for wide gamut images has been pretty good across the board on the web for ages, but support for wide gamut colors in CSS is newer and not as well supported. It’s absolutely the future though, and a new spec now should take it into consideration. The great news is that it’s not really wide gamut support we’re discussing, it’s just for the spec to be color space aware. If you’re taking colors seriously, you have to be aware of the color space they’re in.

For native apps, wide gamut support for colors has existed on iOS, macOS, and Android for many, many years.

The syntax for color values proposed by @romainmenke could resolve these issues because:

  • The floating point numbers for each channel offer a much higher color depth than the 8bits afforded by the hex format the spec currently specifies

Yep, floats are good idea. If only one format is supported, it should be floats. If supporting HEX can also be done, that’s great.

  • Explicitly stating the color space lets folks use different color spaces. Though, I'd imagine the spec would need to define a finite set of color spaces that can be used in order to enable interoprability.

A finite set of spaces would be totally fine. If no color space is specified, sRGB should be assumed (I think this should be explicitly stated in the spec).

Essential:

Bonus points:

  1. Is it possible to do a lossy conversion from a higher color depth to a lower one?

It’s possible to do lossy conversions between color space and color depths.

  1. Is it possible to do a lossless conversion from one color space to another for colors where their gamuts overlap?

There’s almost always a loss in precision, but if the color depth is enough and if the space you’re converting to is contained inside the color space you’re converting from, it’ll be fine.

  • I'm assuming if a color in space A does not exist in space B's gamut, the conversion would necessarily be lossy. Right?

That will typically result in colors being clipped/clamped. It would mean a color outside the destination color space will look different (often duller).

Assuming the answer to 1. is "yes", then any tools that only support 8bits per channel could simply do the lossy conversion from the token's "raw" floating point value. Depending on their needs, this could be done at the point at which they load a tokens file or at the point at which the value is displayed in the UI.

Yep, definitely. FWIW, color depth conversions are super easy. Color space conversions are non-trivial, and a library will often be needed.

The use-case that requires some further thought would be a tool that can import, manipulate and then export token files. Ideally any tokens in the original file that were imported, not modified and then included in the exported file would be perfectly preserved. However, if the import process inluded a lossy conversion, then the corresponding exported token would no longer be the same. I think that's a broader topic as it applies to other kinds of tokens too. For example dimension tokens with rem values. If they were to travel through a tool that internally only supports px values, there's the same kind of challenge. I think I'll therefore open a separate Github issue for this specific topic.

I think your assumptions are correct and imported colors could be clipped or have rounding errors. That’s on the tool though — if the spec defines a color space and colors are floats, best practices are being covered.

The question therefore becomes, if we were to go down this route with the spec, which other color spaces should we support?

Please see my list above. :) It’s a pretty non-controversial list!

Question: Is there a color space that has a gamut wide enough to encompass all other color spaces? If so - and assuming you can convert in gamut colors losslessly between spaces - then would it not suffice to only add that?

There’s a few answers to this. Rec.2020 is pretty huge, and that will cover quite a lot of future advancements. ACES is way bigger again. sRGB Extended allows for values beyond 1.0, which means it can also cover anything.

But, in all honesty, it makes sense to support Display P3 before other spaces.

romainmenke commented 2 years ago

I keep forgetting this but color space could also be something custom. The format doesn't need to support this explicitly from the start, but keeping this in mind will easy future additions.

{
  "myPrintProfile": {
    "$type": "colorSpace",
    "some-way-to-embed-color-spaces": ""
  },
  "aColor": {
    "$type": "color",
    "colorSpace": "{myPrintProfile}",
    "channels": [0.5, 0.5, 0.5, 0.1, 1],
    "alpha": 1.0
  }
}
kaelig commented 2 years ago

The proposals in this thread are great, keep them coming!

From a technical perspective, this is all solvable. There are canonical implementation of color space translation functions, and design tools as well as token translation tools could work around this when consuming tokens. That said, some tools are aim to not only consume tokens, but also manage them.

I'm really curious about the user experience for someone consuming/editing/exporting tokens in a design tool like XD, UXPin, Framer, Figma… which don't have full color space/profile management (yet).

Here's an example use-case, followed by a few questions about the possible flows:

Use-case

  1. import a token file
  2. edit a wide-gamut color
  3. save/re-export the token file

Questions

In the context of an sRGB-only tool...

  1. What should the editing flow/color picking UX be?
  2. When saving/exporting edited color tokens, what sort of prompts would you expect in relation to potential data-loss?
  3. What should the exported data look like (considering the user may have picked an sRGB color, overwriting a P3 color)?
  4. What about people working on monitors that don't cover sRGB? What should their editing experience be?
romainmenke commented 2 years ago
  1. What should the editing flow/color picking UX be?

Checking if a color token is out of gamut or has an unknown color space is trivial. Each tool can scan a token file for tokens it can not represent faithfully or edit without altering the result.

If it is a translation tool this could be a warning that can be silenced.

For design tools this is problematic and I would see this as a destructive action. Following usual UX patterns the user would be given a prompt to explain and warn about the destructive action.

  1. When saving/exporting edited color tokens, what sort of prompts would you expect in relation to potential data-loss?

see 1.

  1. What should the exported data look like (considering the user may have picked an sRGB color, overwriting a P3 color)?

Can you clarify or give a concrete example? I do not follow the question.

  1. What about people working on monitors that don't cover sRGB? What should their editing experience be?

This is a problem that exists today and will continue to exist. Even if we use hex and limit to sRGB, this problem will exist as even this smaller color space can not always be fully represented.


Aside from these points I still do not understand why it is not possible to use a data format that has a clear update path?

I don't want to have some legacy code that checks if $value for $type: color is of type string.

{
  "color-token": {
    "$type": "color",
    "$value": {
      "colorSpace": "sRGB",
      "channels": [1, 0.5, 0],
      "alpha": 1
    }
  }
}

The questions that surface from using hex are almost exactly the same as those you have for color spaces :)

marcedwards commented 2 years ago

I'm really curious about the user experience for someone consuming/editing/exporting tokens in a design tool like XD, UXPin, Framer, Figma… which don't have full color space/profile management (yet).

They need to add support. There really isn’t any other way if they want to handle colours properly. At the very, very least, they should support a full sRGB workflow, with warnings and proper import conversion to sRGB.

Checking if a color token is out of gamut or has an unknown color space is trivial. Each tool can scan a token file for tokens it can not represent faithfully or edit without altering the result.

Yeah, that feels like a very easy solution for the tool makers. If they do not want to add full colour management, they can warn about colours being changed on import.

c1rrus commented 2 years ago

(As promised in my earlier comment) I have opened a new issue #157 which proposes some generalised rules for what the expected behaviour for tools should be in these kinds of scenarios. As I explain there, I believe those behaviours will not only be relevant to colors (when support for more color spaces is added) but also other types of tokens.

I therefore suggest we discuss the expected behaviour of tools there and keep this thread focussed on the details of color values specifically (i.e. what the permitted syntax(es) should be and what color spaces should be supported).

svgeesus commented 2 years ago

There’s a few answers to this. Rec.2020 is pretty huge, and that will cover quite a lot of future advancements. ACES is way bigger again. sRGB Extended allows for values beyond 1.0, which means it can also cover anything.

Rec BT.2020 is pretty huge indeed, and there are significant problems with it as a practical display space (observer metamerism, speckle, getting adequate brightness while keeping color purity) but as a space to specify colors it is fine and is widely used in industry (4k and up video content is delivered in BT.2020 or, for HDR, BT.2100 which has the same primaries). Rec BT.2020 does not cover all real-world colors but it covers a very substantial portion of them and is a significant increase over display-p3.

As for ACES, there are two sets of primaries - the AP0 set is enormous and not physically realizable, the AP1 set is similar to BT.2020 in coverage. ACEScg and ACEScc use the AP1 primaries.

kevinmpowell commented 2 years ago

At a minimum, whatever capabilities we add to the Color Type in future iterations, token authors who hand-edit their files must be able to specify a color using only a HEX value represented as a string.

My view is that the current spec as authored (where Color is specified via HEX) satisfies a couple of key principles of this group.

Namely:

Inclusive: Allow anyone to become familiar with design tokens. Empower people, no matter what their skills and tool choices are, as they develop new mental models, acquire skills, and implement tools to scale design in their projects.

and:

Focused, yet extensible: Stay focused on the smallest surface area necessary to cover the most commonly referenced use-cases. Be a platform that opens the door to a wide range of possibilities. This small footprint helps maintain simplicity with zero dependencies. Extensibility allows the community to incubate new ideas that will define the future of design tokens.

My read of those principles as applied to the Color Type and some of the proposals in this thread:

First - Empower people, no matter what their skills and tool choices are I'm very concerned about a spec change that would require a token author to specify a color space and a use a notation that may be unfamiliar to many. HEX, for all its shortcomings, is widely understood and standardized not just across tools, but also in the minds of many many designers and developers across multiple fields (not just web). It may be an insufficient format for what modern screens are capable of, but it's well established and that carries weight in the form of familiarity. That familiarity will aid in the spec's adoption by those who are familiar with HEX and have no need for colors in a wider gamut.

If we require specification of color spaces and array notation to specify color, we'll be placing an additional burden on many token spec adopters to not only learn the design token format, but possibly a whole new means of specifying colors they already have documented elsewhere in HEX. My concern is that this requirement would be so off-putting that it will limit the adoption of the specification as a whole.

To argue the counterpoint, you could say the current spec is not inclusive because it excludes those who wish to use colors from a wider-gamut. The lack of wider-gamut color space support is off-putting to those that wish to define their colors in something more powerful than HEX provides. For that group, I lean on the second principle: Stay focused on the smallest surface area necessary to cover the most commonly referenced use-cases.

I believe we are doing that by norming on the most commonly used representation of color in our current ecosystem.

All that said, I want to be future-looking in a future version of the spec. I believe something like @c1rrus proposed in https://github.com/design-tokens/community-group/issues/137#issuecomment-1166543573 would be the most inclusive syntax we could adopt - supporting both the today mindset of HEX and the future mindset of wider-gamut colors.

romainmenke commented 2 years ago

Stay focused on the smallest surface area necessary to cover the most commonly referenced use-cases. I believe we are doing that by norming on the most commonly used representation of color in our current ecosystem.

But this is a self re-enforcing mechanic right? It is the most commonly used representations because authors lack tools and now authors will lack tools because they haven't been authoring in more modern formats.

All that said, I want to be future-looking in a future version of the spec. I believe something like @c1rrus proposed in https://github.com/design-tokens/community-group/issues/137#issuecomment-1166543573 would be the most inclusive syntax we could adopt - supporting both the today mindset of HEX and the future mindset of wider-gamut colors.

This will place significant burden on tool maintainers as they will need to support two formats indefinitely. I am not even starting on my planned implementation for PostCSS because of issues likes these. I do not want to add tech debt on day one.

marcedwards commented 2 years ago

If we require specification of color spaces and array notation to specify color, we'll be placing an additional burden on many token spec adopters to not only learn the design token format, but possibly a whole new means of specifying colors they already have documented elsewhere in HEX. My concern is that this requirement would be so off-putting that it will limit the adoption of the specification as a whole.

As mentioned previously, sRGB can and should be the default when the color space is omitted, which lets people use a simpler format, if they’d like. It will cause massive issues if color spaces aren’t considered as part of the original spec. It’s just not a viable option to ignore color spaces in 2022. I’d go as far as saying I will not use a format that can’t specify the color space of a color.

jeromefarnum commented 2 years ago

I’ll leave the colorspace discussion to all you wizards that know far more than myself.

To me, the easily much more useful feature that I’m seeing discussed in this thread is the addition of the alpha field on the color type. This is absolutely essential, and a very conspicuous omission from the current and latest (as best as I can decipher) color type specifications.

As a token manager, I need to be able to pair a color token with either an alpha token or an arbitrary alpha value. This is incredibly useful when:

Neither of rgba or hex8 notation work well, in my opinion, because they would require tokenization of individual color channels (rgba) or a needless deviation from a much more readily understood notation for alpha (hex8).

romainmenke commented 2 years ago

@jeromefarnum I think this relates to : https://github.com/design-tokens/community-group/issues/121 and https://github.com/design-tokens/community-group/issues/149

Although that issue focusses on values like 10px the same underlying concerns also apply to other micro syntaxes like hex colors.

Since the format uses JSON it makes sense to store data in a structured way and not stringified/encoded.

This has the benefit of making it easy to manipulate a single sub-value like alpha. It also allows using references for each sub-value.

romainmenke commented 2 years ago

@kevinmpowell Can you elaborate on this statement :

At a minimum, whatever capabilities we add to the Color Type in future iterations, token authors who hand-edit their files must be able to specify a color using only a HEX value represented as a string.

Why is this a requirement? There have been numerous arguments in this issue and others against HEX colors.

The only argument in favour of it is that some people are already familiar with it now.

It is important to look at the long term here. If future designers and developers never have to learn hex color notation, would that be a good thing?

And equally important, if no one ever directly interacts with token files (because it is a transfer format) does it matter? Is it not better to let this arbitrary requirement go and pick the best color format?

jeromefarnum commented 2 years ago

I think this relates to : #121 and #149

@romainmenke I could see how my request could feel related to the issues you referenced; however, I would hope that my request would be evaluated separately.

Adding support for an alpha sub-value for the color token type, in my opinion, has neither a negative or positive impact on the human readability/maintainability of the spec. It is solely about providing a mechanism for composing a color token with either a tokenized or arbitrary alpha value. This is a pattern that designers and design systems use with regularity - and, removing the tokenization aspect, a pattern that all major design tools have long supported.

And unlike the unit sub-values, one would reasonably expect to encounter cases where color and alpha sub-values were composed with different values depending on their contextual use (e.g. an alert component with a warning role may compose a colors.warning token with component.alert.border.alpha and component.alert.shadow.alpha alpha tokens to achieve a desired visual effect, and the same alert component with an error role may compose the same alpha tokens with a colors.error token)

Conversely, I don’t think, pragmatically speaking, the same holds true for units. I’d not expect that many designers would desire to pair a spacing.large token with a px unit in one case and a vh unit in a sibling case within the same token theme. Similar for pairing a duration.short time token with ms, seconds, or minutes conditionally within the same token theme.

This is not to dispute the validity of those other issues - they seem like worthy discussions to have. I simply wouldn’t expect the outcomes of those discussions to have much impact on this particular matter.

romainmenke commented 2 years ago

Adding support for an alpha sub-value for the color token type, in my opinion, has neither a negative or positive impact on the human readability/maintainability of the spec. It is solely about providing a mechanism for composing a color token with either a tokenized or arbitrary alpha value. This is a pattern that designers and design systems use with regularity - and, removing the tokenization aspect, a pattern that all major design tools have long supported.

I meant that at its core a structured data format enables more use cases. Having a separate alpha field works for your case, having units separate from values works for others. But the shared principle is that avoiding microsyntax and encodings has specific benefits.

Referencing these issues is only intended to illustrate that this is a general pattern in the current specification (to favour microsyntaxes). I do not expect the resolution to be linked.

o-t-w commented 2 years ago

Chrome browser will ship modern color in version 110, to be released in December.

romainmenke commented 2 years ago

Chrome browser will ship modern color in version 110, to be released in December.

This implies not only Chrome, but all Chromium based browsers and Electron apps.

PavelLaptev commented 2 years ago

Agreed with @romainmenke. groups might solve the issue at the beginning.

{
  "modern-colors": {
    "$type": "color",
    "$description": "We use it only if oklch is supported",
    "colors": {
      "color-space": "oklch",
      "colors": [
        {
          "name": "primary",
          "$value": [
            "40%",
            "0.1",
            "21"
          ]
        },
        {
          "name": "secondary",
          "$value": [
            "10%",
            "0.2",
            "12"
          ]
        }
      ]
    }
  }
}
o-t-w commented 1 year ago

Modern color is now supported in all browsers - Chrome, Edge, Safari, Firefox.

kaelig commented 1 year ago

I wonder if we should be a bit more descriptive in the names of the channels/components for clarity, readability, and clearer autocomplete (potentially allowing for 'none' values).

Here's what I mean:

{
  "PrettyInPink": {
    "$type": "color",
    "$value": {
      "$hex": "#ff70b8",
      // Give each color scheme its own object type,
      // with descriptive keys
      "$display-p3": {
        "red": 0.76, 
        "green": 0.28, 
        "blue": 0.62 
      },
      "$oklch": {
        "lightness": 0.72, 
        "chroma": 0.46, 
        "hue": 329 
      }
    }
  }
}
JSON Schema for $oklch Ported from the [CSS Color Module 4 OKLCH notation spec](https://www.w3.org/TR/css-color-4/#funcdef-lch) ```json { "type": "object", "properties": { "lightness": { "oneOf": [ { "type": "number", "minimum": 0, "maximum": 100, "title": "The numeric value for lightness, from 0.0 (darkest) to 100.0 (lightest) without any unit" }, { "type": "string", "pattern": "^(100%|[1-9]?[0-9]%|none)$", "title": "The percentage value for lightness or 'none' to indicate it is not defined" } ] }, "chroma": { "oneOf": [ { "type": "number", "minimum": 0, "maximum": 150, "title": "The numeric value for chroma, scaled from 0 (neutral) to 150 (vivid)" }, { "type": "string", "pattern": "^(100%|[1-9]?[0-9]%|none)$", "title": "The percentage value for chroma, where 100% is mapped to the numeric value 150 or 'none' to indicate it is not defined" } ] }, "hue": { "oneOf": [ { "type": "number", "title": "The numeric value for hue, interpreted in degrees" }, { "type": "string", "pattern": "^(none)$", "title": "The string 'none' to indicate no hue defined" } ] }, "alpha": { "oneOf": [ { "type": "number", "minimum": 0, "maximum": 1, "title": "The numeric value for alpha transparency, from 0.0 (fully transparent) to 1.0 (fully opaque)" }, { "type": "string", "pattern": "^(100%|[1-9]?[0-9]%|none)$", "title": "The percentage value for alpha transparency or 'none' to indicate full opacity" } ] } }, "required": ["lightness", "chroma", "hue"], "additionalProperties": false } ```

Thoughts from folks in this thread?

romainmenke commented 1 year ago

I wonder if we should be a bit more descriptive in the names of the channels/components for clarity, readability

Yes, a fully typed object with descriptive names would be good.

But it isn't clear from your example which value should be used. $hex could be a specified fallback in case an implementation does not support wide gamut color formats, but how does an implementation decide between $oklch and $display-p3?

potentially allowing for 'none' values

This would be nice! Certain interpolations are only possible when specific channels have a value of none.

IanVS commented 9 months ago

I have a related issue that I haven't seen discussed here so far. The colors for my design system are specified in hsl. If I have to convert them to hex for storage in the design token, and then convert them back to hsl during processing, I get slightly different hue and saturation values, which is disappointing. It would be great if I could store it directly as hsl to avoid the conversion losses.

drwpow commented 9 months ago

@IanVS that will happen since HSL is a distortion of the sRGB/hex gamut. If you get any different values converting back, it just means the exact same color can be expressed in multiple ways (one of HSL’s many flaws). It shouldn’t affect the final output, but understand it can be annoying just dealing with the noise.

kaelig commented 9 months ago

Personal take: after running into serious color conversion issues and broader team confusion, I consider the hsl() notation harmful, and would encourage practitioners to move away from it.

That being said, for those stuck using HSL (or manage to make it work for them), it'd be great to offer a format that helps them do the right thing.

kaelig commented 6 months ago

@romainmenke's proposal is the closest to what we want, and here's what we have right now:

{
  "my-token": {
    "$type": "color",
    "$value": {
      "hex": "#xxxxxx", // Only HEX 6 supported (no HEX 3, 4, or 8)
      "colorSpace": "dci-p3",
      "channels": [0.1, 0.2, 0.3],
      "alpha": 0.6
    }
  }
}

We could borrow the pre-defined CSS spec spaces for absolute color(<color-space> ...) values with rectangular spaces, as in: srgb | srgb-linear | display-p3 | a98-rgb | prophoto-rgb | rec2020 | lab | oklab | xyz | xyz-d50 | xyz-d65.

That said, community feedback shows people want to write and use polar color spaces: hsl | hwb | lch | oklch.

My question to color experts here is: can we support both polar and rectangular color spaces with the spec showed above?

romainmenke commented 6 months ago

My question to color experts here is: can we support both polar and rectangular color spaces with the spec showed above?

Yes

Both rectangular and polar color spaces use 3 channels each and you can define unambiguous value definitions for both rectangular and polar color spaces.

{
  "my-token": {
    "$type": "color",
    "$value": {
      "hex": "#xxxxxx",
      "colorSpace": "hsl",
      "channels": [270, 0.5, 0.3],
      "alpha": 0.6
    }
  }
}

Could be equivalent to hsl(270deg 50 30).

That is to say, these are all just numbers and as long as there is a clear definition of what the numbers mean it will work out fine.

I would suggest staying close to the CSS value definitions : https://drafts.csswg.org/css-color-4/#the-hsl-notation

Staying close to CSS makes it possible to use more of the shelf tooling around color and facilitates copy/pasting of values.


I would suggest using a different term than colorSpace if the intention is to adopt such a wide range of possible notations. Since not every notation might be a color space.

Maybe colorScheme?

o-t-w commented 6 months ago

The term color scheme is often used interchangeably with theme. E.g.: https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme

Maybe "syntax" or "notation"?

romainmenke commented 6 months ago

Right, color scheme is much more widely known in the context of dark/light mode.

notation works for me

marcedwards commented 6 months ago

My question to color experts here is: can we support both polar and rectangular color spaces with the spec showed above?

Color space typically describes which colors are possible, and how they’re mapped within the available gamut.

It’s usually referred to as color model or color mode when talking about how the actual values describe the color (within the color space). With that in mind, RGB, HSB, HSL etc are all color models or color modes.

It’d be good to not conflate the two concepts in the spec. With that in mind, this could be good?

By default, sRGB should be assumed as the color space, and RGB should be assumed as the color mode.

{
  "my-token": {
    "$type": "color",
    "$value": {
      "channels": [0.1, 0.2, 0.3],
      "alpha": 0.6
    }
  }
}

But, a color space and color mode can be provided.

{
  "my-token": {
    "$type": "color",
    "$value": {
      "colorSpace": "display-p3",
      "colorMode": "hsl",
      "channels": [0.1, 0.2, 0.3],
      "alpha": 0.6
    }
  }
}

Personal take: after running into serious color conversion issues and broader team confusion, I consider the hsl() notation harmful, and would encourage practitioners to move away from it.

My personal stance on this is that RGB is the native format, and typically how the data is represented in textures on the GPU. RGB is the format with a lower risk of rounding errors and other weirdness, and given it’s the default assumption for color mode, it’s the safest. I try not to store colors in HSL or HSB, but… I do see the value in it and I bet lots of people will want it.


I guess another part of this conversation is that without color spaces, there are colors you can not describe and can not achieve. Color spaces are extremely important. If early spec versions are missing some color modes, I think that’s less of an issue — you can always just convert the values to RGB to get the correct color.

kaelig commented 6 months ago

I would suggest using a different term than colorSpace if the intention is to adopt such a wide range of possible notations. Since not every notation might be a color space. – @romainmenke

It’d be good to not conflate the two concepts in the spec. – @marcedwards

The CSS spec seems to use "color space" to describe concepts like spaces, models, and notations, which has left me confused 😅 For example, I couldn't explain to someone why hsl is simultaneously a notation expressing colors in the srgb color space, and a radial color space (note that I'm not criticizing the spec, but rather pointing out how it can be confusing to some without the level of expertise as people who write the CSS spec).

@svgeesus your guidance on naming would be extremely appreciated 🙏🏻

marcedwards commented 6 months ago

I guess that just happened becuase these names are more of an industry convention that has evolved over time, rather than an agreed upon spec? For me, “color space” is something I try to avoid saying unless I’m describing gamut (and all the other things that make up a color space).

marcedwards commented 6 months ago

Also, maybe I’ve oversimplified things a little too much, because color spaces can also dictate the color model used.

DominikDeak commented 6 months ago

I think a good way to alleviate confusion is to look at what ICC Standard uses for terminology. In my opinion, following the convention used by the authority on colour management and being consistent with their vocabulary is good practice.

When most people speak of "colour spaces", they probably actually meant Colour Profiles, which define the following properties:

Some special Colour Profiles do not have a Colour Gamut, nor do they use a particular Transfer Function (i.e. values are interpreted directly without gamma correction). Examples of this are CIEXYZ, CIELAB, and OKLAB, and they only specify a Colour Space, because they are gamut-independent absolute spaces.

So, if we were to follow ICC way of specifying properties, the following two attributes the should be present: the Colour Profile, and the Colour Space (if applicable). Using and modifying the aforementioned examples, my proposal would look like this:

{
  "my-token": {
    "$type": "color",
    "$value": {
      "colorProfile": "display-p3",
      "colorSpace": "hsl",
      "channels": [0.1, 0.2, 0.3],
      "alpha": 0.6
    }
  }
}

For profiles that have an absolute colour space, the colorSpace property can be omitted, as the space is implied by the colorProfile itself:

{
  "my-token": {
    "$type": "color",
    "$value": {
      "colorProfile": "oklab",
      "channels": [0.1, 0.2, 0.3],
      "alpha": 0.6
    }
  }
}
Shrinks99 commented 6 months ago

Because @kaelig asked for comments, will just mention that I'm generally quite happy with where this is ending up. We seem to have rejected calls for simplification for simplification's sake and are instead converging towards a method that can correctly encode colour information. Good stuff! The future for design tokens looks bright :)

romainmenke commented 6 months ago

I said :

I would suggest using a different term than colorSpace if the intention is to adopt such a wide range of possible notations. Since not every notation might be a color space.

Maybe colorScheme?

I've changed my mind about this. I think colorSpace is perfectly fine.

I don't want to derail this thread in pursuit of finding a perfect name that encompasses all possible values. I also do not want to kick-off a fresh design fase for the schema of color values.

I think everyone will understand the meaning and intention behind colorSpace even if there is support for a value that, from a color theory perspective, isn't really a color space.

ilikescience commented 6 months ago

I'm with @romainmenke here, I think colorSpace does a great job.

From Wikipedia:

Since "color space" identifies a particular combination of the color model and the mapping function, the word is often used informally to identify a color model.

nesquarx commented 6 months ago

Seconded, as long as there's a way to define non-standard gamut and model combinations - color space is fine, semantic derails can often lose the point.

On Fri, May 17, 2024, 7:17 PM Matthew Ström @.***> wrote:

I'm with @romainmenke https://github.com/romainmenke here, I think colorSpace does a great job.

From Wikipedia:

Since "color space" identifies a particular combination of the color model and the mapping function, the word is often used informally to identify a color model.

— Reply to this email directly, view it on GitHub https://github.com/design-tokens/community-group/issues/137#issuecomment-2117649255, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEKS36EUEQVW2QBUB5UQWO3ZCYDANAVCNFSM5YYUJBRKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TEMJRG43DIOJSGU2Q . You are receiving this because you commented.Message ID: @.***>