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] Visual viewport units #7194

Closed
devongovett opened this issue Apr 1, 2022 · 12 comments
Closed

[css-values-4] Visual viewport units #7194

devongovett opened this issue Apr 1, 2022 · 12 comments

Comments

@devongovett
Copy link
Contributor

The new viewport relative units introduced recently are a great step forward. However, none of them correspond with the VisualViewport API in JavaScript. Specifically, when the software keyboard is visible, the visualViewport.height property changes accordingly, but e.g. 100dvh does not.

This behavior is problematic when trying to build interfaces that are positioned above the on-screen keyboard, or resize so that they are always visible while the keyboard is open. Examples include chat UIs, commenting UIs, trays/sheets, modals containing forms, floating toolbars, etc.

I would like to propose another unit that corresponds exactly to what the VisualViewport API returns, but without requiring JavaScript. It is possible to accomplish this by setting a custom property from JS when the VisualViewport resize event occurs, but this approach has some drawbacks:

  • It requires JavaScript. This seems like a common enough UI pattern to warrant a CSS-only solution.
  • It does not adjust smoothly during keyboard open/exit animations. The VisualViewport API typically only fires a single resize event at the end of the transition. This can lead to janky user experience where UI components are incorrectly positioned or sized temporarily while the keyboard is opening or closing. I think the UA would need to be in charge of doing this animation for performance reasons, rather than dispatching a JS event every frame.

Possible names:

  • vvh - i.e. visual viewport height
  • vvw
  • vvmin / vvmax

Has something like this been discussed in the past?

@Loirooriol
Copy link
Contributor

when the software keyboard is visible, the visualViewport.height property changes accordingly, but e.g. 100dvh does not.

I'm not much familiar with that, but I think dvh should change accordingly. Wasn't that the entire point of adding that unit?

@devongovett
Copy link
Contributor Author

The current spec for dynamic viewport units is clear:

Additionally, UAs may have some dynamically-shown interfaces that intentionally overlay content and do not cause any shifts in layout—and therefore have no effect on any of the viewport-percentage lengths. (Typically on-screen keyboards will fit into this category.)

That's why I think we need a new unit.

@bfgeek
Copy link

bfgeek commented Apr 5, 2022

I believe based on https://bokand.github.io/demo/urlbarsize.html (and inserting a <textarea> or in the DOM to trigger the keyboard behaviour) that Blink will adjust the dvh/lvh unit based on whether the keyboard is showing. @devongovett - Does Chrome Canary on Android (with chrome://flags/#enable-experimental-web-platform-features enabled) match your expected behaviour?

@devongovett
Copy link
Contributor Author

I believe Chrome on Android has always resized the viewport when the keyboard appears, even with regular vh units. iOS does not do this though - the keyboard covers the content instead. The spec as quoted above seems to allow this, which is why I think either the spec should be changed, or a new unit is needed.

@tabatkins
Copy link
Member

It does not adjust smoothly during keyboard open/exit animations.

Note that this would still be true of a new viewport unit. dvh explicitly says UAs are not required to animate the unit while stuff is showing/hiding, just that they have to be correct when the animation is finished. We'd have a similar clause for any other unit in this space.

@bokand
Copy link
Contributor

bokand commented Jun 16, 2022

This behavior is problematic when trying to build interfaces that are positioned above the on-screen keyboard, or resize so that they are always visible while the keyboard is open. Examples include chat UIs, commenting UIs, trays/sheets, modals containing forms, floating toolbars, etc.

A challenge with using a visual viewport unit to achieve these use cases is that the visual viewport also resizes (and offsets) as a result of pinch-zoom. If you're positioning a floating toolbar based just on the visual viewport height, it'll be wrong as soon as some pinch-zoom (and non-0 visualViewport.offsetTop) is introduced (and browsers perform automatic zoom onto a focused input element in some cases).

IMHO, something like position: device-fixed seems more natural for these use cases since it'd let you position things in the coordinate space of the visual viewport.

@devongovett
Copy link
Contributor Author

That might work for fixed size floating toolbars, but I need to both position and size content to fit above the keyboard though. When the user scrolls while the keyboard is open, content shouldn't be behind the keyboard, only above it.

@bramus
Copy link
Contributor

bramus commented Jun 21, 2022

(@bfgeek) I believe based on https://bokand.github.io/demo/urlbarsize.html (and inserting a <textarea> or in the DOM to trigger the keyboard behaviour)

A forked version that includes this can be found at https://urlbarsize.netlify.app/urlbarsize-allowresize.html
It also contains an extra option to toggle the behavior of the Virtual Keyboard (if supported by the browser).

(@devongovett) I believe Chrome on Android has always resized the viewport when the keyboard appears, even with regular vh units.

Correct. It's the only platform that does this, and we'll be looking into that as part of web-platform-tests/interop#41

(@bokand) A challenge with using a visual viewport unit to achieve these use cases is that the visual viewport also resizes (and offsets) as a result of pinch-zoom.

What if the zoom level was also exposed? Then an author would be able to reconstruct the “Unzoomed Visual Viewport” values from that:

  • Unzoomed vvh = calc(100vvh * 100vvz);
  • Unzoomed vvw = calc(100vvw * 100vvz);

(vvz to be bikeshed, but you get the point)

