Viewport height is taller than the visible part of the document in some mobile browsers

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.

An issue with Apple iOS Safari

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

Here is what this page looks like on an iPhone 5:

100vh is computed for when the browser interface is hidden, after a scroll:

As suggested by Yoav Weiss there and there, I opened a bug in Apple Bug Reporter(#19879505) and Webkit Bugzilla.

Description

When trying to use a 100vh CSS value to build an 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 of Safari iOS on iPhone, or below the “fold” on iPad.

Steps to Reproduce

  1. Open http://lab.gasteroprod.com/vub/index-ios-issue.html on iOS Safari with an iPhone in portrait mode, or an iPad in portrait or landscape mode
  2. 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: https://github.com/rodneyrehm/viewport-units-buggyfill/issues/13

But not the only one…

In fact I saw later that iOS Safari is not the only one doing this.

Firefox on Firefox OS

I discovered later the same behavior on the browser of Firefox OS:

So what?

Are these behaviors browsers bugs, or the correct implementation of the standard, or is it open to interpretation?

February 23rd update

Webkit bug has been set to RESOLVED WONTFIX, with this explanation:

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.

March 4th update

The issue on Apple Bug Reporter has been closed with this comment:

This issue behaves as intended.

Meh…

The W3C CSS Working Group replied on Twitter with links to past discussions:

March 9th update

The W3C CSS Working Group suggestion doesn’t fix anything, in iOS at least. Test it live here.

June 30th update

Boris, a friend, told be he saw a disturbing behavior of my text content when scrolling on this site:

@nhoizey j’ai un changement de taille de police au scroll… Bizarre!

— Boris 🚀 (@borisschapira) June 30, 2015

In fact, the viewport height changes when he scrolls and the browser chrome hides. Combine this with the fact that he font-size is partialy based on a vh value, and you understand that when scrolling and hiding the browser chrome, the text size was growing.

Here is a visual demonstration, from two screenshots he gave me:

The font-size increases when the user scrolls

Boris uses a OnePlus One running Android 5.0.2 and Chrome 43.0.2357.93.

So there is at least one browser that behaves as I want for my full height game screen… but it makes users wonder if there is an issue…

January 19th, 2016 update

People developing Chrome for Android now plan to change its behavior to match iOS Safari’s one, claiming that “Safari’s been doing this for years without user/developer complaint”.

I’ve tried to answer1, but I don’t believe it will change anything. At least, we will have the same “bug” everywhere…

November 8th, 2016 update

Chrome will indeed now work like Safari.

There is a lot of interesting informations in this study about the differences between mobile browsers, and the proposed consensus.

December, 2016 update

David Bokan explains how Chrome will now behave starting with version 56: URL Bar Resizing.

Unfortunately:

The unintuitive choice of making vh units the largest possible viewport but the ICB the smallest possible is to match Safari’s behavior.

January 3rd, 2017 update

Jeremy Keith made the same observation, and concluded that “the result of this messiness is that the vh unit is practically useless for real-world situations with real-world devices”.

February 22nd, 2017 update

Peter-Paul Koch makes the same observation that viewport size is a tricky topic, with many disparities among browsers, in his post Toolbars, keyboards, and the viewports.

  1. Thanks Yoav for the notification about this discussion! ⬆︎

Si vous voulez signaler une erreur ou proposer une modification de ce texte, n'hésitez pas à l'éditer directement à la source sur Github.

34 commentaires

  • Good article compiling all your findings, I have just ran across the same issue and this is very annoying

  • I am having the Chrome for iOS issue listed here. I have full size photos that use 100vh and 100vw, but when I scroll up and down, the address bar appearing and disappearing causes some horrible scrolly jank on the page. It seems fine on mobile Safari, I guess I have the opposite problem to you! Or at least more like the font size issue. I have no idea what to do to stop it screwing up on Chrome for iOS…

  • Bottom nav is even more difficult because if the interface is hidden, a tap on a button at the bottom will reveal the interface instead of actually hitting the button…

  • Good article indeed.
    Truth be told, I don't think there could be any ideal solution to this problem. One could say it was all better in the old days when mobile browsers did not resize the viewport upon scrolling, but for now we have to deal with it.

    As it stands today, I actually find iOS's behavior makes a lot more sense than Android's. We could argue that 100vh should be equal to the viewport height *with* the chrome being displayed as websites first appear this way upon landing. But changing the actual value of the vh unit multiple times as the user scrolls is a complete nonsense and a nightmare to deal with when developing regular websites. How many times a day do Android users stumble upon a site whose content "jumps" a few dozens pixels when they scroll up and down?

    Many web designs nowadays feature an introductory section with a background image and a height that is relative to the viewport's, which makes using any relative values a no-go on Android. What's even worse, most Android browsers trigger the resize JS event when the chrome shows up or hides, so you can't rely on it to set your layout in JS. I usually end up storing the initial viewport height on Android and use that instead. Oh, and to make everything so much more messed up, scrolling up and down on Android triggers height-related CSS media queries. So if you happen to have one right between the with-chrome and without-chrome values, you're out of luck.

    I understand iOS's behavior could be an issue in certain cases (like developing a game), but I find it a lot less frustrating and a lot easier to deal with on a daily basis than Android's.

  • Thanks for compiling this information. I was trying having a similar problem, but was able to solve my issues by using css fixed position elements for the parts of the page that you want to stick at the top and bottom. You'll be glad to hear that at least Safari on IOS positions them at the top and the bottom of the visible area, rather than at the top and bottom of their calculated viewport (even when top and bottom browser bars appear and disappear when scrolling).

  • oh actually, even better… use the following, it might even solve your problems. Don't use vh measures. Take away min-height if you don't want it to expand over 100%.

    html, body { height: 100%; min-height: 100%; }

    .full-screen { height: 100%; min-height: 100%; }

    <html><body><div class="full-screen"></div></body></html>

    … and then try the same positioning.

  • Thanks for gathering all your findings in one article. It's frustrating to know 'vh' does not get only the available height in browser window on IOS.

  • Thanks for fighting the good fight. I wouldn't say it's "been like this for years with no complaint", too often devs just don't notice it until it directly affects them. Which for me, just happens to be now too. I would complain, but Apple won't care.

  • Googled around to find an answer why this was happening, because I was tearing my hair out. Glad I'm not the only one that sees an issue with it.

    Viewport means its in view. When you throw a navigation bar on top of it, that kind of defeats the hole purpose of the standard.

  • the problem is not this alone, but when it is coupled with the removal of the meta minimal-ui . now we have a part of the screen hidden unless we scroll. 100vh is effectively useless then.

    Maybe we shall request the return of minimal-ui then.

  • that's maybe why nobody complained before, when minimal-ui was there…

  • After years of this being a huge pain i recently discovered a pretty good fix for this thats pure CSS.

    min-height: calc(100% - 0);

    Seems to prevent iOS from scrolling at all and prevents the minimal-ui from kicking in.

    Hope this helps if people come across this issue:)

  • Brandon solution doesn't work for me.So I use JS to fix height to initial vh or this below in CSS to make vh transition smoother:
    .full-height {
    height: 100vh;
    min-height: 100vh;

    transition-property: height, min-height;
    transition-duration: .6s;
    transition-delay: .1s;
    transition-timing-function: ease-in;
    }

  • This is depressing. It really messes up content that is fullscreen and not scrollable. I appreciate you fighting the good fight.

  • This almost makes vh useless. I only ever use it to keep things full screen, which then implies no scrolling. Now, vh has scrolling automatically. To have 100% without scrolling we HAVE to use%. We are back to 2005.

  • I use vh in many ways, it is still very useful. But find it also very sad that 100vh doesn't always mean what it should.

  • Hmm so is there a good workaround for filling the actual visible viewport? The bottom of my sites based on 100vh are being cut off as well.:/

  • I get really annoyed with mobile browsers in general, the viewport size changing on scroll is so ugly, when I use something that has vh it makes the whole page jump up and down when I scroll and the address bar shows up for instance. The viewport in mobile browsers should always be at a fixed height in my opinion. If that means always showing the address bar and other bars and sacrificing some screen real estate, so be it. Phones are becoming so huge anyway that 40px less height in a browser really isn't a big deal.

  • “I don't think there could be any ideal solution to this problem.”

    Sure there could be:

    meta name="viewport" content="[…], expand-on-scroll={allow|no}, initial-containing-block={actual|min|max}, vh-unit={actual|min|max}"

  • why can't they introduce another css unit for the maximum viewport height (mvh) and let vh means vh?

  • Unfortunately I couldn't find a way to do this with css, so I did it with the below js.

    const height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
    document.getElementsByClassName('yourelement')[0].style['min-height'] = height + 'px'

Twitter 500px Flickr Facebook Instagram Github Feed