web-dev-qa-db-fra.com

comment afficher correctement un iFrame dans un safari mobile

J'essaie d'afficher un iframe dans mon application Web mobile, mais je ne parviens pas à limiter la taille de l'iframe aux dimensions de l'écran de l'iPhone. Les attributs height et width de l'élément iframe semblent n'avoir aucun effet, étrangement. L'entourer d'un div parvient à le contraindre, mais je ne peux pas faire défiler dans l'iframe.

Est-ce que quelqu'un a déjà abordé les iframes lors d'un safari sur mobile? Des idées par où commencer?

52
Matt Diamond

Oui, vous ne pouvez pas contraindre l'iframe lui-même avec la hauteur et la largeur. Vous devriez mettre une div autour de lui. Si vous contrôlez le contenu dans l'iframe, vous pouvez insérer du code JS dans le contenu de l'iframe qui indiquera au parent de faire défiler le div lorsque l'événement touch est reçu. 

comme ça:

Le JS:

setTimeout(function () {
var startY = 0;
var startX = 0;
var b = document.body;
b.addEventListener('touchstart', function (event) {
    parent.window.scrollTo(0, 1);
    startY = event.targetTouches[0].pageY;
    startX = event.targetTouches[0].pageX;
});
b.addEventListener('touchmove', function (event) {
    event.preventDefault();
    var posy = event.targetTouches[0].pageY;
    var h = parent.document.getElementById("scroller");
    var sty = h.scrollTop;

    var posx = event.targetTouches[0].pageX;
    var stx = h.scrollLeft;
    h.scrollTop = sty - (posy - startY);
    h.scrollLeft = stx - (posx - startX);
    startY = posy;
    startX = posx;
});
}, 1000);

Le HTML:

<div id="scroller" style="height: 400px; width: 100%; overflow: auto;">
<iframe height="100%" id="iframe" scrolling="no" width="100%" id="iframe" src="url" />
</div>

Si vous ne contrôlez pas le contenu de l'iframe, vous pouvez utiliser une superposition de manière similaire, mais vous ne pouvez pas interagir avec le contenu de l'iframe autrement que pour le faire défiler. Vous ne pouvez donc pas cliquer sur liens dans l'iframe.

Auparavant, vous pouviez utiliser deux doigts pour faire défiler une iframe, mais cela ne fonctionne plus.

Mise à jour: iOS 6 a cassé cette solution pour nous.Je tente d'obtenir un nouveau correctif, mais rien n'a encore fonctionné. En outre, il n’est plus possible de déboguer du code javascript sur le périphérique, car ils ont introduit Remote Web Inspector, qui nécessite un Mac.

20
Case

Si le contenu d'iFrame ne vous appartient pas, la solution ci-dessous ne fonctionnera pas.

Avec Android, tout ce que vous avez à faire est d’entourer l’iframe d’un DIV et de définir la hauteur du div sur document.documentElement.clientHeight. IOS, cependant, est un animal différent. Bien que je n’aie pas encore essayé la solution de Sharon, elle me semble une bonne solution. J'ai trouvé une solution plus simple, mais elle ne fonctionne qu'avec IOS 5. +.

Entourez votre élément iframe d'un DIV (appelons-le scroller), définissez la hauteur du DIV et assurez-vous que le nouveau DIV a le style suivant:

$('#scroller').css({'overflow' : 'auto', '-webkit-overflow-scrolling' : 'touch'});

Cela seul fonctionnera, mais vous remarquerez que dans la plupart des implémentations, le contenu de l'iframe devient vierge lors du défilement et est rendu inutilisable. D'après ce que j'ai compris, ce problème a été signalé comme un bogue à Apple dès iOS 5.0. Pour contourner ce problème, recherchez l'élément body dans l'iframe et ajoutez -webkit-transform ',' translate3d (0, 0, 0) comme suit:

$('#contentIframe').contents().find('body').css('-webkit-transform', 'translate3d(0, 0, 0)');

Si votre application ou votre iframe utilise beaucoup de mémoire, vous pouvez obtenir un défilement incohérent pour lequel vous devrez peut-être utiliser la solution de Sharon.

11
Tmac

Cela ne fonctionne que si vous contrôlez la page externe et la page iframe.

Sur la page extérieure, indiquez iframe inscrollable.

<iframe src="" height=200 scrolling=no></iframe>

Sur la page iframe, ajoutez ceci.

<!doctype html>
...
<style>
html, body {height:100%; overflow:hidden}
body {overflow:auto; -webkit-overflow-scrolling:touch}
</style>

Cela fonctionne parce que les navigateurs modernes utilisent html pour déterminer la hauteur. Nous lui attribuons donc une hauteur fixe et transformons la body en un nœud pouvant défiler.

10
Kernel James

