Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating the css env() function to enable selection by index from a list of pre-defined environment variables #5622

Open
zouhir opened this issue Oct 15, 2020 · 9 comments

Comments

@zouhir
Copy link

zouhir commented Oct 15, 2020

In issue #5621 we highlighted a new syntax for the media feature that was proposed to help Web developers match and insert rules that are specific to dual-screen and foldable devices, the new syntax can be extended to cover multi-screen scenarios and offers better scalability.

Detecting whether the browser viewport is spanning across 2 or more screens is only one part of the solution, the other part is informing developers about the geometry and size of each screen and while the env() function is great for exposing such hardware-specific configurations, we believe it could be extended and improved to offer better experience for Web developers.

Illustrating the problem of verbosity

Today, user-agents provide custom-identifiers that web developers pass to the env() function as a first argument to get back a value that can be assigned to numerous CSS properties. Following is an illustration of how the safe-area-inset-top custom-ident is used to help developers prevent content from being occluded by a smartphone's notch:

body {
    padding-top: env(safe-area-inset-top);
}

smartphone-notch-inset

In dual-screen and foldable devices scenarios where the browser window is spanning across more than 1 display region, the user-agent might want to expose the geometry of each display region. Today, that would be something like:

Display Region 1 Display Region 2 ... Display Region N
env(viewport-segment-1-width) env(viewport-segment-2-width) ... env(viewport-segment-n-width)
env(viewport-segment-1-height) env(viewport-segment-2-height) ... env(viewport-segment-n-height)
env(viewport-segment-1-top) env(viewport-segment-2-top) ... env(viewport-segment-n-top)
env(viewport-segment-1-left) env(viewport-segment-2-left) ... env(viewport-segment-n-left)
env(viewport-segment-1-bottom) env(viewport-segment-2-bottom) ... env(viewport-segment-n-bottom)
env(viewport-segment-1-right) env(viewport-segment-2-right) ... env(viewport-segment-n-right)

Stylistically, the solution demonstrated above to expose the display regions' geometry is verbose. Creating a list of custom-identifiers accompanied by a mechanism for web developers to retrieve values by index offers greater scalability and better ergonomics.

Proposal: CSS index() function

The index() CSS function can be used within the env() function to select one value by index from a user-agent-defined environment variables list.

Syntax and example usage

The example below illustrates how to use the browser-provided env() variables to create a 2-column CSS Grid layout, where each column's size should equal the corresponding display's width.

grid-example

HTML

<div id="grid">
    <div id="A"></div>
    <div id="B"></div>
</div>

CSS

#grid {
    display: grid;
    height: 100vh;
    grid-template-columns: env(index(viewport-segment-width 0), 1fr) env(index(viewport-segment-width 1), 1fr);
    grid-template-rows: 100vh;
}

Formal syntax

index( <custom-ident> <index-value> )

Parameters

  • custom-ident: arbitrary user agent-defined string, mdn
  • index-value: integer, with the index origin being 0 matching arrays behaviour.

Behavior

Case sensitivity

User-agent-defined property names are case-sensitive. env() respects that today and index() will not introduce any changes to that behavior.

Example:

height: env( index(display-height 0) , 700px); /* height equals the first display-region height */

height: env( index(Display-Height 0) , 700px); /* 700px, because 'Display-Height' does not match the 'display-height' property */

"2D" Screen setup

In the case we have more than 1 row and 1 column of screens, we propose flattening-out the screens matrix to a linear list where the top-left gets the index 0 followed by the consecutive screens on that row.

photo credit wikipedia

Possible future uses

Usage with env() in media query rules

env() function values can be used as a part of a descriptor such as Media Query rules; thus using env(index(ua-property 0)) is also supported.

Usage with custom properties

The index() function will initially be scoped to the user-agent-defined lists of environment variables. However, if developers in the future are empowered to create lists as custom properties values, index() function can be used with var() the same way this document proposes for use with env().

Example use-case

image007

image001-5f5fae6619385

@tabatkins
Copy link
Member

I'm not sure I understand what value the index() function is bringing here. Your proposal is for allowing an env() variable to be multi-valued, with an integer index to select one of the values; index() doesn't add anything here, and is being used with a syntax and purpose unrelated to its original proposal.

If you need something like this functionality, we can just add an optional integer to the syntax, so env(name 1) is valid and has the meaning you're sketching.

That said, I'm not sure I see how this affects the verbosity at all. All it's doing is moving the integer out of the name. I don't immediately see how this changes what the names would actually be, however - aren't env(display-segment-1-width) and env(display-segment-width 1) essentially identical?

It's possible I'm missing some important details of this proposal. ^_^

