Comment faire en sorte qu'un IFrame soit réactif dans iOS Safari?

134

Le problème est que lorsque vous devez utiliser IFrames pour insérer du contenu dans un site Web, alors dans le monde Web moderne, on s'attend à ce que l'IFrame soit également réactif. En théorie, c'est simple, aidez simplement à utiliser <iframe width="100%"></iframe>ou à définir la largeur CSS, iframe { width: 100%; }mais en pratique, ce n'est pas aussi simple, mais cela peut l'être.

Si le iframecontenu est entièrement réactif et peut se redimensionner sans barres de défilement internes, iOS Safari redimensionnera le iframesans aucun problème réel.

Si vous considérez le code suivant:

<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=9,10,11" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Iframe Isolation Test</title>

    <style type="text/css" rel="stylesheet">

        #Main {
            padding: 10px;
        }
    </style>
</head>
<body>
    <h1>Iframe Isolation Test 13.17</h1>
    <div id="Main">
        <iframe height="950" width="100%" src="Content.html"></iframe>
    </div>
</body>
</html>

Avec le Content.html :

<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=9,10,11" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Iframe Isolation Test - Content</title>

    <style type="text/css" rel="stylesheet">

        #Main {
            width: 100%;
            background: #ccc;
        }

    </style>
</head>
<body>
    <div id="Main">
        <div id="ScrolledArea">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc malesuada purus quis commodo convallis. Fusce consectetur mauris eget purus tristique blandit. Nam nec volutpat augue. Aliquam sit amet augue vitae orci fermentum tempor sit amet gravida augue. Pellentesque convallis velit eu malesuada malesuada. Aliquam erat volutpat. Nam sollicitudin nulla nec neque viverra, non suscipit purus tincidunt. Aenean blandit nisi felis, sit amet ornare mi vestibulum ac. Praesent ultrices varius arcu quis fringilla. In vitae dui consequat, rutrum sapien ut, aliquam metus. Proin sit amet porta velit, suscipit dignissim arcu. Cras bibendum tellus eu facilisis sodales. Vestibulum posuere, magna ut iaculis consequat, tortor erat vulputate diam, ut pharetra sapien massa ut magna. Donec massa purus, pharetra sed pellentesque nec, posuere ut velit. Nam venenatis feugiat odio quis tristique. 
        </div>      
    </div>
</body>
</html>

Ensuite, cela fonctionne sans problème dans iOS 7.1 Safari. Vous pouvez passer du paysage au portrait sans aucun problème.

entrez la description de l'image ici entrez la description de l'image ici

Cependant, en changeant simplement le CSS Content.html en ajoutant ceci:

    #ScrolledArea {
        width: 100%;
        overflow: scroll;
        white-space: nowrap;
        background: #ff0000;
    }

Vous obtenez ceci:

entrez la description de l'image ici entrez la description de l'image ici