J'ai mis le code de @ Sharon dans ce qui suit, ce qui fonctionne pour moi sur l'iPad avec défilement à deux doigts. La seule chose que vous devriez changer pour que cela fonctionne est l'attribut src de l'iframe (j'ai utilisé un document PDF).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Pdf Scrolling in mobile Safari</title>
</head>
<body>
<div id="scroller" style="height: 400px; width: 100%; overflow: auto;">
<iframe height="100%" id="iframe" scrolling="no" width="100%" id="iframe" src="data/testdocument.pdf" />
</div>
<script type="text/javascript">
    setTimeout(function () {
        var startY = 0;
        var startX = 0;
        var b = document.body;
        b.addEventListener('touchstart', function (event) {
            parent.window.scrollTo(0, 1);
            startY = event.targetTouches[0].pageY;
            startX = event.targetTouches[0].pageX;
        });
        b.addEventListener('touchmove', function (event) {
            event.preventDefault();
            var posy = event.targetTouches[0].pageY;
            var h = parent.document.getElementById("scroller");
            var sty = h.scrollTop;

            var posx = event.targetTouches[0].pageX;
            var stx = h.scrollLeft;
            h.scrollTop = sty - (posy - startY);
            h.scrollLeft = stx - (posx - startX);
            startY = posy;
            startX = posx;
        });
    }, 1000);
    </script>
</body>
</html>
4
Eric Pohl
<div id="scroller" style="height: 400px; width: 100%; overflow: auto;">
<iframe height="100%" id="iframe" scrolling="no" width="100%" src="url" />
</div>

Je construis mon premier site et cela m'a aidé à le faire fonctionner pour tous les sites pour lesquels j'intègre iframe. 

Merci!

3
Krossyomind

La méthode de Sharon a fonctionné pour moi, cependant, lorsqu'un lien dans l'iframe est suivi, puis que le bouton Précédent du navigateur est activé, la version en cache de la page est chargée et l'iframe ne peut plus défiler. Pour surmonter cela, j'ai utilisé du code pour actualiser la page comme suit:

if ('ontouchstart' in document.documentElement)
     {
        document.getElementById('Scrolling').src = document.getElementById('SCrolling').src;
    }
1
Phil Green

Ne faites pas défiler la page IFrame ou son contenu, faites défiler la page parent. Si vous contrôlez le contenu IFrame, vous pouvez utiliser la bibliothèque iframe-resizer pour transformer l'élément iframe lui-même en un élément de niveau de bloc approprié, avec une hauteur naturelle/correcte/native. De même, n'essayez pas de positionner (fixe, absolu) votre iframe dans la page parent, ni de présenter un iframe dans une fenêtre modale, surtout si elle contient des éléments de formulaire.

Je soupçonne également qu'iOS Safari a un comportement non standard qui étend la hauteur de votre iframe à sa hauteur naturelle, un peu comme le ferait la bibliothèque iframe-resizer pour les navigateurs de bureau, qui semblent rendre le contenu iframe réactif à une hauteur de 0px ou 150px ou autre pas utile par défaut. Si vous devez limiter la largeur, essayez un style de largeur maximale à l'intérieur de l'iframe.

0
spaceRace

J'ai implémenté ce qui suit et ça marche bien. Fondamentalement, je définis les dimensions du corps en fonction de la taille du contenu iFrame. Cela signifie que vous pouvez faire défiler notre menu non iFrame, mais sinon, nos sites sont fonctionnels avec iPad et iPhone. "workbox" est l'identifiant de notre iFrame.

// Configure for scrolling peculiarities of iPad and iPhone

if (navigator.userAgent.indexOf('iPhone') != -1 || navigator.userAgent.indexOf('iPad') != -1)
{
    document.body.style.width = "100%";
    document.body.style.height = "100%";
    $("#workbox").load(function (){ // Wait until iFrame content is loaded before checking dimensions of the content
        iframeWidth = $("#workbox").contents().width();
        if (iframeWidth > 400)
           document.body.style.width = (iframeWidth + 182) + 'px';

        iframeHeight = $("#workbox").contents().height();
        if (iframeHeight>200)
            document.body.style.height = iframeHeight + 'px';
     });
}
0
MSchimpf

En utilisant purement le code de MSchimpf et Ahmad, j'ai apporté des ajustements afin de pouvoir insérer l'iframe au sein d'une div, conservant ainsi un en-tête et un pied de page pour le bouton Précédent et le marquage de ma page. Code mis à jour:

<script type="text/javascript">
    $("#webview").bind('pagebeforeshow', function(event){
        $("#iframe").attr('src',cwebview);
    });

    if (navigator.userAgent.indexOf('iPhone') != -1 || navigator.userAgent.indexOf('iPad') != -1)
    {
        $("#webview-content").css("width","100%");
        $("#webview-content").css("height","100%");
        $("#iframe").load(function (){ // Wait until iFrame content is loaded before checking dimensions of the content
            iframeWidth = $("#iframe").contents().width();
            if (iframeWidth > 400)
               $("#webview-content").css("width",(iframeWidth + 182) + 'px');

            iframeHeight = $("#iframe").contents().height();
            if (iframeHeight>200)
                $("#webview-content").css("height",iframeHeight + 'px');
         });
    }       
</script>  

et le html

<div class="header" data-role="header" data-position="fixed">
</div>

<div id="webview-content" data-role="content" style="height:380px;">
    <iframe id="iframe"></iframe>   
</div><!-- /content -->

<div class="footer" data-role="footer" data-position="fixed">
</div><!-- /footer -->   
0
dgig