Skip to content

[css-values] Functional counterparts of other CSS-wide keywords (revert-layer(), revert-rule()) #11773

@LeaVerou

Description

@LeaVerou

This proposal is a portmanteau of two past resolutions:

  1. In [css-values-5] inherit() function: like var() for parent value, for any property #2864 we resolved to add an inherit() function that resolves to the inherited value of any property and can be be used in expressions similarly to var().
  2. Recently, in [css-cascade][css-syntax] New !revertable flag to mark a declaration as "can be reverted when IACVT" #10443 (comment) we resolved to add a revert-rule CSS-wide keyword.

There is a cornucopia of use cases where it would be incredibly useful to be able to access this (and revert-layer) as a value that can be used to modify a property "in place".

As a contrived example, we frequently teach folks that this won’t work, because it creates a cycle:

--foo: calc(var(--foo) + 1);

However, this could:

--foo: calc(revert-rule(--foo) + 1);

More pragmatically, this could be incredibly useful for manipulating design tokens in-place, without introducing dozens of intermediate CSS properties. E.g. if you have CSS variables like --color-{hue}-{tint} (e.g. --color-green-95), here are a few things you could do that would normally require a ton of intermediate properties, repeating values verbatim, or making the tweak part of the property definition:

Make them sensitive to light-dark mode:

--color-green-95: light-dark(revert-rule(--color-green-95), var(--color-green-05));

Tweak their coordinates:

--color-green-95: oklch(from revert-rule(--color-green-95) l calc(c * var(--chroma-scale, 1)) calc(h + var(--hue-shift, 0)));

Adjust for high contrast:

--color-green-40: if(style(--contrast: high), var(--color-green-05), revert-rule(--color-green-40));

I’m only using colors as an example, but there is nothing color-specific here. Being able to tweak a CSS variable "in-place", without needing an extra level of element nesting or an intermediate variable is something that crops up a lot.

This is not specific to CSS variables either. It could solve the age-old problem of modifying other CSS properties quite elegantly:

transition: revert-rule(transition, all), 1s --foobar;
transform: rotate(5deg) revert-rule(transform, ) scale(.8);
background: var(--icon), revert-rule(background, none), var(--backdrop);

What about cycles?

This proposal only supports referencing the value of the same property, which should (?) eliminate cycles.
It still takes the property name as an argument for these reasons:

  • Consistency with inherit() and var()
  • Potential later expansion
  • Fallback (sure, in theory the fallback could be the only value, but then we can never allow it to reference other properties)

MVP

  • Similar use cases for revert-layer(), and supporting revert-layer() means this can ship independently of revert-rule and authors can reap the benefits by just wrapping code with @layer {}.
  • Fewer use cases for initial(), revert(), unset() so I'm not proposing these (but we could keep them in mind as an elegant solution if use cases appear that they would solve).
  • Just like inherit(), this would be immensely useful even if it only ships for custom properties.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions