-
Notifications
You must be signed in to change notification settings - Fork 756
Description
There has been discussion in several issues recently about providing a ::document selector, or @document/@global/@env rule that would allow authors a quick way to register globally available constants (as custom properties or environment variables) - without a full @property rule describing each individually. See, for example:
- [css-fonts] [palettes] Disallow usage of var() in
@font-palette-values#6931 - [css-pseudo] Custom properties on :root #6641
- [css-env] Adding custom env() variables #2627
(Hopefully this issue is useful as a way of combining several discussions, and not just a duplicate)
Those first two issues have more specific concerns that could be (or have been) addressed in specific ways - but mention the possibility we might still want a more generic solution for registering global properties. Custom media queries (@custom-media) have similarly been solved as a specific case, but not yet implemented – and there's an open issue for adding @custom-container. Those use-cases could also be solved by a well-defined global parameter registry.
There are two primary overlapping concerns here:
- A less verbose syntax for authors to register custom properties with an initial value and syntax. As @LeaVerou has pointed out, authors define a lot of variables, and the
@propertyrule is a very bulky way to register them one-at-a-time. - Authors would like to define global values that can be reused in at-rules, or other places where the cascading
var()would not be possible to resolve.
I tend to agree with @tabatkins that:
Having an author-defined
env()might work, but would require an author to duplicate values across properties andenv(), or else decide for each whether they want to express it as a var or anenv().
I like the proposed solution of allowing global reference to the initial values of registered custom properties, but think we need to make that registration simpler for it to work. I don't know the right syntax for that, but if we're able to come up with something compact, it could also be useful for defining parameters in declarative custom functions and (someday, maybe) mixins.
The @property rule can register a custom property name with three associated descriptors:
syntax: the CSS type/grammar(s) used to validate and interpolate values (often but not always a single type like "<color>" or "<length>"'inherits: a boolean to set if the property inherits or not (this would not be needed in function/mixin parameters)initial-value: the initial value of the property
Authors often skip this registration for most properties, and only define the name along with an un-registered not-technically-'initial' value on the root element. Then some authors add the @property registration for specific properties - often to define a syntax for the sake of interpolation, but occasionally to set inheritance or a more formal initial value.
Things I would expect from a syntax:
- Optionally register just the name and initial value (default to universal syntax, with inheritance on)
- Optionally register props with the guaranteed invalid initial value
- Optionally register groups of properties that share a
syntax
The main complexity that I see with defining a compact syntax is that custom property values (including initial values) are very permissive. It will be difficult to combine initial-value with anything else on the right side of a standard property:value; format – though it should be possible using either the ! delim-token, or wrapping ()/{}/[] of some kind. The other thought I had was to put some of the definition on the left side. Some rough ideas:
@global {
--my-color("<color>"): mediumvioletred;
--my-padding("<length>"): 10px !no-inherit;
}
@global "<color>" no-inherit {
--brand-color: teal;
}The an all-in-one syntax is more appropriate for reuse in function parameter definitions, while the grouped syntax helps with defining a whole set of related variables in a single place.
On the other end, when calling custom properties, a env() or global() function could give access to the initial registered value anywhere in the document, while var() returns only the cascaded value. I prefer this to a context-dependent resolution of var(), since it provides more clarity on what value to expect, and makes both available where var() is already supported:
.my-thing {
color: var(--brand-color);
padding: global(--my-padding);
@media global(--above-small) {
...
}
}This is far from a complete proposal, and mostly a request that we consider these use-cases together. Happy for thoughts, and willing to merge this into the env() conversation if it belongs there.