Comme vous pouvez le voir, même si le contenu Content.html est entièrement réactif ( div # ScrolledArea a été overflow: scrolldéfini) et que la largeur de l'iframe est de 100%, l'iframe prend toujours toute la largeur du div # ScrolledArea comme si le débordement n'existait même pas. Démo

Dans des cas comme celui-ci, si le iframecontenu comporte des zones de défilement, la question devient: comment obtenir le iframeréactif, lorsque le contenu iframe a des zones de défilement horizontal? Le problème ici ne réside pas dans le fait que Content.html n'est pas réactif, mais dans le fait que iOS Safari redimensionne simplement l'iframe pour que le div#ScrolledAreasoit entièrement visible.

Idra
la source
Pouvez-vous partager un lien avec nous? Êtes-vous en train de dire qu'iOS étendra un iFrame sur toute la largeur de la page si la page contient du contenu avec du white-space: nowrapstyle?
DA.
@DA J'ai ajouté des démos au problème et à la solution. Et non, white-space: nowraple problème n'est pas en soi. Je l'utilise simplement pour obtenir une largeur extrême div#ScrolledArea. Le problème survient lorsque le contenu IFrame contient des zones de défilement horizontal. Si tel est le cas, iOS Safari ignore simplement vos paramètres de largeur et affiche le contenu du trou et brise la réactivité du site.
Idra
Hmm ... Je me demande si c'est une «fonctionnalité». Il serait gênant d'avoir une zone de défilement (iFrame) contenant du contenu à défilement. Ce serait une chose très difficile d'interagir avec un écran tactile.
DA.
@DA Bien sûr, c'est un cas de nièce, et ce que vous avez dit peut être vrai (cela dépend de l'implémentation, cela fonctionne pour nous) et la plupart des sites n'ont pas de zones de défilement horizontal, mais quand vous le faites ... vous ne pouvez même pas imaginer combien de temps j'ai passé là-dessus. Mais cela peut être un problème même si vous avez des images qui sont cachées et défilées avec des boutons ou quelque chose comme ça.
Idra
Il semble qu'il y ait des questions connexes à ce sujet: stackoverflow.com/questions/5267996/ ... Cela semble être une `` fonctionnalité '' de safari mobile ... il essaie de s'assurer que le contenu est dimensionné de manière à ce que l'utilisateur puisse interagissez toujours avec lui. Je ne sais pas ce qui se passerait si vous aviez du contenu défilant dans une iframe défilante ... comment Safari interpréterait-il un balayage dans des éléments défilants imbriqués?
DA.

Réponses:

289

La solution à ce problème est en fait assez simple et il existe deux façons de le résoudre. Si vous avez le contrôle sur Content.html, modifiez simplement la div#ScrolledArealargeur CSS en:

        width: 1px;
        min-width: 100%;
        *width: 100%;

Fondamentalement, l'idée ici est simple, vous définissez le widthsur quelque chose qui est plus petit que la fenêtre (largeur de l'iframe dans ce cas), puis écrasez-le avec min-width: 100%pour permettre le remplacement réel de width: 100%Safari iOS par défaut. Le *width: 100%;est là pour que le code reste compatible IE6, mais si vous ne vous souciez pas d'IE6, vous pouvez l'omettre. Démo

entrez la description de l'image ici entrez la description de l'image ici

Comme vous pouvez le voir maintenant, la div#ScrolledArealargeur est en fait de 100% et le overflow: scroll;peut faire son travail et cacher le contenu débordant. Si vous avez accès au contenu iframe, c'est préférable.

