Bug 141832 - Viewport height is taller than the visible part of the document in some mobile browsers
Summary: Viewport height is taller than the visible part of the document in some mobil...
Status: RESOLVED WONTFIX
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-02-20 02:40 PST by Nicolas Hoizey
Modified: 2016-04-29 11:15 PDT (History)
9 users (show)

See Also:


Attachments
Bottom hidden in iOS Safari in portrait mode (44.38 KB, image/png)
2015-02-20 02:40 PST, Nicolas Hoizey
no flags Details
Full content visible in iOS Safari in portrait mode after scroll (46.68 KB, image/png)
2015-02-20 02:41 PST, Nicolas Hoizey
no flags Details
Bottom hidden in iOS Safari in landscape mode (38.53 KB, image/png)
2015-02-20 02:41 PST, Nicolas Hoizey
no flags Details
iOS Safari in landscape mode goes full screen after scroll (37.63 KB, image/png)
2015-02-20 02:42 PST, Nicolas Hoizey
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nicolas Hoizey 2015-02-20 02:40:04 PST
This description is a duplication from a blog post I did [1], maybe easier to read with illustrations in context:

# Description

When trying to use a 100vh CSS value to build a new interface for a game that would use the full viewport, I discovered that this full height value meant the bottom of the game interface was partialy hidden behind the browser buttons bar or below the "fold" of some mobile browsers.

I first discovered this on my iPhone 5 and iPad 2.

See in attachments what the test page [2] looks like on an iPhone 5, portrait and landscape, before and after scroll (and interface minification).

The 100vh value seems to be computed for when the browser interface is hidden, after a scroll.

There is « VIEW » in viewport, so defining it’s dimensions with hidden parts seems strange… The really sad thing is it doesn't help people trying to develop full-viewport interfaces, for games for example, but not only.

As suggested by Yoav Weiss [3], I first opened a bug in Apple Bug Reporter, got the id 19879505.

# Steps to Reproduce

- Open [2] on iOS Safari with an iPhone in portrait mode, or an iPad in portrait or landscape mode
- The bottom part of the "bottom right" box is not visible, the 100vh height container being taller than the visible part

# Expected Results

I would have expected the viewport size (and the 100vh dimension) to be equal to the visible part of the page in the browser. It’s called VIEWport after all.

I understand it means the viewport changes when the browser interface hides, but I find it better, and necessary for "full viewport" interfaces. Fullscreen API is not available either, so there is no simple way to fix this behavior.

# Actual Results

The bottom part of the "bottom right" box is not visible, the 100vh height container being taller than the visible part

# Configuration

iPhone 5 and iPad 2

# Version & Build

iOS 8.1.3 (12B466), and other versions in the iOS simulator

# Additional Notes

There is a JavaScript library that tries to fix some issues with viewport units in iOS, but it has issues too [4] 

----

[1] http://gasteroprod.com/web/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers
[2] http://lab.gasteroprod.com/vub/index-ios-issue.html
[3] https://twitter.com/yoavweiss/status/568145414320492544
[4] https://github.com/rodneyrehm/viewport-units-buggyfill/issues/13
Comment 1 Nicolas Hoizey 2015-02-20 02:40:38 PST
Created attachment 246953 [details]
Bottom hidden in iOS Safari in portrait mode
Comment 2 Nicolas Hoizey 2015-02-20 02:41:10 PST
Created attachment 246954 [details]
Full content visible in iOS Safari in portrait mode after scroll
Comment 3 Nicolas Hoizey 2015-02-20 02:41:32 PST
Created attachment 246955 [details]
Bottom hidden in iOS Safari in landscape mode
Comment 4 Nicolas Hoizey 2015-02-20 02:42:02 PST
Created attachment 246956 [details]
iOS Safari in landscape mode goes full screen after scroll
Comment 5 Benjamin Poulain 2015-02-23 09:25:58 PST
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.
Comment 6 Nicolas Hoizey 2015-02-23 09:32:26 PST
Thanks for the explanation.

