[css-variables?] Higher level custom properties that control multiple declarations · Issue #5624 · w3c/csswg-drafts (original) (raw)

Currently, custom properties can be used to hold small pieces of data to be used as parts of larger values. Despite being called custom properties, they are mainly used as variables. High-level custom properties that control a number of other CSS properties cannot be implemented.

Besides limiting regular CSS authors, this makes it impossible for custom element authors to follow the TAG guideline to avoid presentational attributes and to use a custom property instead, except for very simple bits of data like fonts, colors, and lengths. For anything more complex, web component authors use attributes instead.

Examples from a variety of custom element libraries:

I can collect more if needed, examples abound in nearly all component libraries. Currently, these are impossible to implement as CSS custom properties, for a number of reasons:

Essentially, component authors need more high-level custom properties that encapsulate the corresponding declarations better instead of just containing fragments of values.

Some proposals to address this problem focus on a JS-based way to monitor property changes [WICG/webcomponents#856], but that appears to be hard to implement. So, I'm wondering if we can address this from CSS instead, especially since it would also address a number of other use cases too that are unrelated to components, a big one being mixins, without the problems that we had with @apply.

There are discussions in the group about inline conditionals [#4731, #5009]. If we were to have such conditionals, these would be possible to implement, but very painful (each declaration value would need to be one or more if()). I was wondering if we could simplify this.

A pseudo-class such as :if-var(<dashed-ident> <comparison-operator> <value>) would solve this ideally, but would likely not be implementable due to cycles. OTOH we already do cycle detection for variables, so perhaps it is? If so, I can flesh out a proposal.

Otherwise, perhaps a nested @rule?

my-input { @if-var(--pill = on) { border-radius: 999px; } }

With nesting, that would even allow multiple rules, so it would cater for use cases such as e.g. the tabs placement without too much repetition.

One way to implement this would be as sugar for multiple if()s, but that would have the undesirable side effect of all containing declarations being set to initial when the conditional doesn't match and there's no @else, which is suboptimal.

Whatever solution we come up with, some things to consider:

Current status (updated April 5th, 2021)

This is a long discussion, this is the current status: