design-tokens / community-group

This is the official DTCG repository for the design tokens specification.
https://tr.designtokens.org
Other
1.55k 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.

marcedwards commented 5 months ago

Yep! I’m all for whatever gets it done. And maybe @DominikDeak ’s suggestion of colorProfile is the least ambiguous for that portion.

danosek commented 5 months ago

I'm using Oklch as a primary space in our design system mainly used in web apps. We also need another spaces for Figma, MS Office etc. We don't use Design Tokes Format Module yet, just plain JS object. This is how it would looked like:

{
    "$name": "amber-30",
    "$humanName": "Amber 30",
    "$css": "--amber-30",
    "$modifier": "30",
    "$bgInteractionMode": "darken",
    "$type": "color",
    "$value": "oklch(0.84 0.1 82)",
    "$colorSpaces": {
        "oklch": "oklch(0.84 0.1 82)",
        "hex": "#ebc57d",
        "rgb": "rgb(240 200 130)",
        "hsl": "hsl(39 74% 71%)"
    }
}

What I would improve is that if $type: color has multiple values, the name of the key could represents name of color space. I don't think there is a need for hex to be split into channels. It is so widely used as is, so there is no need to complicate its definition.

{
    "$type": "color",
    "$value": {
        "oklch": {
            "channels": [0.84, 0.1, 82],
            "alpha": 0.5
        },
        "hex": "#ebc57d80",
        "rgb": {
            "channels": [240, 200, 130],
            "alpha": 0.5
        },
        "hsl": {
            "channels": [39, 0.74, 0.71],
            "alpha": 0.5
        },
    }
}
drwpow commented 4 months ago

What I would improve is that if $type: color has multiple values, the name of the key could represents name of color space. I don't think there is a need for hex to be split into channels. It is so widely used as is, so there is no need to complicate its definition.

We considered that, but have decided to just have 1 token = 1 color (1 colorSpace) for now. It would be overly complex for tooling to look at a color and have to sift through which colorSpaces are / aren’t available for a given token, and “rank” what it wants to pull as the color (because, for example, many OKLCH colors have no parallel in HSL, and so it’s opinionated how you’d even go about converting one to the other).

hex is just a fallback for sRGB, not a competing colorSpace, meant to encourage wider support for older hardware where only sRGB is supported. For that reason it’s optional and can be omitted if you don’t need it. But many platforms will, and again, gamut clipping is opinionated and there’s no absolute way to do it.

Lastly, taking gamut clipping out of the equation, if you’re converting from one colorSpace to another, it’s trivial to do with libraries available like culori, so in a sense, declaring multiple colorSpaces on one token is redundant and unnecessary work. No matter what form your color tokens are in, you’ll still have to transform them anyway when delivering code to any platform (web, Android, iOS, etc), and make per-platform decisions on how to do so. A design goal of the DTCG spec is to have platform-agnostic tokens that you can apply platform-specific decisions to later; not to have to solve all your platform problems in one place (even assuming that’s possible).

drwpow commented 4 months ago

Also, a few notes amended to @kaelig’s updated proposal:

Channel definition

It’s been raised “what are the channel values and how are they defined?” For example, is "colorSpace": "srgb", "channels": [64, 0, 128] valid? For clarity, we’ll use the same definitions as CSS Color Module 4’s color() function, which defines colorspaces and values in §10, such as srgb channels being red, blue, green in that order, and accepting only [0, 1] values.

The only clarification we’d make is that percentages wouldn’t be supported, since there is no percentage type (yet). Just normalize to 1 (0% = 0, 100% = 1).

Aliasing

Also a question of “what is aliasable” is inevitable, and we’d like to propose Any sub-value is aliasable if it resolves to a valid $type.. For example:

✅ Valid: Entire $value

This is supported today, of course

{
  "action": {
    "$value": "{color.blue.500}"
  }
}

✅ Valid: Aliasing part of a value is valid only if it aliases a valid existing $type

This is consistent with current docs for $type:

If the token’s value is a reference, then its type is the resolved type of the token being referenced.

In other words, this seems allowed by current usage of spec.

Further, referencing within "channels" should be allowed because even though there is no array of number types, individual values are all $type: number as well. Just as though gradient tokens’ stops aren’t a $type in and of themselves, they are allowed to alias color and number tokens.