@dlibby-
Copy link
Contributor

dlibby- commented Oct 15, 2020

Reducing verbosity wasn't a goal for introducing index() — we were mainly concerned with two aspects:

  1. being able to represent the arbitrary values in spec (i.e. I don't think you could specify that viewport-segment-n-width is a variable that is potentially valid for all n)
  2. compatibility with the existing env() syntax, given that the fallback value comes after the comma.

If I'm wrong about (1) then adding the variables with permutations to the spec sounds like a reasonable path forward. Else what you proposed for extending the env() syntax to have an optional integer to the first 'argument' (before the comma) seems like a nice way to express this concept (and is less verbose than an index() function).

We were also thinking something like index() might eventually have broader applicability, say for use with var() assuming you could declare array-like variables, but again extending the syntax with an optional integer would work well in the same way.

@tabatkins
Copy link
Member

(i.e. I don't think you could specify that viewport-segment-n-width is a variable that is potentially valid for all n)

We could certainly define that. The set of names isn't directly exposed anywhere, it's just a matter of the UA looking at the name and seeing if it's defined.

say for use with var() assuming you could declare array-like variables

We could just as easily add to the var() grammar to allow var(--foo 1). ^_^

@dlibby-
Copy link
Contributor

dlibby- commented Oct 16, 2020

We could certainly define that. The set of names isn't directly exposed anywhere, it's just a matter of the UA looking at the name and seeing if it's defined.

I see. I saw #2630 and assumed the set of names would eventually be exposed, but perhaps that is not the case

We could just as easily add to the var() grammar to allow var(--foo 1). ^_^

Yep, that would definitely make sense.

In any case, I'd like to have a discussion on the merits of one vs. the other. Tagging for TPAC discussion.

@astearns astearns added this to the TPAC-2020-08-19 milestone Oct 16, 2020
@fantasai
Copy link
Collaborator

fantasai commented Oct 19, 2020

We had a discussion about representing a grid of screens as a matrix rather than a list, how would that play in with that? #4736 (comment) Wouldn't it make more sense to represent these using a dual-indexed matrix notation?

@FremyCompany
Copy link
Contributor

Just noting that my current thought would be that var(var(--theme) accent-colors 1) would be a syntax sugar for var(dark-accent-colors-1)

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Updating the css `env()` function to enable selection by index from a list of pre-defined environment variables, and agreed to the following:

  • RESOLVED: Develop a list and matrix version of variable references so that we can pull various pieces of an env() out, and the syntax we choose for these variables should match the MQ for it
The full IRC log of that discussion <myles> Topic: Updating the css `env()` function to enable selection by index from a list of pre-defined environment variables
<myles> GitHub: https://github.com//issues/5622
<myles> dlibby: A continuation of the previous discussion. Targetting dual-screen devices. Creating primitives that are more extensible to target desktops or future devices. That could be better than the original proposal. Previously we described where a fold might exist in yoru viewport, but this changes to describe segments of your viewport and their dimensions. It's probably 2 issues: 1. Whether this set of env variables makes sense, and 2. the right way
<myles> to represent it syntactically. TabAtkins replies about 2. Focusing on the env variables themselves... these would be in visual viewport coordinate system. Targetting the top level layout constructs.
<myles> dlibby: We have not yet heard use cases for integrating into the various layout submodules.
<fremy> q+ (after Tab gets an opportunity to reply)
<astearns> zakim, open queue
<Zakim> ok, astearns, the speaker queue is open
<TabAtkins> q+
<fremy> q+
<myles> dlibby: the ordering in the proposal for this issue is a row major order with a single index. Maybe there will be some discussion about whether that should be a 2-d index. -> Syntax question about whether env variables should be specified up front about the ones that are represented by the UA, or if an open-ended set of variables is sufficient for that spec.
<myles> dlibby: Our goal is to get something into the WD for css-env. But feedback on the concept / makes sense/ etc. would be appreciated.
<astearns> ack TabAtkins
<heycam> q+
<myles> TabAtkins: On the syntax question, the original proposal has an index(var name, integer) and represents an indexed variable name there. We don't' need a function, if we want a list or matrix value env variables, we can build them into the name like name-1 or name-2 but if we want to make them separable, which is reasonable, we can't target a particular screen if it's built into the ident, we can add 1 or more integers into the main argumetn part of
<myles> the [missed]
<fantasai> +1 to Tab
<myles> TabAtkins: I'm happy to add in 1+ integers after the variable name, that makes sense.
<fantasai> s/[missed]/env() function/
<astearns> ack fremy
<myles> fremy: That mostly covers the thing I was going to say.
<bkardell_> q+
<myles> fremy: One little thing: when I looked at this, one of the things you can do if you have a way of separating the numbers and the value is you can have the number be a variable. You cannot have the name of a variable be a variable. There can be use cases for that.
<myles> fremy: Why limit ourselves to integers?
<myles> fremy: Right now, the syntax for variable is [ident comma fallback]. What if instead we allowed the ident to be a list of identifiers or numbers, and then concatenate them. Then we could use variables in the name of variables, which would be cool. You could have a structure, like main color, secondary color, and then prefix them with the name of a theme, like dark-maincolor or light-maincolor, and use a variable to select which theme you're using on
<myles> an element.
<myles> fremy: Like what TabAtkins said, we don't need a function, but we can put any arbitrary ident there.
<myles> myles: Floating point values makes that tricky
<myles> TabAtkins: it would be ident | int
<astearns> ack heycam
<myles> heycam: In the proposal, there's talk of 2d screen setup. Will this work with non-mobile device situations? 2d arrangements of monitors is usually for desktop machine.
<astearns> ack bkardell_
<myles> <dlibby's connection is broken, he can't answer>
<astearns> ack fantasai
<Zakim> fantasai, you wanted to ask about viewport vs display
<astearns> q+ bkardell_
<bkardell_> q-
<myles> fantasai: 2 questions: 1. Are we distinguishing between viewport and physical display, is env() returning the value for the viewport (if you move a window on the display) how does that effect the env()
<myles> fantasai: 2. Do we want to linearize the list? Or do we want to assume a gridded layout and have a matrix w/ 2 indices, one for each axis
<myles> astearns: If we decide to use a list syntax now, can we extend that to accommodate a matrix syntax?
<myles> fantasai: It depends on what exactly we decide to do. A linear form is ... the syntax would have different needs depending on what you wanted to do. It's interesting how exactly the syntax work and how it relates to the MQ and how it relates to each other and other things in CSS. It's important that we think of these two features together. The MQ + the env()
<myles> <dlibby is back>
<myles> fantasai: 2 questions: 1. Are we distinguishing between viewport and physical display, is env() returning the value for the viewport (if you move a window on the display) how does that effect the env()
<myles> dlibby: We are querying the viewport in relation to the physical/logical display regions.
<myles> fantasai: That needs to be clear in the name.
<myles> fantasai: and in the spec also.
<myles> fantasai: With the MQ we were talking about going toward a matrix form, where you've got rows and columns. For the env(), would we want to do that here also? Or a linearized version here for some reason? Both?
<tantek> This sounds like pagination but for different shaped pages that are displays
<myles> dlibby: Perhaps having both would be useful, but the hesitation with the matrix is just for the set of hardware we know about currently, that extra metal load of the matrix-like syntax seems a difficulty for authors to get over. If there's consensus that having that consistency with the MQ.... We're amenable to having it for the syntax as well.
<tantek> Also curious if this is meant to model complex non-rectangular amalgams of displays like adjacent Times Square video screens
<myles> fantasai: It would be good if the MQ + the env() would have consistent syntax. If we need the linear version for some reason, then maybe we can look into that. But we should aim for consistency
<myles> dlibby: Okay, we can take a look.
<myles> heycam: In the proposal, there's talk of 2d screen setup. Will this work with non-mobile device situations? 2d arrangements of monitors is usually for desktop machine.
<astearns> q?
<smfr> q+
<myles> dlibby: One thing we've been referring to is a semantic mode from the window manager. If there would be a desktop OS that supports an app window going into a configuration where it has a rectangular viewport that is spanning some number of screens, we would want it to apply. But if you're moving your window between displays and happen to let go of your mouse where a few pixels are bleeding into another monitor, that doesn't feel right for the
<myles> semantics of this.
<fantasai> window manager should be snapping that, probably
<myles> heycam: It seems like you would want to know the spatial arrangement of these displays. Even in a simple situation of two halves, if they are arranged vertically or horizontally, that would change how you woudl use the env() vars. Maybe we want the matrix syntax.
<myles> dlibby: Yes, it's important, and part of a separate issue related to the media issue that fantasai alluded to earlier. The proposal: Two media features, one in X direction and one in Y direction about how many you have in a certain axis.
<myles> dlibby: As newer form factors come into existence, they can fit into that
<myles> heycam: The author would have a MQ to select on arrangement, then within that, env() to index within that
<myles> dlibby: Yes. fantasai is right that we want consistency
<astearns> ack smfr
<myles> smfr: I have a hard time evaluating these proposals b/c I don't understand the model w/r/t scrolling + zooming. When you scroll, do both screens move up and down at the same time? Is the right side showing the bottom of the left side down? Or can we do multicol thing where scrolling is <hand waves>
<myles> smfr: Or does the whole thing scroll as once? If you zoom, where is the origin? Is it all one big thing? I would like to see animated images how scrolling + zooming works.
<myles> dlibby: Okay. We can put that together. By default you have a single rectangular viewport / ICB which is the size of the rectangle, spanned across both screens. If you don't do anything special, the entire thing will scroll. The site could use the primitives that independently scroll themselves with overflow-scroll. We don't want these values to change on zoom. Similar principle on zoom - shouldn't change, like safe-area-inset. We don't want
<myles> relayouts on every zoom frame. To the exten that we can match that existing behavior we think that's a good model for these env() vars
<myles> smfr: I think it would be useful if your examples started with a simple case that didn't have a scrollable left column, and then add in teh scrollable left column wehre it makes sense to map things on to two screens.
<myles> smfr: Like a page with no columns. Wikipedia.
<myles> dlibby: At the bottom there's an example of an outlook application.
<myles> dlibby: Where it just flows across that seam or fold, across the 2 displays. It would scroll as if your viewport was just that size. This is about letting people customize that w/r/t the viewport.
<myles> smfr: I think that's fine.
<myles> astearns: I read through the proposals a few times. There's lots of layout described. Different kinds of layout across / separately. But to smfr's point, there isn't the extra stuff that he's asking for in terms of scrolling / zooming / other actions across both screens / independently. But it's a separate issue. smfr, can you raise a new issue about including more, specific examples?
<myles> smfr: Sure.
<myles> astearns: proposal: Develop a list and matrix version of variable references so that we can pull various pieces of an env() out, and resolve the syntax we choose for these variables should match the MQ for it
<myles> dlibby: That sounds like what i've been hearing?
<myles> RESOLVED: Develop a list and matrix version of variable references so that we can pull various pieces of an env() out, and the syntax we choose for these variables should match the MQ for it

@dlibby-
Copy link
Contributor

dlibby- commented Dec 11, 2020

@smfr - To expand on how scrolling/zooming works with these environment variables:

Similar to the existing safe-area-inset environment variables, these values would not change under scroll and zoom. The best summary would be that these are in client coordinates at the base zoom value of the page. Since these are intended to be used directly as values or with calc expressions, we believe not changing these under zoom and scroll will preserve the performance of interactions/manipulations.

Here are a couple examples that show a page that is not using the new variables, for illustration purposes (not pixel precise, but hopefully the ideas are clear). Note that the layout viewport is a rectangle and is agnostic to the hinge/fold. This shows a page at initial zoom, no scroll offset. The fold/hinge segments the viewport into multiple horizontal segments, which can be used as env(viewport-segment-{prop} 0 0) and env(viewport-segment-{property} 1 0), respectively.

image

After pinch zooming, the CSS pixel values stay the same, thus the values will no longer match up to the physical features of the device. This doesn't require any re-evaluation of the values or layout changes.
image

When scrolling, the values do not change as they are oriented to the origin of the client coordinate space. In this example, the viewport-segment-top environment variable values would stay the same (namely they would be 0).

image

For a site that does want to take advantage of these values, you could imagine instead creating subscrollers in each segment, which would remove the ability to scroll the root scroller.

Let me know if this answers the questions you had, thanks!

dlibby- added a commit that referenced this issue Aug 30, 2021
…ent environment variables #5622  (#6474)

This change adds the ability to index multiple dimensions via the env() syntax. Also adds the viewport segment variables, of which there are 6 values (viewport-segment-{width, height, top, right, bottom, left}), all of which have two dimensions representing their physical location in grid-like organization of the divided viewport.

Co-authored-by: Tab Atkins Jr. <jackalmage@gmail.com>
@MatsPalmgren
Copy link

Will you add some or all of the figures and accompanying explaining text to the spec? The spec text for viewport-segment-* is still rather rudimentary IMO, making it hard to understand this feature from just reading the spec.

Also, how does the various viewport-segment-* metrics relate to safe-area-inset-* metrics? For example, if there is a notch on one or more sides of a folded device. The spec says:

In certain hardware configurations, the separator itself may occupy logical space within the viewport. The dimensions of the separator can be computed by calculating the area between the position of the viewport segments.

which I read as the the viewport-segment-* describes the space inside any notches/hinges etc (which seems like it's the opposite of how the viewport size / safe-area-inset-* were defined). So, will env(safe-area-inset-*) still report non-zero values on such a device? Could you add an example of how to layout something in the "upper corner" next to the notch on such a device? Presumably I'd have to use something like margin-top: calc(-env(viewport-segment-top 0 0)), which would result in a notch-sized negative margin?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants