https://drafts.csswg.org/css-env-1/
What are the current ideas being pitched to add custom env() variables via CSS?
To add custom env() variables, could a similar syntax be used as seen in custom media and custom selectors?
@custom-env --some-width 30em;
Or what other issues might there be?
Should it work on a rule level, so you can insert arbitrary stuff into a rule, like reusing a block of declarations?
While I feel like the answer _should_ be ānot yetā, if the answer to this question is yes, could syntax like @media
(curly braces) be used?
@custom-env --some-centering {
align-items: center;
justify-content: center;
}
As for JS, I hope that can be resolved separately via Houdini, because Iām under the impression there are still many things to work out with the similar concept of custom properties (as well as shorthands which apply to both, or selectors and rulesets that could apply to env()
) .
I think the general idea is to allow script to set them. But it's probably a good idea to allow stylesheets specify default values to them. Probably something like
@env {
--some-width: 30em;
--some-color: #000;
}
works.
What would the advantage of 'custom env()
variables' be compared to using the CSS custom properties we already have?
These env()
values could potentially be things the browser user has influenced (like if they have a setting for 'prefer low motion' or 'high contrast' that gets exposed as an env()
, or information about the device, OS, and browser it's being displayed in) but if they're settable by CSS authors that seems like it defeats the purpose of themāif it's the case that we want custom settable variables _and_ special variables with reserved names that the browser supplies to value to why not expose these values as some kind of reserved default CSS custom property, what would we even need env()
for?
env() is guaranteed global, which means you can store them in a much more memory-efficient whole-page data structure, rather than on each individual element like currently. (Chrome, at least, attempts to detect custom props that are set on the root element and not set anywhere else, and automatically upgrade them to such a data structure.)
env() also should be usable in further contexts outside of properties on elements, such as in MQs. This is fundamentally impossible with var().
I hope this is the place for ideas to prevent use of author-defined env()
causing FOUC.
In https://github.com/w3c/csswg-drafts/issues/3285#issuecomment-436063294 @tabatkins says...
Setting a new env() value would trigger a reparse in this idea.
Any thoughts on what @upsuper points out in https://github.com/w3c/csswg-drafts/issues/2627#issuecomment-386932374?
I hope the implementation of how users can define environment variables can happen at the same time or shortly after the implementation of referencing env variables.
@tomhodgins re
What would the advantage of 'custom env() variables' be ...
media queries can't use var
, because they are not attached to an element.
Use case: in css
, define --minW: 400 px;
Now wish to create a media query:
@media (max-width: 400 px) {}
Except instead of hard-coding 400 px
, use var(--minW)
. Can't.
In my case, I have a calculated "base font size" that grows/shrinks based on window width, but stops at min/max values at specified min/max width. Yeah, accessibility issues if I do this wrong, so I may end up with javascript to resolve the various inputs to this calculation, but that isn't the point here. Unless max
/min
or if ... then ... else ...
expression is added to css
, this requires media queries at the min/max widths, to override the formula. Or must use a pre-processor. or javascript. Would be nice to express it fully with css
. OTOH, TBD at what point it stops being worth burdening css
parsers with additional functionality.
I have a calculated "base font size" that grows/shrinks based on window width, but stops at min/max values at specified min/max width.
Sounds like a job for clamp()
, rather than media queries:
:root {
font-size: clamp(10px, 10vw, 50px);
}
As for using custom identifiers in Media Query conditions, though you do need to process it (either ahead of time, or at runtime) there's already flexibility in CSS to allow you to encode some nice breakpoints, and write at-rules that use those user-defined breakpoints, and interpret those at-rules as though they were media queries written for the values those custom breakpoints represent:
:root {
--breakpoints: {
"narrow": "(min-width: 300px)",
"medium": "(min-width: 600px)",
"wide": "(min-width: 900px)"
}
}
@supports (--breakpoint("narrow")) {
html {
background: red;
}
}
@supports (--breakpoint("medium")) {
html {
background: green;
}
}
@supports (--breakpoint("wide")) {
html {
background: blue;
}
}
Demo: https://codepen.io/tomhodgins/pen/yLBOyBe
So nothing else needs to be added to CSS to accomplish either the scalable font-size functionality where a scalable unit is capped with a minimum and maximum it won't go beyond, as well as the ability to encode custom breakpoint names and refer to them, though for the second one you'll need a little bit of code to help either in advance, or like my Codepen demo in the browser at runtime :D
@tomhodgins I'm not sure why you seem to be arguing against user-defined environment variables? š¤ There's no potential conflict if user-defined environment variables need to be prefixed with --
, which system-level variables would not be, and as others have pointed out, not only are there performance benefits (they don't have to trickle down and be calculated through the cascade), but they can have use-cases that custom properties don't allow. I mean, it's cool that custom props can be hacked to do some cool things / be set via scripts, but that doesn't fundamentally change that they're inherently more expensive to calculate than environment vars, because they factor in the complexity of markup and related style calculation.
I'm not sure why you seem to be arguing
Please don't think I'm arguing, nothing I'm saying here is meant like that at all! š©
I'm showing some things the platform can do, no hostility intended.
@tomhodgins Ah okay, fair enough. Sorry if I misunderstood your position!
Hello,
@tomhodgins:
I'm really interresting about your breakpoint solution. I tried your great codepen link. I also find the Houdini project with the JSON in CSS feature. Then, in this solution, we got two things.
1 - JSON in CSS with ability to access their first level property in this form : --breakpoint("narrow")
2 - @supports (min-width: 300px) inerpretation as a media query.
But...
1 - If JSON in CSS var level 1 access becomes a CSS spec, i will say Ok. But for now, it's not a CSS solution, but a JS hack.
2 - @supports's role is to test if some features are supported or not. Conceptually, it's not ilogic to consider that if window width is 200px, and html width is 100% of it, then min-width: 300px should return false. But it suppose to grow up the concept of "supported feature" in a way that will become confused. "_Is supported to assign 300px to min-width css property_" is not the same that "_is html able to get 300px width_", and should always return true if browser supports min-width CSS property written in pixels.
So
It's an elegant JS hack, and maybe i will use it (waiting for another solution). But it's not, and probably never will become, a valid CSS solution.
For variables media queries breakpoints, we can imagine two simple possibilities.
1 - media queries should tolerate css variables defined on ":root", or in another new specific selector to avoid confusion.
2 - media queries should works with env(), then we have to be able to define custom env(--constant-var).
I think the first solution may be reasonable (and then may needs another ticket if not already existing). But it's only my point of view.
Maybe something like this:
@constants {
--my-unalterable-var: my_Value_That_Is_Selector_Context_Agnostic;
--breakpoint-s: 640px;
--body-bg: blue;
}
@media screen and (min-width: var(--breakpoint-s, 300px)) { /* because constants are selector agnostic */
body {
--body-bg: red; /* no effect, because --body-bg is already a constant (then it's unalterable) */
background-color: var(--body-bg, green); /* blue, because --body-bg is simply already defined */
}
}
(if --breakpoint-s is not set as constant, then media query min-width value will be 300px)
I'm going to
1 - Search in tickets if something similar exists.
2 - Post a ticket if not.
Most helpful comment
env() is guaranteed global, which means you can store them in a much more memory-efficient whole-page data structure, rather than on each individual element like currently. (Chrome, at least, attempts to detect custom props that are set on the root element and not set anywhere else, and automatically upgrade them to such a data structure.)
env() also should be usable in further contexts outside of properties on elements, such as in MQs. This is fundamentally impossible with var().