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

[css-values-4] Add vhc value #4329

Closed
frehner opened this issue Sep 18, 2019 · 102 comments
Closed

[css-values-4] Add vhc value #4329

frehner opened this issue Sep 18, 2019 · 102 comments

Comments

@frehner
Copy link

frehner commented Sep 18, 2019

Latest info

Added lvh, svh, dvh, lvw, svw, and dvw units.

See #4329 (comment) and #4329 (comment) for more details. 🎉

Original content below:

Background

vh is defined as Equal to 1% of the height of the initial containing block. Perhaps the current behaviour 1 2 could also be defined as

Equal to 1% of the height of the initial containing block with user agent chrome minimized.

In other words, on devices where the browser chrome changes size (e.g. mobile devices), 100vh is actually larger than the viewport when the browser chrome is maximized, and thus overflows.

A brief history of the vh unit is outlined here #4329 (comment)

Proposal

vhc (c = "with chrome", but it could be something else) could be defined as

Equal to 1% of the height of the initial containing block, with user agent chrome maximized

On devices without a changing chrome size (e.g. desktop devices), 1vh === 1vhc.

Advantages and Drawbacks

Pros and Cons list for each proposal

Original content of this section:

A drawback of vh units is that content will be cut off when (1) you load a page and (2) when you scroll upwards, while the content fits when you scroll down and the chrome is minimized.

The vhc unit would be the inverse: content would fit the page when (1) you load the page and (2) when you scroll upwards, but you would see additional content (or whitespace, depending on the implementation) when the chrome is minimized.

It also would provide a better experience than vh for games and other full-screen content that doesn't or shouldn't scroll at all.

In the end, this proposal does not completely solve the issue of 1vh needing to be different values at different times. However, it does at least give the developer a choice in which value that they want to use.

(For what it's worth, my personal preference is that I would end up using vhc units for responsive designs, because I would rather have additional content visible or some whitespace added, rather than have content cut off and not visible.)

Alternative Proposals

And a breakdown of the pros and cons of each proposal so far

Current Workarounds

As it stands, web developers that want to have a full-height website are either reliant on javascript 1 2 3 to get vh units to not cut off content, or just tend to avoid 1 using vh units altogether.

Unrelated

This is my first time proposing, so if I did something wrong or need to improve something please let me know! Thank you for your patience. :)

@frehner frehner changed the title [css-values] Add vhc value Sep 18, 2019
@frehner frehner changed the title [css-values] Add vhc value Sep 22, 2019
@frehner
Copy link
Author

frehner commented Oct 9, 2019

Another article that advocates for avoiding vh units completely because of this problem: https://chanind.github.io/javascript/2019/09/28/avoid-100vh-on-mobile-web.html

@fantasai
Copy link
Collaborator

Agenda+ to make everyone read the article linked above. This is bad and we should do something about it; I'm less sure about what.

@rachelandrew
Copy link
Contributor

Is this behavior ever useful? Should it not be the case that if the size of the viewport changes, by way of scrollbars or due to browser chrome appearing, the size of the initial containing block changes. Or is there something special about this URL bar?

@frehner
Copy link
Author

frehner commented Oct 10, 2019

This is bad and we should do something about it; I'm less sure about what.

Agreed! As noted, my proposal doesn’t really solve the issue, but it does at least offer choice and perhaps a better default than how vh currently behaves.

But if someone comes up with a solution that makes the vh unit itself useful again I would be all for it!

Should it not be the case that if the size of the viewport changes, by way of scrollbars or due to browser chrome appearing, the size of the initial containing block changes.

That’s actually how vh units initially behaved! But it turns out that it’s a horrible UX because content would actually move/change size as you scrolled. So Safari (and later Chrome) both agreed that just fixing it to a single height would be the better UX - feel free to take a look at the two citations in my first paragraph.

@rachelandrew
Copy link
Contributor

I'm thinking that the issue is that we really need a good default for vh as it stands that doesn't cause data loss, because a lot of web developers do not test very comprehensively on mobile devices, instead they will drag their window small or use RWD browser tools that cause a small viewport. These methods won't highlight the appearing chrome problem you describe. It would be better to have the default for vh be unable to cause data loss even if that caused content to shift, and then add the thing people can opt into that does the other behavior. As the people opting in then presumably know what they are doing. However maybe that ship has sailed.

@frehner
Copy link
Author

frehner commented Oct 10, 2019

I'm thinking that the issue is that we really need a good default for vh

Agreed; I would love for vh to be useful again.

However maybe that ship has sailed.

Yeah, I think it has unfortunately. There have been issues opened for both browsers for years and all have been closed saying the current behavior is intentional.

@tabatkins
Copy link
Member

vh doesn't pay attention to scrollbars, so that it can be a computed-value time unit and not depend on layout.

But nothing stops vh from responding to UA chrome hiding/showing. That's not a content-based decision, it just happens as a result of user interaction. It means we have to invalidate as the chrome disappears, but otherwise is not problematic. I think we can just clarify that the viewport units should do so.