Cependant, si vous n'avez pas accès au contenu de l'iframe (quelle qu'en soit la raison), vous pouvez en fait utiliser la même technique sur l'iframe lui-même. Utilisez simplement le même CSS sur l'iframe:

    iframe {
        width: 1px;
        min-width: 100%;
        *width: 100%;
    }

Cependant, il y a une limitation à cela, vous devez désactiver les barres de défilement avec scrolling="no"sur l'iframe pour que cela fonctionne:

<iframe height="950" width="100%" scrolling="no" src="Content.html"></iframe>

Si les barres de défilement sont autorisées, cela ne fonctionnera plus sur l'iframe. Cela dit, si vous modifiez le Content.html à la place, vous pouvez conserver le défilement dans l'iframe. Démo

Idra
la source
1
Comme @NickGottlieb mentionné, j'ai dû ajouter !importantà l' widthattribut pour que l'iframe responsive-web-design soit prêt sur un iPhone 4 avec iOS 7
malisokan
@ ЮнгвиртТони Cela ne devrait pas être nécessaire pour que la solution de contournement fonctionne, il est possible que le ait widthété défini plus tôt !importantou qu'un CSS de priorité plus élevée l'ait écrasé. Dans des cas isolés sur iPhone 4 iOS7, ce n'était pas nécessaire.
Idra
Je n'avais pas besoin! Important non plus. Fonctionne très bien sur iOS 8 aussi. Cheers
Sam Potts
J'ai besoin de scrolling = non seulement lorsque cela est nécessaire, sinon scrolling = yes. Alors, que dois-je détecter? Est-ce un problème iOS? ou un problème de kit Web? ou...?
gerbz
@ggwarpig il s'agit d'un problème iOS, dans lequel iOS Safari active automatiquement l'attribut transparent et vous ne pouvez pas l'écraser. Si vous avez le contrôle sur le contenu, alors vous devez modifier le contenu afin d'avoir scrolling="yes"sinon il n'y a aucun moyen de corriger cela, pour que le correctif fonctionne sur IFRAME, il vous suffit d'avoir scrolling="no"sur l'IFRAME
Idra
24

Le problème, semble-t-il, est que Mobile Safari refusera d'obéir à la largeur de votre iFrame si le document qu'il contient est plus large que ce que vous avez spécifié. Exemple:

http://jsbin.com/hapituto/1

Sur un navigateur de bureau, vous verrez un iFrame et un Div tous les deux réglés sur 300 pixels. Le contenu est plus large afin que vous puissiez faire défiler l'iFrame.

Sur mobile safari, cependant, vous remarquerez que l'iFrame est automatiquement étendu à la largeur du contenu.

Je suppose que c'est une solution de contournement pour les problèmes de longue date avec le défilement du contenu dans une page. Dans le passé, si vous aviez une grande iframe à défilement sur un appareil tactile, vous restiez `` coincé '' dans l'iframe car cela ferait défiler au lieu de la page elle-même. Il semble qu'Apple ait décidé que le comportement par défaut d'un iFrame est «pas de défilement» et se développe pour l'empêcher.

Une option peut être cette solution de contournement. Au lieu de supposer que l'iFrame défilera, placez l'iframe dans un DIV sur lequel vous avez le contrôle et laissez-le défiler.

exemple: http://jsbin.com/zakedaja/1

Exemple de balisage:

<div style="overflow: scroll; -webkit-overflow-scrolling: touch; width: 300px;">
   <iframe src="http://jsbin.com/roredora/1/" style="width: 600px;"></iframe>
</div>

Sur mobile safari, vous pouvez maintenant faire défiler le contenu de l'iFrame maintenant entièrement développé via le div qui le contient.

Le hic: Cela semble vraiment moche sur un navigateur de bureau, car vous avez maintenant des barres de défilement doubles. Vous devrez peut-être faire une détection de navigateur avec JS pour contourner ce problème.

DA.
la source
1
Je maintiendrai toujours que ce n'est pas vraiment dans le cadre de la question, car la solution que vous avez montrée ici est la manière standard de simuler le défilement iframe de trou dans iOS Safari, mais prendre en considération ce problème iOS est un problème concernant le défilement IFrame (contenu ou autre) alors c'est bien de l'avoir ici.
Idra
1
Je suppose que je ne comprends pas entièrement votre question. D'après ce que je comprends, le problème que vous rencontrez est que dans iOS, Mobile Safari essaie d'empêcher un iFrame de défiler en premier lieu et lui impose une largeur. Suis-je mal compris votre problème?
DA.
C'est essentiellement le problème, c'est juste que la solution requise est différente. Dans le problème initial, le contenu IFrame était réactif, tout en ayant un contenu à défilement horizontal, la question n'était donc pas de savoir comment émuler le défilement iframe , mais comment faire en sorte que la largeur de l'iframe soit à 100%, c'est-à-dire réactive, alors que vous avez un contenu à défilement horizontal avec in cette iframe. C'est pourquoi l'approche ci-dessus ne fonctionne pas dans ce cas, car la réactivité conçue a été interrompue et vous devez faire défiler pour voir le contenu complet, même dans des endroits par conception dont vous n'auriez normalement pas besoin.
Idra
1
Je m'excuse, j'ai réalisé que je vous avais induit en erreur sur l'un des commentaires. L'iframe ne défile pas. C'était le point, l'iframe n'était pas censé faire défiler uniquement certaines parties de son contenu, c'est-à-dire le div#ScrolledArea(en vert) dans mon exemple. J'ai juste mal lu avant. Mais l'iframe ne doit pas défiler uniquement en se redimensionnant en fonction de l'élément conteneur, c'est-à-dire avoirwidth: 100%;
Idra
18

J'avais besoin d'une solution multi-navigateurs. Les exigences étaient:

  • nécessaire pour fonctionner à la fois sur iOS et ailleurs
  • n'ont pas accès au contenu de l'iFrame
  • besoin de faire défiler!

En s'appuyant sur ce que j'ai appris de @Idra concernant le scrolling = "no" sur iOS et ce post sur l'ajustement du contenu iFrame à l'écran sous iOS, voici ce que j'ai obtenu. J'espère que ça aide quelqu'un =)

HTML

<div id="url-wrapper"></div>

CSS

html, body{
    height: 100%;
}

#url-wrapper{
    margin-top: 51px;
    height: 100%;
}