{
  "action": {
    "$type": "color",
    "$value": {
      "colorSpace": "oklch",
      "channels": ["{lightness.70}", 0.153, 246.18],
      "alpha": "{alpha.100}",
      "hex": "#3ca5f7"
    }
  }
}

❌ Invalid: Aliasing part of a value that is not a valid $type

Since there is no valid types that "colorSpace" or "channels" could resolve to, they’re invalid. Further, since string types are not supported, and colors are now objects, technically "hex" could not resolve to a valid $type, either.

{
  "action": {
    "$type": "color",
    "$value": {
      "colorSpace": "{colorSpace.oklch}",
      "channels": "{channels.color.blue.500}",
      "alpha": 1,
      "hex": "{color.blue.500}"
    }
  }
}

❌ Invalid: Partially aliasing just a part of another $type: color’s value

This is another proposal entirely: https://github.com/design-tokens/community-group/issues/148

{
  "action": {
    "$type": "color",
    "$value": {
      "colorSpace": "oklch",
      "channels": [0.7, 0.153, 246.18],
      "alpha": 1,
      "hex": "{color.blue.500.$value.hex}"
    }
  }
}
kaelig commented 2 months ago

Update: I just edited the comment below to mention we'd be only supporting HEX 6 as a hex fallback (not HEX 3, 4, 8), because the alpha is controlled by the alpha property.

https://github.com/design-tokens/community-group/issues/137#issuecomment-2116168184

mck commented 1 month ago

I'd like to propose adding support for the CMYK color model to the specification. This enhancement aligns with our goal of making the specification more flexible and future-proof by accommodating various color spaces.

Proposal Details:

  1. Extend the Color Token Format:
    • Introduce the ability to specify colorSpace as "cmyk".
    • Allow channels to accept an array of four values representing the Cyan, Magenta, Yellow, and Key (black) components.
  2. Example Syntax: Using decimal values between 0 and 1:
    {
     "$type": "color",
     "$value": {
       "colorSpace": "cmyk",
       "channels": [0.0, 1.0, 1.0, 0.0],
       "alpha": 1.0,
       "hex": "#ff0000"
     }
    }

    Or using percentages between 0 and 100:

    {
     "$type": "color",
     "$value": {
       "colorSpace": "cmyk",
       "channels": [0, 100, 100, 0],
       "alpha": 1.0,
       "hex": "#ff0000"
     }
    }

    Benefits:

    • Print Design Integration:
    • Seamless Workflow: Facilitates a smoother integration between digital and print design processes by allowing designers to specify print-ready colors directly in design tokens.
    • Accuracy: Reduces the need for manual color conversions and minimizes discrepancies between on-screen designs and printed materials.
    • Specification Flexibility:
    • Future-Proofing: By supporting CMYK, we make the specification more adaptable to various mediums and industries.
    • Consistency with Ongoing Discussions: This proposal aligns with the existing discussions about supporting multiple color spaces through the colorSpace and channels properties.
romainmenke commented 1 month ago

Important to then be able to specify which cmyk profile.

drwpow commented 1 month ago

Very much in favor of supporting CMYK but yes would have to specify the profile as @romainmenke said. We wouldn’t have cmyk on its own, but following the other colorspace syntax, it would be cmyk-swop or cmyk-fogra32, etc. Would love for someone who works more regularly with printing to propose what a reasonable set of all those would be.

svgeesus commented 1 month ago

Uh, before going off and inventing a new syntax, perhaps look at 5.4. CSS and Print: Using Calibrated CMYK and Other Printed Color Spaces in CSS Color 5, which already does calibrated CMYK?

svgeesus commented 1 month ago

Introduce the ability to specify colorSpace as "cmyk".

That doesn't mean anything, without saying which cmyk colorsdpace (what inks, what paper, what printing conditions, what level of GCR, maximum coverage, etc). All fo which is defined in an ICC profile.

svgeesus commented 1 month ago
{
  "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
    }
  }
}

Is the sRGB hex a fallback, or the main color?

Is DCI-P3 (a projector space for digital cinema, to be viewed in an entirely dark room) really, means, or display P3?

drwpow commented 1 month ago

Ah sorry @svgeesus this issue is out-of-date. We’re currently working on updating this PR after some internal discussion, but TL;DR we’re going to align around CSS Color Module 4 (and potentially Module 5). So we’re aligning with display-p3 over dci-p3, e.g.

Is the sRGB hex a fallback, or the main color?

Optional fallback for support on more devices (since color clamping is opinionated)