ChatGPT解决这个技术问题 Extra ChatGPT

iOS 7 iPad Safari Landscape innerHeight/outerHeight layout issue

We're seeing issues with a web app that has a height of 100% on Safari in iOS 7. It appears that the window.innerHeight (672px) doesn't match window.outerHeight (692px), but only in landscape mode. What ends up happening is that in an app with 100% height on the body, you get 20px of extra space. This means that when a user swipes up on our app, the navigation elements get pulled behind the browser chrome. It also means that any absolutely positioned elements that are at the bottom of the screen end up being 20px off.

This issue was also outlined in this question here: IOS 7 - css - html height - 100% = 692px

https://i.stack.imgur.com/VPQYy.png

What we're trying to do is hack around this so that until Apple fixes the bug, we don't have to worry about it.

One way of doing this is to absolutely position the body only in iOS 7, but this pretty much puts the extra 20px at the top of the page instead of the bottom:

body {
    position: absolute;
    bottom: 0;
    height: 672px !important;
}

Any help with forcing outerHeight to match innerHeight, or hacking around it so that our users can't see this issue would be much appreciated.

for more detail refer this URL: krpano.com/ios/bugs/ios7-ipad-landscape
On a side note: this bug seems to be fixed on iOS8. Workarounds should only target iOS7.

S
Samuel Moreno López

In my case, the solution was to change positioning to fixed:

@media (orientation:landscape) {
    html.ipad.ios7 > body {
        position: fixed;
        bottom: 0;
        width:100%;
        height: 672px !important;
    }
}

I also used a script to detect iPad with iOS 7:

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i)) {
    $('html').addClass('ipad ios7');
}

I combined this with doing window.scrollTo(0,0); on orientation change and it seems to have solved 99% of our problems. Give me a couple days of using this in production and I think we might have our answer.
I just found that a friend with the iPad mini OS 7 do not have this problem, any idea to find if it's iPad mini?
i have an iPad mini with retina and seeing the same problem
Wow... I can't believe it took me so long to find this. I've been searching all night trying weird javascript hacks that almost but never worked. This is amazing.
OMG wasted about two days on this on the ipad sim thinking my postion:absolute; was casuing this. Thanks!
m
mikeStone

Simple, cleaner CSS-Only solution:

html {
     height: 100%;
     position: fixed;
     width: 100%;
   }

iOS 7 seems to set the height correctly with this. Also there is no need for resize javascript events, etc. Since you are working with a full height app, it doesn't really matter if it is always position fixed.


This works on a regular iPad w/ Retina, but does not work on an iPad Mini, strangely. The 672px fix seems to work on both.
A
Andrea Tondo

Samuel's answer, as also stated by Terry Thorsen, is working great, but fails in case the webpage has been added to the iOS home.

A more intuitive fix would be to check for window.navigator.standalone var.

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i) && !window.navigator.standalone) {
    $('html').addClass('ipad ios7');
}

This way it only applies when opened inside Safari, and not if launched from home.


another situation this doesn't work in is when the favorites bar is showing. So with this answer and mine bellow - all issues covered (as far as I'm aware!)
T
Terry Thorsen

Samuel's answer is the best although it breaks if a user adds the page to their home screen (home screen pages don't exhibit the bug). Check the innerHeight before adding the class like so:

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i)) {
    if(window.innerHeight==672){
        $('html').addClass('ipad ios7');
    }
}

Note that the bug also does not exhibit under webview.


My iPad reports window.innerHeight of 671 (with console.log), so 672 is not always accurate.
c
czuendorf

I used this JavaScript solution for solving that problem:

    if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i) && window.innerHeight != document.documentElement.clientHeight) {
  var fixViewportHeight = function() {
    document.documentElement.style.height = window.innerHeight + "px";
    if (document.body.scrollTop !== 0) {
      window.scrollTo(0, 0);
    }
  }.bind(this);

  window.addEventListener("scroll", fixViewportHeight, false);
  window.addEventListener("orientationchange", fixViewportHeight, false);
  fixViewportHeight();

  document.body.style.webkitTransform = "translate3d(0,0,0)";
}

o
overmailed

A variant of Samuel's approach, but with position: -webkit-sticky set on html worked for me the best.

@media (orientation:landscape) {
    html.ipad.ios7 {
        position: -webkit-sticky;
        top: 0;
        width: 100%;
        height: 672px !important;
    }
}

Notice 'top: 0', not 'bottom: 0', and target element is 'html', not 'body'


V
Vadim

Basically there are two bugs - the hight of the window in landscape mode and the scroll position when the user rewerts to it from portrait mode. We have solved it this way:

the hight of the window is controlled by:

// window.innerHeight is not supported by IE
var winH = window.innerHeight ? window.innerHeight : $(window).height();

// set the hight of you app
$('#yourAppID').css('height', winH);

// scroll to top
window.scrollTo(0,0);

now, the above can be put into a function and bind to window resize and/or orientation change events. that's it... see example:

http://www.ajax-zoom.com/examples/example22.php