@tabatkins
Copy link
Member

Further question: should it respond to on-screen-keyboard showing/hiding? I suspect the answer is no, but I'm not sure what answer is most consistent.

@AmeliaBR
Copy link
Contributor

should it respond to on-screen-keyboard showing/hiding?

I would say that yes, any feature for adjusting to URL bar show/hide behavior should also include the keyboard and any other pop-up/pop-over browser widgets that cover part of the layout viewport. Example use case: if the UI consists mostly of a large text box, it's nice to make that fill most of the window. It's less nice if the box gets covered up by the keyboard you're using to type in it, and you end up with a scrolling text box inside a scrolling window.

An alternative to adding new units would be to expose environment variables for the size of the obscured region on each side of the screen. Or maybe, include this type of obscuring in the "safe inset area" variables that are already defined.

@frehner
Copy link
Author

frehner commented Oct 15, 2019

I think we can just clarify that the viewport units should do so.

sorry, can you clarify what you mean by this? Are you proposed that vh units go back to the original behavior of changing the value of 1vh based on UA chrome?

If so, I don't think that is a better solution than the current situation -- that's how it behaved originally and it was a worse experience than what we have now. :)

(If not, sorry, can you explain what you mean? I apologize)

An alternative to adding new units would be to expose environment variables for the size of the obscured region on each side of the screen. Or maybe, include this type of obscuring in the "safe inset area" variables that are already defined.

I think that would put us back at the original behavior of vh units, which means that content actually changes size (and thus can shift underneath the user) when you scroll, right? Or am I misunderstanding your proposal?

@tabatkins
Copy link
Member

If so, I don't think that is a better solution than the current situation -- that's how it behaved originally and it was a worse experience than what we have now. :)

Hm, I'm confused then. In what situations would it be worse? Naively, I'd think that it's the best of both worlds, neither under- nor over-flowing regardless of how the chrome is displayed.

I think that would put us back at the original behavior of vh units, which means that content actually changes size (and thus can shift underneath the user) when you scroll, right? Or am I misunderstanding your proposal?

Ah, hm, is this the issue? It's really better to have something over or underflowing than have things possibly shift when the user scrolls?

@frehner
Copy link
Author

frehner commented Oct 15, 2019

Ah, hm, is this the issue? It's really better to have something over or underflowing than have things possibly shift when the user scrolls?

Correct! At least, that's what Safari and Chrome teams agreed as well. Here's a brief history of vh units:

  1. vh units are added to browsers. 1vh changes values depending on UA chrome sizes. This is a bad UX because content is constantly shifting as a user scrolls up and down the page.
  2. Safari changes the value of 1vh to be whatever the height when UA chome is minimal. Here's a quote on their reasoning, around 2015:

This is completely intentional. It took quite a bit of work on our part to achieve this effect. :)

The base problem is this: the visible area changes dynamically as you scroll. If we update the CSS viewport height accordingly, we need to update the layout during the scroll. Not only that looks like shit, but doing that at 60 FPS is practically impossible in most pages (60 FPS is the baseline framerate on iOS).

It is hard to show you the "looks like shit" part, but imagine as you scroll, the contents moves and what you want on screen is continuously shifting.

Dynamically updating the height was not working, we had a few choices: drop viewport units on iOS, match the document size like before iOS 8, use the small view size, use the large view size.

From the data we had, using the larger view size was the best compromise. Most website using viewport units were looking great most of the time.

  1. Chrome follows suit about a year later

So, that's how we got here -- vh units used to change dynamically, then it was determined that was horrible (and honestly it was), but now we're left with a vh value that only reflects the larger view size but not the small view size, which makes full screen designs difficult to work with.

@AmeliaBR
Copy link
Contributor

Ah, I hadn't realized you wanted vhc to always represent the minimum viewport height (minus the pop-up chrome), even when that chrome isn't current visible.

So there are three distinct use cases:

  • A stable layout that exactly fits the full viewport with minimized chrome.
  • A stable layout that exactly fits the viewport when pop-up browser chrome is displayed.
  • A dynamic layout that always exactly fits the current viewport, regardless of how many browser widgets are surrounding it.
@frehner
Copy link
Author

frehner commented Oct 15, 2019

Ah, I hadn't realized you wanted vhc to always represent the minimum viewport height (minus the pop-up chrome), even when that chrome isn't current visible.

So there are three distinct use cases:

  • A stable layout that exactly fits the full viewport with minimized chrome.
  • A stable layout that exactly fits the viewport when pop-up browser chrome is displayed.
  • A dynamic layout that always exactly fits the current viewport, regardless of how many browser widgets are surrounding it.

Seems like a great summary, yes! Thank you.

I think everyone hoped that one css unit (vh) could work for all those cases (and honestly it would be awesome if it did), but I'm not entirely sure what that would look like or how it would work.

So I proposed an additional unit instead :D

@hiikezoe
Copy link

* A stable layout that exactly fits the viewport when pop-up browser chrome is displayed.

If the vhc means this, it would be confusing. vhc sounds the height includes the browser chrome's height.