#url-wrapper iframe{
    height: 100%;
    width: 100%;
}

#url-wrapper.ios{
    overflow-y: auto;
    -webkit-overflow-scrolling:touch !important;
    height: 100%;
}

#url-wrapper.ios iframe{
    height: 100%;
    min-width: 100%;
    width: 100px;
    *width: 100%;
}

JS

function create_iframe(url){

    var wrapper = jQuery('#url-wrapper');

    if(navigator.userAgent.match(/(iPod|iPhone|iPad)/)){
        wrapper.addClass('ios');
        var scrolling = 'no';
    }else{
        var scrolling = 'yes';
    }

    jQuery('<iframe>', {
        src: url,
        id:  'url',
        frameborder: 0,
        scrolling: scrolling
    }).appendTo(wrapper);

}
Gerbz
la source
1
voté, mais ... pourquoi la règle IE6 dans la classe "ios"? :-)
J. Bruni
12

Le problème avec toutes ces solutions est que la hauteur des iframechangements ne change jamais vraiment.

Cela signifie que vous ne pourrez pas centrer les éléments à l'intérieur du iframeJavascript position:fixed;, ou position:absolute;puisque le iframelui - même ne défile jamais.

Ma solution détaillée ici est d'envelopper tout le contenu de l'iframe dans un en divutilisant ce CSS:

#wrap {
    position: fixed;
    top: 0;
    right:0;
    bottom:0;
    left: 0;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
}

De cette façon, Safari pense que le contenu n'a pas de hauteur et vous permet d'attribuer iframecorrectement la hauteur du . Cela vous permet également de positionner les éléments comme vous le souhaitez.

Vous pouvez voir une démo rapide et sale ici.

Jetée
la source
1
C'est la seule solution qui a fonctionné pour moi. Bien sûr, il ne peut être utilisé que si vous contrôlez le contenu du iframe, mais dans mon cas, je le fais. À votre santé!
Vince
Hmm. Votre exemple ne semble pas réactif sur iOS?
BrandonReid
C'était il y a 2 ans quand j'ai écrit ceci. Pouvez-vous déposer un problème dans le repo?
Pier
après avoir perdu des heures et des heures sur ce problème avec Ionic / Cordova sur iOS, c'est la seule chose qui a fonctionné. Merci!
Andrew
1
C'est génial, le seul qui a fonctionné, j'ai passé 1 jour à chercher une solution comme celle-ci @Pier 100pts pour vous
Carlos E
5

Ce problème est également présent sur iOS Chrome.

J'ai jeté un œil à toutes les solutions ci-dessus, la plupart sont très piratées.

Si vous n'avez pas besoin de support pour les navigateurs plus anciens, définissez simplement la largeur de l'iframe sur 100vw;

iframe {
  max-width: 100%; /* Limits width to 100% of container */
  width: 100vw; /* Sets width to 100% of the viewport width while respecting the max-width above */
}