I suppose I will have to use JS instead of CSS for positioning the interface elements and adjust according to the "real" viewable area… :-/
Comment 7 Benjamin Poulain 2015-02-23 09:47:32 PST
(In reply to comment #6)
> Thanks for the explanation.
> 
> I suppose I will have to use JS instead of CSS for positioning the interface
> elements and adjust according to the "real" viewable area… :-/

For positioning, you can look into "fixed" and "sticky" positinioning. Those two modes creates layers that are composited in real time.

Both fixed and sticky positioning follow the view height and WebKit can handle them at 60FPS effortlessly.

If you use JavaScript for positioning while scrolling, you will need to be careful with this:
-resize events are only sent once for the small state or the large state. If you need continuous update, you need to check the window.innerHeight in response to touch events.
-To keep rendering in sync with scrolling, you must respond to each frame in less than ~16ms (in practice, really 9-10ms).
Comment 8 David Bokan 2015-11-30 10:28:07 PST
(In reply to comment #5)
> 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.

Hi Benjamin, sorry to resurrect this old bug, but I'm working on improving interop between Chromium and Safari here and the choice to use the larger view size seems strange given that the ICB uses the smaller view size.

In particular, this means height:100% and height:100vh will be different which might be surprising. Did you intentionally make the ICB and 100vh unequal? Do you have any examples of pages that look better using this method?

Thanks,
David
Comment 9 Rick Byers 2016-01-25 07:49:31 PST
Note that blink is planning on matching WebKit's behavior here, but it's causing some developer concern.  Details:
https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/BK0oHURgmJ4
https://groups.google.com/a/chromium.org/forum/#!topic/input-dev/EBNboiECIAQ

It's still not at all clear this is really the right design for the web long-term.  Perhaps there's a missing API somewhere?
Comment 10 John Meyer 2016-04-27 16:55:10 PDT
It seems to me that the original intent to not reflow while scrolling was a good idea. However, the divergence of height: 100% and height: 100vh breaks the principal of least astonishment at the very least. Rather than choose the largest or smallest icb, I believe users and developers would expect the viewport size to not change at all while scrolling. However, when the scrolling is complete, the viewport should be updated and the elements reflowed.

I realize that reflowing the document after the user has finished scrolling is challenging due to potential changes in scroll position, but maintaining the expected scroll position should be doable. This would allow developers to use 100vh and have it most closely resemble the spec while keeping the desired performance.
Comment 11 hexalys 2016-04-28 16:58:21 PDT
(In reply to comment #9)
> Note that blink is planning on matching WebKit's behavior here, but it's
> causing some developer concern.  Details:
> 
> It's still not at all clear this is really the right design for the web
> long-term.  Perhaps there's a missing API somewhere?

As a dev, the important part is to at least, be able to detect the difference in px via JS. For my own use so far, I have managed to detect the dynamic iOS Safari bar and its size; using a generic debounced resize|scroll event, which updates a CSS class on the document. That give me CSS class updating CSS height accordingly using `calc`. But it remains a fragile hack relying on quite a few assumptions.

The current behavior, *if detectable*, has a significant benefit. This can allow for example, adding a bottom notifications, messages or button bar. But not until a scroll has occurred, and the bottom menu bar is gone; to avoid redundant double bars and/or not to clutter screen space.

As for an API, HTML5 has the BarProp interface for this kind of thing. It seems however that browsers have moved away from exposing any useful values for those attributes, to the point of no longer exposing anything at all on mobile browsers. It seems appropriate to review what BarProp is, what to keep, redefine or add, such as pixel values. Or else BarProp might as well be deprecated...

But if 100vh is context dependent, the browser *should* surely expose that behavior somewhere.
Comment 12 David Bokan 2016-04-29 11:15:46 PDT
(In reply to comment #10)
> It seems to me that the original intent to not reflow while scrolling was a
> good idea. However, the divergence of height: 100% and height: 100vh breaks
> the principal of least astonishment at the very least. Rather than choose
> the largest or smallest icb, I believe users and developers would expect the
> viewport size to not change at all while scrolling. However, when the
> scrolling is complete, the viewport should be updated and the elements
> reflowed.

This is perhaps less astonishing to developers, but to users can be quite frustrating if the developer hasn't thought about it. For e.g., I've seen examples that use vh units to size fonts, which works quite nicely on desktop. On mobile, the page becomes exceedingly annoying as everything resizes and reflows on each change of direction.

> I realize that reflowing the document after the user has finished scrolling
> is challenging due to potential changes in scroll position, but maintaining
> the expected scroll position should be doable. This would allow developers
> to use 100vh and have it most closely resemble the spec while keeping the
> desired performance.

Anchoring the scroll position on relayout is tricky but doable and Chrome's actively working on this. Even if that works perfectly though, I still think that we should make the layout height static *by default*. Exposing this information is a good idea, and we plan to keep window.innerHeight reflecting the status of the top controls (as Safari does IIRC) for motivated developers to make use of it. But I see a static layout as a "pit of success". If a developer doesn't think about this, the default doesn't cause the user a poor experience (even with non-visible differences, constantly changing the layout size causes increased power draw on mobile). If the dev does think about it, they should have the tools to design an even better user experience.