Closed grorg closed 3 years ago
@jakearchibald I won’t contradict you :) Do you treat the keyboard overlay similarly?
The drawback being it can’t be handled with pure CSS.
@diligiant On Android & iOS, the keyboard just reduces the viewport size, you can still scroll down to the area that the keyboard may have obscured. This means visualViewport
will tell you about it. This works in Chrome today.
When @grorg mentioned "overlay keyboards", I took that to mean something that overlays the viewport, so even if you scroll right to the bottom of the page, the keyboard will still be obscuring content. In this case constant(safe-area-inset-bottom)
could give you the amount of padding you can apply to the bottom of the page to overcome this.
@jakearchibald I'll be very interested to read @grorg explanations as I have the feeling safe-area-inset-*
and visualViewport
are tackling different issues (highlighted by the fact that the former is css-oriented and the latter being js-oriented.)
@diligiant
I have the feeling
safe-area-inset-*
andvisualViewport
are tackling different issues
We agree!
If it's something that changes the size/position of the viewport, such as a keyboard, a URL bar, or a pinch-zoom, visualViewport
is what you're looking for. It is very very rare to need to change layout as the result of a viewport change (details).
If it's something that obscures content but does not change the viewport, such as physical screen shape, overscan, a picture-in-picture overlay, or an overlaying keyboard, the proposed solution is viewport-fit
and safe-area-inset-*
.
See https://developers.google.com/web/updates/2017/09/visual-viewport-api#layout_viewport_vs_visual_viewport for a description of the layout vs visual viewport. The iOS & Android keyboard changes the visual viewport, whereas the notch requires the user to adjust layout so content moves out of its way.
Again, can we please move discussion about the new iPhone's notch/corners (which isn't specific to the iPhone anyway) to another issue. It's not directly germane to the general discussion of UA-defined constants/globals.
Should there be a standardized set of constant names with an expected meaning, or is that all up to the UA? I believe @grorg's pull request only defines the mechanism, but not any specific constant names.
@othermaciej I think the names Apple intends to use should be standardised. Otherwise, it's all the problems of vendor prefixes without the minor benefit of an actual vendor prefix.
FWIW the proposed naming seems good.
@diligiant
IMHO unless Safari supports CSS Level 4 min/max at the same time, it will be tough to accommodate the complex positioning rules we have today.
Yep, we agree. See https://bugs.webkit.org/show_bug.cgi?id=167000 😄
Replying to @tabatkins
I have got a problem here, and my problem varies ;) More precisely, the values that we are discussing here are not going to be constants.
Yeah, what eeeps said - they're constant over the page, as opposed to refs that can vary from element to element.
All in all, I have not seen any argument to convince me we should invest in adding a new function instead of a namespace for existing value references.
A big difference is that these are usable in places other than properties and animations - you should be able to use these "constants" in MQs and such. (Again, because they're constant across the page, and so don't care about what context they're being used in.) I'm loathe to say "var() is only allowed on elements normally, but you can use it wherever you want if you use this particular type of var name" - much better for everyone if it's a totally distinct name.
Ok, so I gave this another round of thoughts, and I agree that I can see the value in having a different function name to make it clear the places where the replacement will work are not the same. I still think this isn't needed, but I can see the value.
I really do not like the name constant(...)
though. Really, there is no such thing as "constant at any given time". If you look at the definitions of "constant", you get either of these which both do not apply here (because the value of the variable can change over time):
adj: remaining the same over a period of time noun: a situation or state of affairs that does not change
The other thing is that this is utterly verbose. If you have to use this multiple times in a calculation, having to type constant()
is really annoying and space-filling, reducing gimpsability quite a lot.
I remember that when var(...)
was introduced, we ruled out $...
because it would conflict with css preprocessors, then also ruled out $(...)
because Tab wanted to use it for things that would replace to the same thing globally.
I think this proposal matches that description: some value replacement that happens to be globally the same (but could be globally invalidated as a result of a value change). I would therefore propose we rename these variables to "globals" instead of "constants" and use $(...)
to refer to them anywhere a css value is allowed.
Opinions?
Hmm... Are you at so worried that $ here could lead to even more confusion?
To me, the term constant()
feels like a misnomer, especially if the rule (and property and value) can be overriden by a more specific selector.
body {
color: constant(fontColor);
}
body.home {
color: red;
}
It's not looking "constant" in any sense of the word, plus it's confusing on another level with var
and const
in JavaScript existing for similar uses, but different to each other and also different to variable()
and the proposed constant()
.
The $()
syntax doesn't feel quite like anything else in CSS. The first thing that pops into my mind would be something like global()
or ua()
standing for user-agent. Consider you had never heard of the functionality of exposing browser settings to CSS before, which of the following syntax examples conjures up the idea that that's what's going on in the code:
body {
color: constant(fontColor);
background: constant(backgroundColor);
}
or
body {
color: $(fontColor);
background $(backgroundColor);
}
or
body {
color: browser(fontColor);
background: browser(backgroundColor);
}
Given these examples, the presence of constant()
without any other context makes it sound like an invariable…variable? What's that? It doesn't really make sense, if you wanted it constantly one colour couldn't you just set that in the CSS all the time? It's so wrong it feels nearly self-negating.
The second example, using $()
reads to me like a layer on top of CSS - either a preprocessor variable or something that's going to be interpolated before that text becomes CSS. This is closer to what's really going on, but my first thought is not that it's coming from the browser. If I saw that in the wild my first thought would be that somebody accidentally published some kind of Sass/Less/Stylus-like preprocessor dialect without compiling it to CSS first. My initial thought would be to google what preprocessor uses $()
as a syntax so I could compile it properly.
But given the third example, browser()
, even if you have no idea that the functionality is possible, it's CSS-like enough that it could be a native feature, and the name browser()
hints that it's nothing that could be rendered in advance…before the browser. For me at least, I think this is not only elegant enough to use while authoring CSS, but also provides the correct context to help people intuit what is going on in the code, as well as provide something 'googleable' they can look up to find out more.
That's my 2¢. This is a great idea for a feature, getting the naming right (or wrong) could be the difference between empowering authors and bewildering them.
Why not follow the idea of currentColor?
body {
color: userForegroundColor;
}
currentColor
isn't global, so it isn't really the same.
I get that, but it is a predefined value that the dev can't directly manipulate (indirectly he can in this case). The values proposed here can also change constantly (no pun intended) depending on device orientation, environment, settings, whatever, so it is merely an alias to some value defined in the UA.
The difference between currentColor and userForegroundColor is just the scope, as one uses this
and the other window
EDIT: The newly proposed system-ui
"font" or simply sans-serif
would be another example that is, in my view, the same thing as we are discussing here. currentColor might have been the wrong example to use here because it's distracting.
Why not follow the idea of currentColor/system-ui/...?
Because a browser needs to track all these values one by one, and that is costly in terms of code to write and combinations to test. The advantage of reusing the infrastructure of var(...) is that it is generic and can be detected very easily at parse time.
The second example, using $() reads to me like a layer on top of CSS - either a preprocessor variable or something that's going to be interpolated before that text becomes CSS. This is closer to what's really going on, but my first thought is not that it's coming from the browser.
If I understood @tabatkins properly, while some of these values will come from the browser, some can also come from JavaScript using the proposed $(--my-global) syntax. If I misunderstood that then my point is moot, of course,
If I saw
$(...)
in the wild my first thought would be that somebody accidentally published some kind of Sass/Less/Stylus-like preprocessor dialect without compiling it to CSS first.
Well, it's because you don't know this is allowed in CSS. That's something you would learn as part of learning CSS in the future even before you start learning about SASS.
Should there be a standardized set of constant names with an expected meaning, or is that all up to the UA? I believe @grorg's pull request only defines the mechanism, but not any specific constant names.
Yes, this isn't even a question. Without standardization, this is just vendor-specific, and thus worthless. (And thus should be protected behind whatever your vendor-specific-code mechanism is: prefixes or flags or what-have-you.)
Why not follow the idea of currentColor?
Because keywords need to be tracked and monitored for collisions; there are places where we accept arbitrary keywords (like animation-name
) where we explicitly handle the few built-in keywords (and thus implicitly disallow you from using them as animation names/etc). Every time we add a new built-in keyword, we run the risk of breaking author code that is currently using it as a custom keyword.
A function, on the other hand, can be handled globally without collision; we don't and will never allow user-defined functions with arbitrary names (they'll be --
prefixed like other custom things), so there's no worry about breaking author-level code.
I think this proposal matches that description: some value replacement that happens to be globally the same (but could be globally invalidated as a result of a value change). I would therefore propose we rename these variables to "globals" instead of "constants" and use $(...) to refer to them anywhere a css value is allowed.
I'm fine with this; it does indeed match the use-case I was trying to reserve $
for. It means some Syntax changes, tho. ^_^
Why the constant can't be used in calc? This does not meet expectations.
Yes, we can use height: 44px; padding-top: constant(safe-area-inset-top)
, but height: calc(constant(safe-area-inset-top)+44px)
is conciser, and sometimes we have no choice.
Because i using calc() with no spaces around the +
, constant can be used in calc.
Why the constant can't be used in calc? This does not meet expectations.
The constants do work in calc()
, at least in my testing in Safari on the iPhone X simulator.
header {
height: calc(44px + constant(safe-area-inset-top));
}
They also work in gradients:
linear-gradient(to bottom, black 0%, black constant(safe-area-inset-top), grey constant(safe-area-inset-top), grey 100%);
The Working Group just discussed User Agent properties and variables
, and agreed to the following resolutions:
RESOLVED: rename what was constant variables to environment variables using env()
RESOLVED: Add this as an ED of variables L2
RESOLVED: Add dino as an editor of variables L2 with TabAtkins
RESOLVED: The initial set as safe area top, bottom, left and right
@zhouqicf Your screenshots show you using calc() with no spaces around the +
; that's an error, resulting in an invalid property. constant() will have the same basic semantics as var(), so it's usable anywhere var() is.
I have a few questions.
First, I am presuming the request included making it clear “that there is no way for the developer to set these properties”. And now, I see interest in doing the opposite. which is to make these properties settable. I also see interest in making these properties exposable to @media
.
So, if these properties are settable, how do we distinguish the non-settable ones? The ol’ double-dash?
@env --foo 0px;
body {
margin: env(--foo);
padding: env(safe-area-inset);
}
That makes me wonder. If env()
is no longer the distinguishing quality of being un-settable, then could we modify var()
to support the same functionality?
@var --foo 0px;
body {
margin: var(--foo);
padding: var(safe-area-inset);
}
And if that is possible, would we need @var
at that point? Or would @var
be needed to expose variables to @media
?
Then, if these properties are assignable and also available to @media
, might they create recursion?
@env --foo 0px;
@media( width > env(--foo) ) {
@env --foo 200vw;
}
EDITED: That last example, which I accidentally left un-finished.
I notice the resolution didn't include the proposed multi-value env(safe-area-inset), is that intentional or just wasn't considered at the time?
@othermaciej https://github.com/w3c/csswg-drafts/pull/1819#issuecomment-329926347 – I agree with @grorg here. Although it works well for simple examples, it isn't as useful as I initially thought.
I guess we just have to watch out for anyone advocating patterns that would break on rotation, or future devices.
Perhaps it's too late, but I had a thought regarding the name choice. What about val()
? It's close enough to var()
that it's familiar, and has the impression that it's unsettable, and would therefore be set by some other process (the browser or what have you). It's also short.
My only issue with it would be that it is almost too similar to var()
, and might be mistakenly interchanged, though I am not convinced that this would be a major problem.
We're locked and loaded to ship env(), and there was a WG resolution on that, so we'd really prefer that it not change again.
Ah, very good. Then don't mind me!
Can anyone give me guidance on how to get at these new constant/env() properties from javascript?
@jkuss This is actually quite interesting. I believe at this moment WebKit, being the only User Agent shipped with this functionality, offers no JS API to directly obtain env
s in general. Interestingly, WebKit has listed some of the name strings (i.e., safe-area-inset-bottom
) in CSSStyleDeclaration
object at [340] ~ [343]
, but the values are inaccessible through .getPropertyValue
function unlike any other CSS property.
Being UA-specific things, it sort of makes sense that env
s belong to the unholy navigator
object. But on the other hand, I could see them being an another set of custom properties; defined by the UA not by users, so there is no reason to treat them differently from var
s.
I know this problem is right in the middle of a standardization minefield, and probably out-of-scope of CSSWG, but it doesn’t particularly seem in-scope anywhere else.
EDIT: Issue 1 of the new spec draft suggests an API should be defined on Document
.
Safari Technology Preview 49 has added support for parsing calc()
in media queries, which may be a prelude to supporting env()
in MQs as well.
Safari Technology Preview 52 has added two new ones: fullscreen-inset-top
,fullscreen-auto-hide-delay
.
@kiding any documents about fullscreen-inset-top
and fullscreen-auto-hide-delay
?
@zhouqicf I don't think so, but you can infer them from WebKit's bug tracker.
Since Chrome wants to start working on env(), but no further action has happened in the PR, I've gone ahead and written up a draft spec for the feature: https://drafts.csswg.org/css-env-1/
There are a lot of open issues that need to be addressed. It would be a great help if @grorg could take a crack at answering them here; I'll be happy to edit them into the draft. ^_^
Per... https://drafts.csswg.org/mediaqueries/#units
Relative length units in media queries are based on the initial value, which means that units are never based on results of declarations. For example, in HTML, the em unit is relative to the initial value of font-size, defined by the user agent or the user’s preferences, not any styling on the page.
Any idea on how "user’s preferences" will be interpreted, allowing media queries use of something like calc(env(user-font-size) * 20)
?
Also, this reminds me of discussion currently happening in #2430 - font-size: 'medium' value is the user's preferred font size.
tho user agents may define additional undocumented environment variables
I think this will lead to vendor-specific, or even device-specific, dialects of CSS. That seems like a very bad idea to me.
@tabatkins’ new draft specification mentions:
Because environment variables don’t depend on the value of anything drawn from a particular element, they can be used in places where there is no obvious element to draw from, such as in
@media
rules, where thevar()
function would not be valid.
I want to express that I am glad that this is still being included. There appears to be at least some community demand for this use case, as evidenced by this Stack Overflow question: “CSS native variables not working in media queries”. I myself would find them quite useful as an author.
Are there still plans to advance the spec, make envs definable by users and usable in media queries?
Are there still plans to advance the spec, make envs definable by users and usable in media queries?
Custom envs can probably be discussed in #2627, and for that to be used in media queries probably #3578.
Here is WebKit's proposal for a new type of property and variable.
User Agent Properties
This specification defines an open-ended set of properties called
User Agent properties
, which, among other things, are used to define the substitution value ofconstant()
functions.Name: (various) Value:
<declaration-value>
Initial: (nothing, see prose) Applies to: all elements Inherited: yes Percentages: n/a Media: all Computed value: specified value with variables substituted (but see prose for "invalid variables") Canonical order: per grammar Animatable: noA User Agent property is not specified in a style sheet. User Agent properties instead define variables, referenced with the
constant()
notation. For example, a page that wants to use the user's requested font sizing, and page background:Unlike other CSS properties, User Agent property names are case-sensitive.
User Agent properties are not reset by the all property. If a style rule attempts to define a value for a User Agent property, it is ignored.
Using Cascading User Agent Variables: the 'constant()' notation
The value of a
User Agent property
can be substituted into the value of another property with theconstant()
function. The syntax ofconstant()
is:The
constant()
function is used in the same manner, and follows the same rules, as thevar()
function.Defined User Agent Variables
user-font-size
: User's requested font sizeuser-background-color
: User's requested background coloruser-foreground-color
: User's requested foreground colorsafe-area-inset-top
: Inset, as a<length>
from the top of the viewport to the title-safe content area.safe-area-inset-right
: Inset, as a<length>
from the right of the viewport to the title-safe content area.safe-area-inset-left
: Inset, as a<length>
from the left of the viewport to the title-safe content area.safe-area-inset-bottom
: Inset, as a<length>
from the bottom of the viewport to the title-safe content area.