Alternatively uvvh and uvvz could be exposed, but that would – again – be extra units for the author to remember/use.

(@bokand) IMHO, something like position: device-fixed seems more natural for these use cases

Also a fan of it :)

@bramus
Copy link
Contributor

bramus commented Jul 1, 2022

The proposed Visual Viewport Units do not form a closing solution for the stated use-case of positioning above the Virtual/On-Screen Keyboard (OSK). Take this snippet that should achieve the desired effect.

#target {
  position: fixed;
  height: 2em;
  width: 100vvw;

  top: 100vvh;
  transform: translateY(-100%);
}

The code above only works when the top edges of the Layout Viewport and Visual Viewport line up. This, however, is not always the case. When scrolling down with the OSK shown, the Layout Viewport will initially stay where it is, and the user is merely moving the Visual Viewport down. Because the Visual Viewport always matches the device, the net result is that the Layout Viewport will “shoot up”.

See illustration below where the FixedPos Element (orange) appear to be floating in the middle of the Visual Viewport (orange dotted line) once you scroll down, because it is laid out against the top edge of the Visual Viewport (blue dotted line).

image

To work properly one would also need the distance between the top edges of both viewports mentioned, which would introduce even more extra units.

The already mentioned position: device-fixed; would form a more closing solution, as that would really keep items in place – even when the Visual Viewport moves or gets resized.

The units proposed here would play nice together with that position: device-fixed;, you just wouldn’t be able to use them for guaranteed positioning. By combining both you can position something above the OSK, and have it fill up the entire Visual Viewport Width.

@flackr
Copy link
Contributor

flackr commented Aug 2, 2022

I started #7475 to discuss a particular proposal to allow content to stay visible when the keyboard is shown. It has an interactive demo that can be viewed on desktop. This seems highly related.

@css-meeting-bot
Copy link
Member

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

  • RESOLVED: Not adding units that trigger layout changes based on pinch-zoom
The full IRC log of that discussion <fantasai> Topic: Viewport Units
<fantasai> fantasai: I think we need someone from WebKit in this discussion
<fantasai> fantasai: WebKit does all kinds of fun and interesting things with the viewport on mobile
<fantasai> fantasai: Do we know if they'll be dialing in later today?
<Rossen_> Rossen: I'm happy to defer. Also I would prefer to make progress here and now since we have enough people to discuss and come to a proposed resolution
<fantasai> github: https://github.com//issues/7194
<fantasai> bramus: Recently added viewport-relative units
<fantasai> bramus: lv*/dv*/sv*
<flackr> q+
<fantasai> bramus: Suggestion is to add new units for the visual viewport units vv*
<fantasai> bramus: to reflect the width/height of the visual viewport
<fantasai> bramus: for clear understanding this is the part you see on screen
<fantasai> bramus: when you pinch zoom, this becomes a viewport on top of the canvas
<fantasai> bramus: so this is a sub-viewport of the others, and it describes (?)
<vmpstr> s/(?)/the part that you see/
<fantasai> flackr: I think david and bramus pointed out that if we had such units, it would cause layout changes while you zoom
<fantasai> flackr: which is disruptive and also perf problems
<fantasai> flackr: the fundamental use case seems to be positioning around a virtual keyboard
<fantasai> flackr: so we have some alternate proposals for positioning things relative to the edge of the keyboard
<Rossen_> ack flackr
<fantasai> flackr: see https://github.com//issues/7475
<TabAtkins> fantasai: I think robert's point that pinch-zoom isn't supposed to make layout changes (since you're trying to see something more clealry that's already laid out) is a really important point
<TabAtkins> fantasai: so we can't do this, but we can try to address the concerns another way
<bramus> q+
<emilio> +1 from me too fwiw
<Rossen_> ack bramus
<TabAtkins> +1 from me too on that
<fantasai> bramus: the use case for visual viewport units is if the author wants to have an element that perfectly fits that size
<fantasai> bramus: simply a use case for an element sized to fit within the space left by the keyboard
<fantasai> Rossen_: Any reason why can't use the viewport offsets, that were proposed and are in css-env?
<fantasai> Rossen_: we had an elaborate proposal for how to address these various sizes
<fantasai> bramus: are you talking about pageLeft/pageTop and offsetLeft/offsetTop?
<fantasai> Rossen_: no
<fantasai> Rossen_: I'll take a second to find the actual issue
<TabAtkins> fantasai: I think pinch-zoom and presence of keyboard are two very different things
<TabAtkins> fantasai: keyboard-shifting makes sense to address, pinch-zoom makes sense to specifically *not* address
<TabAtkins> fantasai: agree we commonly need to accommodate the keyboard somehow and should look into it
<TabAtkins> fantasai: but not pinch zoom
<florian> q+
<florian> q-
<fantasai> bramus: should we discuss the issue flackr linked to?
<fantasai> fantasai: Do we want to take a resolution to not add units that respond to pinch-zoom?
<dbaron> +1
<fantasai> Rossen_: any objections?
<fantasai> RESOLVED: Not adding units that trigger layout changes based on pinch-zoom
<Rossen_> q?
<Rossen_> ack fantasai

@fantasai
Copy link
Collaborator

Closing out since we definitely won't be adding visual viewport units, but discussion on addressing the use case should continue in #7475 (or other issues).

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

No branches or pull requests

9 participants