This description is a duplication from a blog post I did , maybe easier to read with illustrations in context:
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  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 , I first opened a bug in Apple Bug Reporter, got the id 19879505.
# Steps to Reproduce
- Open  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
iPhone 5 and iPad 2
# Version & Build
iOS 8.1.3 (12B466), and other versions in the iOS simulator
# Additional Notes
Created attachment 246953 [details]
Bottom hidden in iOS Safari in portrait mode
Created attachment 246954 [details]
Full content visible in iOS Safari in portrait mode after scroll
Created attachment 246955 [details]
Bottom hidden in iOS Safari in landscape mode
Created attachment 246956 [details]
iOS Safari in landscape mode goes full screen after scroll
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.
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… :-/
(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.
-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).
(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
> 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?
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?
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.
(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.
(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
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.
cut the shit. this is clearly a FUCKING BUG and NEEDS TO BE FIXED.
I realize that the WebKit developers aren't interested in supporting standards, but what is the correct in getting the correct height in poorly designed browsers such as WebKit?
Why aren't the developers interested in supplying a way to actually get the height of the content pixels?
Since there still isn't a proper solution to get the actual viewport height on crossbrowser/devices, is there anything planned?
I guess implementing something like 'height: 100vhi;' would solve the majority of problems. This would give back the initial viewport height without the browser chrome (addressbar and other menu's).
100vh = device viewport height
100vhi = 100vh - browser chrome
There may be a solution for this if there is an env() variable defined, as suggested here: https://github.com/w3c/csswg-drafts/issues/2630#issuecomment-397536046
If UA's would define their "overlayed" interfaces we could just inset the HTML document.
We cannot easily use calc with 100vh on Safari because of this... Pretending that vertical height of viewport is not changing when it is causes lots of headaches for developers who need to hack their applications just for Safari on iOS because it has issues with calc(100vh - xxx) CSS calculations.
Please re-open this issue
Here's article with more info: https://benfrain.com/the-ios-safari-menu-bar-is-hostile-to-web-apps-discuss/
We may revisit this.
Any updates on this?
A solution should also include the native keyboard, which while in Android Chrome borrows space from the viewport, in iOS Safari it covers over the viewport.
All of this so the bottom bar can be animated. This is mind boggling.
Right now this is completely broken.
The CSSWG is actually working on this at the moment.
You can follow it here.
I know I'd be beating a dead horse here, but people only complain about something when it finally bites them in the ass. And that's exactly what I am going to do.
I just want to thank you for making mobile web development significantly more of a pain in the ass than it needed to be. Truly, a magnificent feat.
Maybe one day, we can get around to counting the OS Status Bar and OS Buttons as part of the heigh, sometimes, maybe, just so we can really make sure that mobile web development is truly as hard as it can be.
Or better yet, let's make vh the device's physical height, including the plastic or metal bezel. There's still a bit of use left in vh, so doing that will surely complete your goal of killing it.
A tweet  that proposed a workaround based on…
…went pretty viral (917 Retweets, 4.9K Likes), but even as a workaround this doesn't work universally, since Chrome honors `-webkit-fill-available`, but does something different  than Safari, see the demo .
Please fix this shit, as tolga dede said, this is clearly a BUG.
Hello. I assume this is related to this bug:
1. Initial: 100% height match the full visible height
2. As navigation bar is shown: 100% match the full visible height
3. As navigation bar is removed: 100% match the visible height as if the navigation bar is still there (i.e not 100% of the full visible height)
Happens on rotate and on navigation back_forward, on browser and webview.
On a single page web app with no scroll, updating the viewport height to match 100% to the full visible height when navigation bar is removed should be doable. As using vh units or -webkit-fill-available, tends to render content below the visible viewport or behind the navigation bar.