Remarque: vérifiez la prise en charge des unités de fenêtre https://caniuse.com/#feat=viewport-units

Prathamesh Gharat
la source
1
Chrome pour iOS est juste Safari en dessous. Il utilise WKWebView. Aucun autre moteur de rendu Web n'est autorisé dans iOS.
Pier
3

Je travaille avec ionic2 et la configuration du système est comme ci-dessous-


******************************************************

Your system information:

Cordova CLI: 6.4.0 
Ionic Framework Version: 2.0.0-beta.10
Ionic CLI Version: 2.1.8
Ionic App Lib Version: 2.1.4
ios-deploy version: Not installed
ios-sim version: 5.0.8 
OS: OS X Yosemite
Node Version: v6.2.2
Xcode version: Xcode 7.2 Build version 7C68



******************************************************

Pour moi, ce problème a été résolu avec ce code -
pour la balise iframe html -

<div class="iframe_container">
      <iframe class= "animated fadeInUp" id="iframe1" [src]='page' frameborder="0" >
        <!--  <img src="img/video-icon.png"> -->
      </iframe><br>
   </div>

Voir css de même que-


.iframe_container {
  overflow: auto; 
  position: relative; 
  -webkit-overflow-scrolling: touch;
  height: 75%;
}

iframe {
  position:relative;
  top: 2%;
  left: 5%;
  border: 0 !important;
  width: 90%;
}

La propriété de position joue ici un rôle vital dans mon cas.
position: relative;

Cela peut vous aider aussi !!!

S.Yadav
la source
0

Solution CSS uniquement

HTML

<div class="container">
    <div class="h_iframe">
        <iframe  src="//www.youtube.com/embed/9KunP3sZyI0" frameborder="0" allowfullscreen></iframe>
    </div>
</div>

CSS

html,body {
    height:100%;
}
.h_iframe iframe {
    position:absolute;
    top:0;
    left:0;
    width:100%;
    height:100%;
}

DEMO

Une autre démo ici avec une page HTML en iframe

4dgaurav
la source
Peut-être que j'implémente votre solution de manière incorrecte, mais lorsque je l'ai essayé avec mon cas de test isolé, cela n'a pas fonctionné, du tout dans iOS Safari 7.1 iPhone 4. Pouvez-vous expliquer comment cela devrait fonctionner?
Idra
OK, il semble que vous ayez mal compris le problème, vérifiez ce lien, c'est votre nouveau contenu iframe de démonstration intégré sans aucun CSS supplémentaire appliqué à l'iframe. Et si vous le regardez dans iOS Safari, il est toujours réactif, car cette page n'a pas de défilement horizontal qui forcerait la largeur de l'iframe à être plus large que la fenêtre. Comme décrit dans la question, sur un site comme celui-ci, vous n'avez rien à faire pour que l'iframe soit réactif.
Idra
Alors, que voulez-vous exactement qu'il se comporte, donnez l'exemple de votre lien donné?
4dgaurav
0

J'ai eu un problème avec la largeur du volet de contenu en créant une barre de défilement horizontale pour l'iframe. Il s'est avéré qu'une image tenait la largeur plus large que prévu. J'ai pu le résoudre en définissant toutes les images css max-width à un pour cent.

<meta name="viewport" content="width=device-width, initial-scale=1" />

img {
        max-width: 100%;
        height:auto;
    }
Dr Aaron Dishno
la source
0

en fait pour moi je viens de travailler dans ios en désactivant le défilement

<iframe src="//www.youraddress.com/" scrolling="no"></iframe>

et traiter le système d'exploitation via un script.

Luiz Rossi
la source
0

Pour moi, les solutions CSS ne fonctionnaient pas. Mais définir la largeur par programme fait le travail. Lors du chargement d'iframe, définissez la largeur par programme:

 $('iframe').width('100%');
umer
la source