[csswg-drafts] Proposal: CSS Variable Groups (as a solution to several design systems pain points) (#9992)

LeaVerou has just created a new issue for https://github.com/w3c/csswg-drafts:

== Proposal: CSS Variable Groups (as a solution to several design systems pain points) ==
The [whole proposal is here](https://lea.verou.me/docs/var-groups/), I have included a summary below.

## Pain points (summary)

The main pain point is **aliasing**. Currently, design systems are specified as a long series of variables, e.g. `--color-green-100`, `--color-crimson-950` etc.
Aliasing them to other names (e.g. semantic names such as `--color-primary` or simply shorter/simpler names) is currently author hostile, as it requires manually [aliasing every single one](https://www.radix-ui.com/themes/docs/theme/color#aliasing-colors), i.e. hundreds of declarations. Not only is this painful to do for the whole page, it makes it very hard to theme areas on the page with a different color, or pass design tokens to components.

Additionally, tints and shades for each color are generated manually, even if some of them could be inferred via interpolation. Theoretically that can already be done via a series of `color-mix()` values, but it is very tedious and repetitive, especially if you want to tweak the endpoints by adding more manual values where the interpolated ones don't work well.

## Other ideas explored

Some of the following may be useful in their own right, but I don’t think solve the pain points equally well.
- [Custom functions](https://lea.verou.me/docs/var-groups/#custom-functions)
- [CSS functions for tints and shades](https://lea.verou.me/docs/var-groups/#tint-shade)
- [Dedicated syntax for design tokens with standardized names for the low level common things](https://lea.verou.me/docs/var-groups/#design-systems-syntax)

## [The proposal](https://lea.verou.me/docs/var-groups/#proposal) (summary)

At its core (and as an MVP) this proposal allows authors to define groups of variables with the same prefix by using braces, and then pass the whole group around to other variables.

```css
/* Author CSS */
:root {
 --color-green: {
  100: oklch(95% 13% 135);
  200: oklch(95% 15% 135);
  /* ... */
  900: oklch(25% 20% 135);
 };
}

some-component {
 --color-primary: var(--color-green);
}
```
```css
/* some-component.css */
:host {
 background: var(--color-primary-100);
 border: var(--color-primary-400);
 color: var(--color-primary-900);
}
```

- **Groups can be [infinitely nested](https://lea.verou.me/docs/var-groups/#nested-variable-groups)**, to specify not only tints of a single color, but an entire color palette or even an entire design system and pass it around with a single CSS variable.
The granularity is completely progressive: you can go from defining `--ds-color-green` as a group, to defining `--ds-color` as a group to defining `--ds` as a group without changing *anything* about the places referencing them.
- Individual properties can still be specified outside of the group and overridden via regular CSS cascade rules. This provides a migration path for porting existing design systems to groups without their code having to be updated.
- Groups (and their constituent properties) inherit normally, like any other value. Custom properties in descendants can shadow inherited properties with the same name, i.e. a local `--color-green-100` will override the inherited one from `--color-green`  (just like with shorthands).
- There may be value in exposing a [functional syntax](https://lea.verou.me/docs/var-groups/#functional-syntax) for every CSS variable group, to facilitate selecting 

### [Using groups on non-custom properties: The `base` property](https://lea.verou.me/docs/var-groups/#using-groups-on-non-custom-properties%3A-the-base-property)

Authors can optionally specify a `base` value, which will be output if the custom property is used in a context that does not support groups, such as a regular CSS property.

```css
--color-green: {
 base: oklch(65% 50% 135);
 100: oklch(95% 13% 135);
 200: oklch(95% 15% 135);
 /* ... */
 900: oklch(25% 20% 135);
};

.note {
 /* Same as border: 1px solid oklch(65% 50% 135)); */
 border: 1px solid var(--color-green);
}
```

This can also be tweaked from outside the group (just like the group properties), by setting `--color-green-base`. This also facilitates the use case of having constituent properties that are dynamically computed from the base so changing the base tweaks all of them in unison.

### [Continuous tokens](https://lea.verou.me/docs/var-groups/#continuous)

*(This is definitely beyond MVP and more speculative)*

Authors can specify a catch-all expression to be used to resolve undefined keys via a `default` property:

```css
--color-green: {
 base: oklch(65% 50% 135);
 100: oklch(95% 13% 135);
 default: color-mix(in oklch, var(--color-green-100) calc((100 - arg / 10) * 1%), var(--color-green-900));
 900: oklch(25% 20% 135);
};
```

Ideally, numerical keys would be automatically detected, and the min and max would be exposed so that people could do [piecewise interpolation](https://lea.verou.me/docs/var-groups/#piecewise-interpolation) (just like in gradients).

-----

I ran this by a couple design systems folks I know, and the response so far has been overwhelmingly "I NEED THIS YESTERDAY". While I’m pretty sure the design can use a lot of refinement, I’m hoping we can prioritize solving this problem.

Note that beyond design systems, this would also address many (most?) of the use cases around maps that keep coming up (don't have time to track them down right now, but maybe someone else can).

Before commenting please take a look at the [whole proposal](https://lea.verou.me/docs/var-groups/) in case the issue you’re about to point out has been addressed there!

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/9992 using your GitHub account


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

Received on Saturday, 24 February 2024 02:20:37 UTC