web-dev-qa-db-fra.com

iOS 7 iPad Safari Landscape Problème de mise en page innerHeight / outerHeight

Nous rencontrons des problèmes avec une application Web qui a une hauteur de 100% sur Safari sous iOS 7. Il semble que window.innerHeight (672px) ne correspond pas à window.outerHeight (692px), mais uniquement en mode paysage. Ce qui finit par se produire, c'est que dans une application avec 100% de hauteur sur le corps, vous obtenez 20px d'espace supplémentaire. Cela signifie que lorsqu'un utilisateur glisse vers le haut sur notre application, les éléments de navigation sont tirés derrière le chrome du navigateur. Cela signifie également que tous les éléments en position absolue qui se trouvent au bas de l'écran finissent par être désactivés à 20 pixels.

Ce problème a également été souligné dans cette question ici: IOS 7 - css - hauteur html - 100% = 692px

Et peut être vu dans cette capture d'écran ambiguë: iOS 7 Safari outerHeight issue

Ce que nous essayons de faire, c'est de bidouiller cela pour que, jusqu'à ce que Apple corrige le bogue, nous n'avons pas à nous en préoccuper.

Une façon de faire est de positionner absolument le corps uniquement dans iOS 7, mais cela place assez le supplément de 20 pixels en haut de la page au lieu du bas:

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

Toute aide pour forcer outerHeight à correspondre à innerHeight, ou le piratage afin que nos utilisateurs ne puissent pas voir ce problème serait très appréciée.

72
hisnameisjimmy

Dans mon cas, la solution consistait à changer le positionnement en fixe:

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

J'ai également utilisé un script pour détecter l'iPad avec iOS 7:

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

Solution simple, propre et réservée aux CSS:

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

iOS 7 semble définir la hauteur correctement avec cela. De plus, il n'est pas nécessaire de redimensionner les événements javascript, etc. Puisque vous travaillez avec une application pleine hauteur, peu importe si sa position est toujours fixe.

16
mikeStone

La réponse de Samuel, comme l'a également déclaré Terry Thorsen, fonctionne parfaitement, mais échoue si la page Web a été ajoutée à la maison iOS.

Une solution plus intuitive consisterait à vérifier window.navigator.standalone var.

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

De cette façon, il ne s'applique que lorsqu'il est ouvert dans Safari, et non s'il est lancé de chez soi.

14
Andrea Tondo

J'ai utilisé cette solution JavaScript pour résoudre ce problème:

    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)";
}
2
czuendorf

La réponse de Samuel est la meilleure, même si elle est interrompue si un utilisateur ajoute la page à son écran d'accueil (les pages de l'écran d'accueil ne présentent pas le bogue). Vérifiez la propriété innerHeight avant d'ajouter la classe comme suit:

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

Notez que le bogue n'apparaît pas non plus sous Webview.

2
Terry Thorsen

Une variante de l'approche de Samuel, mais avec la position: -webkit-sticky réglé sur html a fonctionné pour moi le meilleur.

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

Avis 'top: 0', pas 'bottom: 0', et l'élément cible est 'html', pas 'body'

1
overmailed

En ce qui concerne la réponse acceptée, j'ai également eu de la chance avec la règle suivante:

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

Cela présente l’avantage supplémentaire de pouvoir arrêter le défilement de l’élément HTML "sous" un élément de corps fixe.

0
Nick Maynard

Vous avez besoin de JavaScript pour contourner ce bogue. window.innerHeight a la bonne hauteur. Voici la solution la plus simple à laquelle je puisse penser:

$(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();
});

Vous aurez également besoin de définir position: fixed sur le <body>.

Voici un exemple de travail complet:

<!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>
0
andraaspar

La réponse acceptée ne résout pas le problème lorsque la barre de favoris est affichée. Voici une amélioration de tous les correctifs:

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

Je suis tombé sur cette page pour le même problème. Il y a beaucoup de réponses utiles ici, et d'autres pas (pour moi).

Cependant, j'ai trouvé une solution qui fonctionne dans mon cas et fonctionne totalement indépendamment de la version de l'OS et du bogue actuel ou antérieur ou futur.

Explication: Développement d'une application Web (pas d'application native) avec plusieurs modules de taille fixe en plein écran, avec le nom de classe "module"

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

qui contient un pied de page avec le nom de classe "footer"

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

Peu importe, si je règle la hauteur du pied de page plus tard à une autre hauteur, ou même si sa hauteur est définie par son contenu, je peux utiliser le code suivant pour la 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();
});

Grâce aux compétences de Matteo Spinelli, je peux toujours utiliser iScroll sans problème, car ses événements de changement sont heureusement renvoyés. Sinon, il serait nécessaire de rappeler l'iScroll-init après la correction.

J'espère que ça aide quelqu'un

0
ddlab

Si j'utilise ceci:

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

Mon Safari sur Mac affiche les mêmes classes HTML ... SO il ne fonctionne pas correctement.

J'ai essayé de combiner plusieurs choses - cela fonctionnait pour moi, afin que je puisse le gérer dans le navigateur et sans affichage du navigateur.

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;
   }
}

///// Avec cela, vous êtes plus flexible ou autre système d'exploitation et les navigateurs

0
user3432605

En gros, il y a deux bugs: la hauteur de la fenêtre en mode paysage et la position de défilement lorsque l'utilisateur y retourne en mode portrait. Nous l'avons résolu de cette façon:

la hauteur de la fenêtre est contrôlée par:

// 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);

maintenant, ce qui précède peut être placé dans une fonction et être lié à des événements de redimensionnement et/ou de changement d’orientation de fenêtre. c'est ça ... voir exemple:

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

0
Vadim