Also, I guess the units people really wants is the visual viewport size instead of the layout viewport.
CCing @bokand

@bokand
Copy link
Contributor

bokand commented Oct 16, 2019

I initially argued that vh should reflect the minimum possible size but didn't get a response from WebKiters so decided that the larger size and compat with Safari was preferable to a saner default but incompatibility with Safari.

Also, I guess the units people really wants is the visual viewport size instead of the layout viewport.
CCing @bokand

I don't think so. The visual viewport is conceptually detached from layout. i.e. if the user zooms in, the visual viewport shrinks. So we don't ever want layout to depend on visual viewport properties.

I think having a new unit for the minimum possible size sounds fine, or exposing the browser chrome insets instead as @AmeliaBR mentioned (I think that's equivalent to this proposal) which might be easier to explain.

I would say that yes, any feature for adjusting to URL bar show/hide behavior should also include the keyboard and any other pop-up/pop-over browser widgets that cover part of the layout viewport. Example use case: if the UI consists mostly of a large text box, it's nice to make that fill most of the window. It's less nice if the box gets covered up by the keyboard you're using to type in it, and you end up with a scrolling text box inside a scrolling window.

Chrome on Android today resizes the ICB when the keyboard comes in. I think it's a rather regrettable decision since resizing the ICB can take a long time - it's a significant source of making the mobile web feel janky. In addition, it's not uncommon to tap on an editable only for the resized layout to now obscure the box you're trying to type into.

We've had success on ChromeOS using a model where the onscreen keyboard shrinks the visual viewport but leaves layout unchanged. Anecdotally this works much better: the user can still pan around the full viewport but the layout doesn't change at all when the keyboard comes up which works much better, especially on sites that didn't give much thought to onscreen keyboards. Unfortunately it's a difficult thing to bring to Android because of compat so we haven't been able to do it yet.

@frehner
Copy link
Author

frehner commented Oct 16, 2019

or exposing the browser chrome insets instead as @AmeliaBR mentioned (I think that's equivalent to this proposal) which might be easier to explain.

My only concern with that is: does the size of the inset change as the UA chrome changes size? If so, that feels like we would actually just be back at the initial behavior of vh units, and we wouldn’t have solved anything. But if they remain the same value even as UA chrome resizes, then I think that’s a good alternative to a vhc unit

@frehner
Copy link
Author

frehner commented Oct 16, 2019

though thinking about it, I'm curious how it would work. If there's 1 value that changes, then that's not good.

If there are 2 values (e.g. something like inset-ua-chrome-small and inset-ua-chrome-large), what would it take to get a full-height element?

For example:

height: 100vhc;

vs

height: calc(100vh - env(inset-ua-chrome-small) + env(inset-ua-chrome-large));

If I'm understanding the proposed env variable correctly - but it's entirely possible I'm not, though.

@bokand
Copy link
Contributor

bokand commented Oct 17, 2019

My recommendation would be the inset is a "collapsible height", i.e. how much the UA might expand as a result of scrolling.

In this case, this would be the full URL bar height, regardless of whether that's showing. So the full height would be:

height: calc(100vh - env(inset-collapsible-height))
@frehner
Copy link
Author

frehner commented Oct 17, 2019

Ah ok, yeah, that’s not too bad. Personally I would prefer to use a vhc unit (easier understand and teach, and if you have to use that value itself in a calc then it is much simpler than having to do nested calcs - unless you then put it in an custom property or something) but I wouldn’t be opposed to it if that’s what’s decided is better.

I also think you’ll find more developers using vhc (or equivalent) over vh so it would be nice if it were simple, but I have no hard evidence of that -- except for all the articles that say "avoid vh on mobile devices" :P

@frehner
Copy link
Author

frehner commented Oct 17, 2019

I was talking in slack with someone, and they proposed an alternative idea.

What if the behavior of vh could be determined in a dynamic way, similar to box-sizing? For example

.container {
  vh-sizing: expanded-viewport-height;
  height: 100vh;
}

with vh-sizing options potentially being something like

  • collapsed-viewport-height (the current behavior of vh)
  • expanded-viewport-height (the desired behavior of a vhc unit)
  • exact-viewport-height (a unit that would always match the viewport exactly, even with keyboards or other UA chrome)

(all of these are just placeholder names)

With this pattern, the developer has options for all three use cases as noted by @AmeliaBR here, while also still being able to use vh in a backwards-compatible way with "progressive enhancement" (probably not the right word for it but I hope the idea comes across).

I thought it was a novel enough idea, and the backwards and forwards compatibility aspect of it made it interesting enough for me to add here for feedback as well.

@fantasai
Copy link
Collaborator

My concern here is that as long as vh itself is defined to be too big when browser chrome is present, sites developed on desktop using emulation or just narrow window sizes will be designed using the existing viewport units, and not work correctly on mobile. Critical information will be beneath the "fold" in these cases. I agree that the vh unit needs to be stable as the user browses the page, but it seems to me that it would be safer (more consistent with the “avoid dataloss” principle) if the vh unit was tailored to the more conservative size, that corresponds to the size on initial page load. If we then also need a unit that corresponds to the fully-retracted UI's viewport size, then we can add an additional unit for that; but imo the default behavior should be the safer one if possible.

@frehner
Copy link
Author

frehner commented Oct 23, 2019

I agree that the vh unit needs to be stable as the user browses the page, but it seems to me that it would be safer (more consistent with the “avoid dataloss” principle) if the vh unit was tailored to the more conservative size, that corresponds to the size on initial page load. If we then also need a unit that corresponds to the fully-retracted UI's viewport size, then we can add an additional unit for that; but imo the default behavior should be the safer one if possible.

I agree; I think @bokand also mentioned that they (blink) would have preferred that to be the default here. Unfortunately, webkit adopted the opposite and now it's standard.

I think in an ideal world we could change the default behavior of vh, but then you have the potential to break the layout of tons of websites that relied on the old (current) size of vh. In other words, it isn't a 100% backwards compatible change.

Which is why I find the solution I listed above compelling, because it is 100% backwards compatible while also allowing new functionality for devs that opt-in to the new behavior.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Add vhc value.

The full IRC log of that discussion <dael> Topic: Add vhc value
<dael> github: https://github.com//issues/4329
<fantasai> https://chanind.github.io/javascript/2019/09/28/avoid-100vh-on-mobile-web.html
<dael> fantasai: Topic is not add a vhc as much as it is solve the problem. Issues is that on mobile we have multiple notions of viewport. viewport units are defined in regards to viewport but on most browsers there's a disappearing address bar
<dael> fantasai: To avoid content from constantly shifting have made that not respond to appear/disappear of address. Problems is deaults being impl makes viewport behavior where 100vh assumes address bar is not visible. THat's not initial state.
<dael> fantasai: Lots of websites design to fit within visible are upon a page load or to have things visible/invisible upon load. Getting that things supposed to be on screen using vh are not visible due to changing height.
<dael> fantasai: Need to solve the problem. Multiple options, could take multiple of them.
<dael> fantasai: Want to hear what others thing
<dael> AmeliaBR: Recap proposals from issue. 1 is don't add any new syntax but encourage any browser with the disappearing nav bar effect to size vh to value when chroma is visible.
<dael> AmeliaBR: Sometimes you'l have more than 100vh visible but on initial load it will fit the screen. That's a guidance to UA without changing language
<dael> AmeliaBR: Original posted suggested alternate unit proportional to the smaller viewport
<dael> fantasai: Third is make the current vh unit to fit the initial load and then add a unit that allows author to take full height of viewport if they want. Inverse of the initial proposal
<dael> fantasai: Problem with that is current keyword is the safer value
<fantasai> s/Problem/Advantage/
<dael> AmeliaBR: Final option is to not add a unit and then add environment variables for disappearing effect so it's similar to inset variables
<dael> florian: Another aspect to problem; it's not just the title, but appearance and disappearance of keyboard. Currently keyboard resizes viewport, but maybe that should only change visual viewport. That's a good idea, but title bar can't do that
<dael> smfr: I don't htink we should derail with keyboard. What you described florian is iOS where it does not change layout height
<dael> florian: If you think it's separate let's keep that out
<dael> smfr: Did any proposals include a unit that changes value when chroma hides? vh that changes
<dael> smfr: It's an option
<dael> TabAtkins: From author feedback they do not want that becaues layout jiggle while it moves
<dael> AmeliaBR: Doesn't behave nicely with things that disappear on scroll. For UX and rendering reasons. For other things like keyboard where it's more discrete it's reasonable.
<dael> smfr: I'm all for avoiding layout jiggle. Seems that pages may be designed such that chrome disappears when you're at bottom
<dael> florian: I think it would be weird to build a page that way
<dael> jensimmons: This is something I've heard a lot, the sentements in this issue. Like many parts of CSS the loudest voices can be most negative. We shoudl work on this and give consideration for all use cases and not jump too quickly and not resolve quickly for what loudest voices say. I'd be happy to work on this and think it through. We need to think about how to animate if they want that. This is more complex. But we should tackle
<jensimmons> +1 to everything should match
<dael> smfr: Related all would match, 100vh, 100% body, window.innerHeight would all mean same thing. Currently don't. Don't know if they can but ti should be a goal
<dael> smfr: Do we know if Andriod has a similar behavior to iOS where 100vh is the chrome hidden state?
<dael> fantasai: Blink has 100vh and 100% on html body meaning different things. 100vh matches Safari. They would like 100% html match but that's currently being a work around for vh not considering address bar
<dael> fantasai: One of the devs that worked on this in Blink said they wanted to argue for 100vh not including address bar but they had to match Safari
<dael> AmeliaBR: Seems like WG took approach for UAs to fill in details and each browser took a different approach and it's not really working and we should come in and specify, but with a range of options for authors so they can do what they want
<AmeliaBR> s/AmeliaBR/jensimmons /
<dael> astearns: Anything else on this to discuss or do we have jensimmons work on the use cases to consider?
<dael> fantasai: I'm happy to kick it to jensimmons to think. It's important and we should not drop, but we can talk later
<dael> astearns: Anything else people want added to discussion?
<dael> astearns: I think smfr list of things that should be eq is excellent
<dael> AmeliaBR: Another option on issue was someone suggesting box sizing like property where authors choose what vh units are relative to. It's another thing to think of
<dael> fantasai: Probably 2 pairs of units would be cleaner and less likely to result in accidental errors
<dael> myles: 2 units might be better cause can use both at the same time. Mode switch you can't use both at same time
<dael> AmeliaBR: Good arguments.
<dbaron> Using both at the same time is probably very hard to do correctly, though.
<dael> AmeliaBR: Lots of options and use cases. Getting through pros and cons for each sounds sensible
<dael> astearns: Let's continue in GH. jensimmons I'll assign it to you?
<dael> jensimmons: Okay
<dael> astearns: We'll discuss again on the call when it's at a good point.
@johncrim
Copy link

johncrim commented Jun 21, 2021

I'm a fan of the new units, I think they make sense as spec'ed. I think the complaints I'm seeing about proliferation of CSS units are understandable, but they overlook the fact that today 100vh isn't useable on mobile without a bunch of additional work.

However, I don't think this problem can be solved in a satisfactory way without also dealing with the visible viewport when the on-screen keyboard appears. Today iOS browsers display the on-screen keyboard over the bottom of the viewport, and Android/Chrome shrinks the viewport to appear above the keyboard.

To provide a concrete example, if you were to define this CSS class using the proposed units:

.bottomQuarter {
  position: fixed;
  top: 75dvh;
  height: 25dvh;
  width: 100vw;
}

It would be hidden by the on-screen keyboard on iOS, and would appear above the keyboard on Android/Chrome. The same problem occurs if you define it using:

.bottomQuarter {
  position: fixed;
  bottom: 0;
  height: 25dvh;
  width: 100vw;
}

Or using units available today:

.bottomQuarterish {
  position: fixed;
  bottom: 0;
  height: 25vh;
  width: 100vw;
}

For additional background/sympathy: To workaround the browser chrome retraction and on-screen keyboard issues today I use the window.visualViewport.resize event (when supported, otherwise window.resize), and set CSS variables that are equivalent to dvh/dvb. I also detect viewport resizes, determine if they look like a "keyboard is showing/hiding" resize, then check whether an input or text area is active (to classify it as a keyboard resize); and then I compare a hidden 100vh element to the viewport height to determine if a --keyboard-height CSS var needs to be set on iOS so that elements that should appear above the keyboard need to be adjusted vertically.

In short, for this to be useful, we also need something like env(keyboard-height) and env(keyboard-active) variables.

@johncrim
Copy link

johncrim commented Jun 22, 2021

Thank you @fabb - I hadn't seen that. The Virtual Keyboard API proposal looks excellent to me.

My revised points are:

  • The CSS developer ergonomics of positioning/sizing using virtual keyboard environment variables and the proposed browser chrome-aware viewport units should be considered. They will often be used together.
  • Both proposals are limited in usefulness without the other.
  • It should be stated that env(keyboard-inset-bottom), env(keyboard-inset-top) and env(keyboard-inset-height) exclude browser chrome.

I think my previous example can be used to illustrate this. Consider an element that occupies the bottom quarter of the visible viewport, and that remains visible above browser chrome, and above the virtual keyboard. And, the Virtual Keyboard proposal and viewport relative lengths are in place. And, we want it to work on browsers that don't support the 2 new proposals. The CSS would look like this:

.bottomQuarter {
  position: fixed;
  bottom: 0;
  bottom: env(keyboard-inset-bottom, 0px);
  width: 100vw;
  width: 100dvw;
  height: 25vh;
  height: calc(25dvh - env(keyboard-inset-height, 0px)/4);
}

I think this CSS is fine, but there's a case for adding environment variables for browser chrome offsets too. We will hopefully have environment variables for safe areas, virtual keyboard borders, and foldable device screens; for completeness it seems like collapsing browser chrome offsets should be added.

@johannesodland
Copy link

@tabatkins and I just committed the changes for this. We named the unit sv* (small viewport) and also added dv* (dynamic viewport) per #6113
The changes should show up in the ED soon: https://drafts.csswg.org/css-values-4/#viewport-relative-lengths

It is so good to se progress on this issue. Thank you!

The floating browser chrome of Safari 15 might introduce some new complexity. There is some ambiguity towards what could be considered the large and the small viewport. There are suddenly not two but three sizes that are of interest:

When browser chrome is floating:

  • The height of the whole screen including the area behind and below the floating chrome (the largest area)
  • The height of the area above the floating chrome (the smallest area)

When browser chrome is collapsed in the bottom:

  • The height of the area above the collapsed browser chrome

I would expect the large viewport to be the area behind the floating chrome. If I were to use the units to size images to fill the entire screen, this is the area I want to fill, even though there is browser chrome floating above.

The small viewport though, would that be the area above the floating chrome (the smallest area), or the area when the browser chrome is collapsed at the bottom of the screen?

@jonjohnjohnson
Copy link

jonjohnjohnson commented Jul 1, 2021

@johannesodland it seems the webkit team is currently toggling the value of safe-area-inset-bottom based on the browser chrome being collapsed or not.

https://twitter.com/jrigerl/status/1402042192160493569

@johannesodland
Copy link

@johannesodland it seems the webkit team is currently toggling the value of safe-area-inset-bottom based on the browser chrome being collapsed or not.

https://twitter.com/jrigerl/status/1402042192160493569

They seem to toggle both vh and safe-area-inset-bottom. These are the values I get on the iPhone 11 Pro simulator:

When browser chrome is floating
100vh = 768px
env(safe-area-inset-bottom) = 112px

When browser chrome is collapsed at bottom
100vh = 716px
env(safe-area-inset-bottom) = 0

There are essentially three sizes here:
768px – height behind the expanded/floating interface
712px – height when interface is retracted
656px – height above the expanded/floating interface

I can se a few issues here:

Fixed and stable
The spec declares that the large and the small viewports are fixed and stable. This is what mobile browsers have converged on for vh, but Safari 15 seems to reintroduce a dynamic vh that toggles when UA interfaces are expanded or retracted. This might cause issues with reflow, which was the reason browsers moved to a fixed vh unit in the first place: https://developers.google.com/web/updates/2016/12/url-bar-resizing

Defining the large viewport
The spec defines the large viewport as such: "... the large viewport size: the viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be retracted. "

The issue here is that with Safari 15 you now get the largest viewport when the UA interfaces are expanded and floating above the viewport, not when it is retracted. It's the opposite of most current mobile browsers.

Defining the small viewport
One of the motivations for the small viewport is apparent in the example: "An element that is sized as height: 100svh, for example, will fill the screen perfectly, without any of its content being obscured, when all the dynamic UI elements of the UA are shown."

The smallest area where nothing is obscured is the area above the floating interface. If svh maps to this area you would be sure no content is obscured. But then you would have no way to reference the area with the UA interfaces retracted.

It could be more sensible to map svh to the height when the UA interfaces are retracted. This is the size that is most common when users are interacting with the page, and it also maps to document.documentElement.clientHeigh and height: 100% inside the root element. This would make content fit perfectly into the viewport when it is at it's smallest, but would not solve the "no content obscured" use case.

I think the spec might have to deal with floating UA interfaces. A also believe that is needs to address that the viewport can be at its largest when UA interfaces are visible, and the smallest when UA interfaces are retracted. This is the complete opposite of how it is in most browsers now.

@jonjohnjohnson
Copy link

Safari 15 seems to reintroduce a dynamic vh that toggles when UA interfaces are expanded or retracted

Since iOS Safari seems to have changed in a way that won't comply with these new spec changes and I just remembered that smart banners possibly affect viewport units, we might need some webkit eyes on this? @smfr?

@frehner
Copy link
Author

frehner commented Jul 3, 2021

@jensimmons could potentially also provide some insight as well?

@frehner
Copy link
Author

frehner commented Jul 7, 2021

I wanted to see for myself and verify what @johannesodland posted above, and here are my thoughts/observations (that are mostly just a rehash of what Johannes said above):

Using this page as a playground https://codepen.io/afrehner/full/MWmyZEq and having downloaded the XCode 13 beta in order to get access to the mobile version of iOS 15's Safari, I was able to take this video:

iOS15-vh.mov

Observations:

  • On page load, vh == lvh == (vh as currently defined)
  • After ~1 second without any user interaction, vh == svh
  • Scrolling downward, vh == svh
  • Scrolling upward or tapping anywhere, vh == lvh

Essentially, Safari is now treating vh == dvh, and with that, all the good AND bad that comes with it. For example, notice the amount of layout shift when looking at section four; because all the content above it is using (d)vh, when the value of vh changes, four dramatically shifts where it is. This will only get worse the more content above you that uses the (d)vh value. We're now (kind of) back to where we were in the beginning, with vh being dynamic!

I think, more than anything, this emphasizes the importance of getting the s/d/l *vh units standardized soon, so that browsers vendors can experiment with their interfaces while allowing developers to build websites that won't be changing on them over time.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Values and Units L4, and agreed to the following:

  • RESOLVED: "dynamic" viewport does indeed use units, not env()
  • RESOLVED: Add lvh as explicit "large viewport" unit
  • RESOLVED: vh/etc are deliberately UA-defined
The full IRC log of that discussion <fantasai> Topic: Values and Units L4
<TabAtkins> ScribeNick: TabAtkins
<fantasai> github: https://github.com//issues/4329#issuecomment-863677668
<TabAtkins> fantasai: Tab and I comitted the changes for our earlier resolution on these joint issues (this and next)
<fantasai> https://github.com//issues/6113
<Rossen_> q
<TabAtkins> fantasai: we resolved to add viewport units to represent the "small" and "dynamic" viewport
<TabAtkins> fantasai: there are a couple open qustions still
<TabAtkins> fantasai: One was whether dynamic should be a unit or an env()
<TabAtkins> fantasai: We went for unit based on comments from Rachel Andrews that it would be easier to teach
<TabAtkins> fantasai: Main reason for env() was to deliberately make it more awkward to use.
<TabAtkins> fantasai: Right now tho, the draft is using units; we can reopen that discussion if people wish
<TabAtkins> fantasai: Other question is we have an unprefixed set of units (vw/etc) and two prefixed sets (svw/etc, dvw/etc)
<TabAtkins> fantasai: Do we want an explicit set of "larger" prefixed units for symmetry?
<TabAtkins> fantasai: And if we do that, should we allow the unprefixed values to do something smarter? Right now they're the larger viewport, but this causes some troubles and browsers might want to do something smarter.
<TabAtkins> fantasai: So do we want to give CSS some flexibility for the unprefixed units?
<TabAtkins> fantasai: So first quesiton to tackle: anyone want us to switch the dynamic units to being an env()?
<TabAtkins> jensimmons: I think it works well as a unit. Authors will need and use it, and having it be the same as the other units will make it much easier to use.
<florian> +1
<miriam> +1
<rachelandrew> +1
<TabAtkins> Rossen_: Do we ahve a particularly well-defined guidance on how and when to add value types vs env()? It woudl be unfortunate if we end up in a situation where scrollbar-width is in an env() but viewport-width is in a unit, etc
<TabAtkins> fantasai: We don't have this written down, but the basic principle is if you're likely to want multiples of this other than 1.
<TabAtkins> fantasai: Like for safe-area-inset, you don't want 30% of it, or 5x that.
<TabAtkins> fantasai: You might add some more length to it, some extra px or something, but very unlikely to want to multiply it by a number.
<TabAtkins> fantasai: But for viewport units it's very common to want 50vh/etc, so it makes more sense to be a unit where it's easier to do that
<TabAtkins> Rossen_: I can see how this could make sense from a usage pov
<TabAtkins> Rossen_: At the same time I could argue the inset should be a unit regardless of whether you'd want it to be x1 or not
<TabAtkins> florian: Other factor is if the value depends on where you are in the tree, it must be a unit. If it doesn't, either works.
<TabAtkins> florian: For example, width of scrollbars cannot be an env() because it changes based on the unit you're applying it to.
<TabAtkins> emilio: Having units depend on computed values of properties is kinda sketchy...
<TabAtkins> florian: Sure, but still like having font-size expressed in an env() doesn't make sense, so you need em
<bmathwig> width of scrollbars can't change depending on element, it's fixed in most UA implementations
<TabAtkins> emilio: Sure, tho there's only two scrollbar widths. Could still be done as two env()s
<TabAtkins> plinss: I don't feel too strongly, but I'm a little concerned about proliferation of units.
<florian> bmathwig, see https://drafts.csswg.org/css-scrollbars/#scrollbar-width
<TabAtkins> plinss: If the non-unit syntax ends up unwieldy, we can work on that.
<TabAtkins> Rossen_: Basically same for me. I'd also like us to formulate a more general reasoning for when to use units vs env()
<bmathwig> auto | thin | none only applies to classical scrollbars and not overlay scrollbars that have zero-width in layout computations
<TabAtkins> Rossen_: But overall I don't object.
<bmathwig> Blink is moving towards overlay scrollbars on Windows in the next few months
<TabAtkins> fantasai: Okay so it sounds like we should resolve on dvh being units
<fantasai> bmathwig, that doesn't change the matter of the width of the scrollbar, only how much space it takes up in layout
<TabAtkins> RESOLVED: "dynamic" viewport does indeed use units, not env()
<TabAtkins> fantasai: So next is about unprefixed units.
<TabAtkins> fantasai: Do we want an explicit large-prefixed set to go with the others?
<TabAtkins> jensimmons: been a lot of convo on WK team last week about how these work
<TabAtkins> jensimmons: We feel very strongly there should be an lvh unit
<TabAtkins> jensimmons: And the vh unit should no longer be defined as longest length; it should instead be something more flexible that the UA can decide on based on what they're doing with their particular browser
<bmathwig> fantasai, very true
<lea> I'm all up for making vw/vh more useful, but how web compatible is this change?
<TabAtkins> florian: I see why you'd want the flexibility for this, to provide best UX possible, I'm concerned about variance in behavior that would cause content to be off-screen in one browser, etc.
<TabAtkins> fantasai: tbf that's already happening today
<TabAtkins> jensimmons: Lea made a comment about webcompat, that's absolutely a concern
<lea> q?
<TabAtkins> jensimmons: I think having this be flexible so UA can make the best decision to present the fewest compat problems
<TabAtkins> jensimmons: And by giving authors the explicit lvh and others let them choose the right one for their website
<florian> I'm sold :)
<lea> +1 for this change from me
<TabAtkins> jensimmons: But browsers may need flexibility to redefine that vh itself based on individual pages
<fantasai> +1 from me also
<TabAtkins> emilio: I think any change to vh should probably be a [...? missed]
<TabAtkins> emilio: I think we want a definition in the spec we can implement interoperably
<emilio> s/be a ?/ consider compat, but...
<TabAtkins> fantasai: So I think we have agreement to add "large" viewport units, make vh/etc ambiguous at the moment (and gradually make it clear what this actually means)
<TabAtkins> fantasai: So for now we say it's UA-defined and it must fall in the range of svh and lvh
<TabAtkins> florian: Also a note that if any UA uses the flexibility to make it something other than the three explicit ones, come back to the group and spec it
<TabAtkins> emilio: Can we file an issue to explore the compat of vh/etc?
<TabAtkins> fantasai: We should also have an issue about what is the ICB in these cases, and that's probably the same
<florian> s/and spec it/so that we can see if it is something we could spec/
<fantasai> s/probably the same/probably should be the same as the unprefixed units/
<TabAtkins> jensimmons: I noticed in the discussion there was some discussion about the "l" standing for "layout viewport", but I like it better to be "longest"
<florian> +1 to s/d/l as the naming
<TabAtkins> fantasai: Earlier we were thinking we'd use an "l" prefix for the dynamic one. Now we're gonna do small/large for s/l, or short/long, whichever you prefer to talk about
<TabAtkins> RESOLVED: Add lvh as explicit "large viewport" unit
<TabAtkins> astearns: So second is about redefining vh
<TabAtkins> fantasai: Currently the spec is actually extremely vague
<TabAtkins> fantasai: it just says "it's the size of the viewport"
<TabAtkins> fantasai: So the resolution here would be to maintain the ambiguity
<TabAtkins> florian: Maintain ambiguity or explicitly say it's UA-defined?
<TabAtkins> fantasai: I'm fine with either
<TabAtkins> florian: I'd prefer UA-defined with the note i said earlier
<TabAtkins> florian: About UAs reporting to the WG if they do somethign creative
<TabAtkins> astearns: Any objections?
<fantasai> scribe+ TabAtkins
<TabAtkins> RESOLVED: vh/etc are deliberately UA-defined
<TabAtkins> fantasai: That should be it for this issue, tho we need to open that issue about the nuances of vh
<TabAtkins> astearns: I'd encourage people to file new issues for any further discussions, these issues got long and intertwined and it'll be easier with new issues
@jensimmons
Copy link
Contributor

Thank you to everyone expressing interest in and concern about what Safari for iOS15 is going to do. Yes, in the first few betas Safari was experimenting with changing vh to work like the new dvh unit. We are still working out the details of how the new Safari will work. Future betas will test other choices until we figure out what's best. It's too early to assume what you see in beta is what will ship in the fall.

@TimmiX88
Copy link

TimmiX88 commented Jul 14, 2021

@jensimmons Glad to see it's on the radar at the Safari team. I do hope that you will stay in touch and collaborate with the people behind other browsers to come to very consistent, standardised implementation in all browsers. This whole issue was created because some browsers showed unexpected behavior when using 100vh compared to others.

It would be a such a shame if all these years of struggle, discussions, finding hacks to make things work cross-browser and now finally introducing additional units to really fix the issue, if afterwards behavior still isn't the same across the board. That would be such a waste of time and effort. This should not really be about Apple's individual opinion but please make this a united decision. Only then these units have a real purpose, otherwise I'm afraid we might as well throw all of this in the bin, while we are so close to a solution. :)

@frehner
Copy link
Author

frehner commented Jul 14, 2021

When the issue/PR about the changes to vh is created, could you please link to it here? I would like to share some thoughts on it but want to wait until there's a focused discussion on it.

Thanks, and it's great to see this resolved!

@fantasai
Copy link
Collaborator

Alright, officially published the 4-way v*/sv*/lv*/dv* spec at
https://www.w3.org/TR/css-values-4/#viewport-relative-lengths

Opened two issues for follow-up discussion: #6454 about enforcing v* as a static unit, and #6453 about the relationship with the actual initial containing block. We also have #6026 open about scrollbars.

@jensimmons
Copy link
Contributor

The CSSWG resolved to close this issue and open new separate issues on anything else that needs to be discussed. It's been a great debate, but now this ticket has far too much going on, and it's not possible to keep up with the ideas. File new separate tickets about each detail / debate, and we can discuss there. As per the CSSWG's way of using issues. Thanks everyone!

@jensimmons
Copy link
Contributor

To keep track of such issues, use [css-values-4] in the title, and put the css-values-4 label on it. Then you can see the list of what's being discussed about these units at: css-values-4 Current Work

And to talk about things that should be environment variables, use [css-env-1] in the issue title, and label it with css-env-1 so that it shows up here: css-env-1

And if you aren't sure whether it should be a unit or environment variable — put the more likely choice in the title, and label it with both labels.

See you in the other issues.

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