You don't actually solve the problem, because there is a strange white space at the bottom of the page (look here) and user still can scroll the page.
a
andraaspar

You need JavaScript to work around this bug. window.innerHeight has the correct height. Here's the simplest solution I can think of:

$(function() {
    function fixHeightOnIOS7() {
        var fixedHeight = Math.min(
            $(window).height(), // This is smaller on Desktop
            window.innerHeight || Infinity // This is smaller on iOS7
        );
        $('body').height(fixedHeight);
    }

    $(window).on('resize orientationchange', fixHeightOnIOS7);
    fixHeightOnIOS7();
});

You'll also need to set position: fixed on the <body>.

Here's a complete, working example:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8"/>
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <meta name="apple-mobile-web-app-capable" content="yes"/>
        <title>iOS7 height bug fix</title>
        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script>
            $(function() {
                function fixHeightOnIOS7() {
                    var fixedHeight = Math.min(
                        $(window).height(),
                        window.innerHeight || Infinity
                    );
                    $('body').height(fixedHeight);
                }

                $(window).on('resize orientationchange', fixHeightOnIOS7);
                fixHeightOnIOS7();

                // Generate content
                var contentHTML = $('#content').html();
                for (var i = 0; i < 8; i++) contentHTML += contentHTML;
                $('#content').html(contentHTML);
            });
        </script>
        <style>
            html,
            body
            {
                margin: 0;
                padding: 0;
                height: 100%;
                width: 100%;
                overflow: auto;
                position: fixed;
            }
            #page-wrapper
            {
                height: 100%;
                position: relative;
                background: #aaa;
            }
            #header,
            #footer
            {
                position: absolute;
                width: 100%;
                height: 30px;
                background-color: #666;
                color: #fff;
            }
            #footer
            {
                bottom: 0;
            }
            #content
            {
                position: absolute;
                width: 100%;
                top: 30px;
                bottom: 30px;
                overflow: auto;
                -webkit-overflow-scrolling: touch;
            }
        </style>
    </head>
    <body>
        <div id="page-wrapper">
            <div id="header">Header</div>
            <div id="content">
                <p>Lorem ipsum dolor sit amet.</p>
            </div>
            <div id="footer">Footer</div>
        </div>
    </body>
</html>

N
Nick Maynard

With reference to the accepted answer, I've also had luck with the following rule:

html.ipad.ios7 {
    position: fixed;
    width: 100%;
    height: 100%;
}

This has the added advantage in that it appears to stop the html element scrolling "under" a fixed body element.


E
Excellll

If I use this:

if (navigator.userAgent.match(/iPad;.*CPU.*OS 7_\d/i) && !window.navigator.standalone) {
    $('html').addClass('ipad ios7');
}

My Safari on Mac shows the same html classes... SO its not working correctly.

I tried to combine a few things - that worked for me, so I can manage it in the browser and without Browser view.

jQuery

if (navigator.userAgent.match(/iPad/i) && (window.orientation) ){
     $('html').addClass('ipad ');
        if (window.innerHeight !=  window.outerHeight ){
          $('html').addClass('browser  landscape');              
    }
    else{
         $('html').addClass('browser portrait');                   
    }
} 

CSS

@media (orientation:landscape) {
   html.ipad.browser > body {
       position: fixed;  
       height: 671px !important;
   }
}

///// With this you are more flexible or other OS and Browsers


d
ddlab

I came across this page for the same issue. There are a lot of useful answers here, and others not (for me).

However, I found a solution, which works in my case, and works totally independent of which OS version and which bug now or in the past or future.

Explaination: Developping a web app (no native app) with several modules of fixed size in fullscreen, with class name "module"

.module {position:absolute; top:0; right:0; bottom:0; left:0;}

which contains a footer with class name "footer"

.module > .footer {position:absolute; right:0; bottom:0; left:0; height:90px;}

Nevermind, if I set the height of the footer later to another height, or even its height is set by its content, I can use this following code for correction:

function res_mod(){
    $('.module').css('bottom', 0); // <-- need to be reset before calculation
    var h = $('.module > .footer').height();
    var w = window.innerHeight;
    var o = $('.module > .footer').offset();
    var d = Math.floor(( w - o.top - h )*( -1 ));
    $('.module').css('bottom',d+'px'); // <--- this makes the correction
}

$(window).on('resize orientationchange', res_mod);

$(document).ready(function(){
    res_mod();
});

Thanks to the skills of Matteo Spinelli I can still use iScroll with no problems, as its change events fortunately are fired after. If not, it would be necessary to recall the iScroll-init again after the correction.

Hope this helps somebody


N
Nick Hingston

The accepted answer doesn't cope when the favorites bar is showing. Here is am improved catch all fix:

@media (orientation:landscape) {
  html.ipad.ios7 > body {
    position: fixed;
    height: calc(100vh - 20px);
    width:100%;
  }
}

a
ainos

what if you try

html{ bottom: 0;padding:0;margin:0}body {
position: absolute;
bottom: 0;
height: 672px !important;
}