How to get an IFrame to be responsive in iOS Safari?
Asked Answered
L

10

143

The problem is that when you have to use IFrames to insert content into a website, then in the modern web-world it is expected that the IFrame would be responsive as well. In theory it's simple, simply aider use <iframe width="100%"></iframe> or set the CSS width to iframe { width: 100%; } however in practice it's not quite that simple, but it can be.

If the iframe content is fully responsive and can resize itself without internal scroll bars, then iOS Safari will resize the iframe without any real issues.

If you consider the following code:

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

With the 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>

Then this works without issues in iOS 7.1 Safari. You can change between landscape and portrait without any issues.

enter image description here enter image description here

However by simply changing the Content.html CSS by adding this:

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

You get this:

enter image description here enter image description here

As you can see, even though the Content.html content is fully responsive (div#ScrolledArea has overflow: scroll set) and the iframe width is 100% the iframe still takes the full width of the div#ScrolledArea as if the overflow does not even exist. Demo

In cases like this, were the iframecontent has scrolling areas on it, the question becomes, how to get the iframe responsive, when the iframe content has horizontally scrolling areas? The problem here is not in the fact that the Content.html is not responsive, but in the fact that the iOS Safari simply resizes the iframe so that the div#ScrolledArea would be fully visible.

Liberalism answered 15/4, 2014 at 12:15 Comment(8)
Can you share a link with us? Are you saying that iOS will expand an iFrame to the full width of the page within if the page within has content with white-space: nowrap style?Maunder
@DA I added demos to both the problem and the solution. And no, the white-space: nowrap in itself is not the problem. I am simply using it to get an extreme width to div#ScrolledArea. The problem comes when the IFrame content has horizontally scrollable areas in it. If that is the case, the iOS Safari simply ignores your width settings and shows the hole content and breaking the responsiveness of the site.Liberalism
Hmm...I wonder if that's a 'feature'. It would be awkward to have a scrollable area (iFrame) that contains scrollable content. It'd be a very difficult thing to interact with on a touch screen.Maunder
@DA Of course this is a niece case, and what you said can be true (depends on the implementation, works for us) and most sites do not have horizontally scrollable areas, but when you do... you can't even imagine how much time I've spent on this. But this can be an issue even if you have images that are hidden and scrolled with buttons or something like that.Liberalism
It looks like there are related questions about this: #5268496 It does appear to be a 'feature' of mobile safari...it's trying to ensure that the content is being sized in way that the user can still interact with it. I'm not sure what would happen if you have scrolling content in a scrolling iframe...how would Safari interpret a swipe within nested scrolling elements?Maunder
@DA yes I know this, but that is a different case. I could have coverd that as well, but yes... too long and out of the scope of this question.Liberalism
I think it's related. In fact, I think the issue is simply that Mobile Safari will force the iFrame to always be as wide as the content within. Example: jsbin.com/hapituto/1Maunder
Does this answer your question? Making an iframe responsiveMote
L
298

The solution for this problem is actually quite simple and there are two ways to go about it. If you have control over the Content.html then simply change the div#ScrolledArea width CSS to:

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

Basically the idea here is simple, you set the width to something that is smaller than the viewport (iframe width in this case) and then overwrite it with min-width: 100% to allow for actual width: 100% which iOS Safari by default overwrites. The *width: 100%; is there so the code would remain IE6 compatible, but if you do not care for IE6 you can omit it. Demo

enter image description here enter image description here

As you can see now, the div#ScrolledArea width is actually 100% and the overflow: scroll; can do it's thing and hide the overflowing content. If you have access to the iframe content, then this is preferable.

However if you do not have access to the iframe content (for what ever reason) then you can actually use the same technique on the iframe itself. Simply use the same CSS on the iframe:

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

However, there is one limitation with this, you need to turn off the scrollbars with scrolling="no" on the iframe for this to work:

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

If the scrollbars are allowed, then this wont work on the iframe anymore. That said, if you modify the Content.html instead then you can retain the scrolling in the iframe. Demo

Liberalism answered 15/4, 2014 at 12:15 Comment(8)
Like @NickGottlieb mentioned, I had to add !important to the width attribute to get the iframe responsive-web-design ready on an iPhone 4 with iOS 7Misdeal
@ЮнгвиртТони It should not be needed for the workaround to work, it is possible that the width was set earlier with !important or a higher priority CSS overwrote it. In isolated cases in iPhone 4 iOS7 it was not needed.Liberalism
I didn't need !important either. Works great on iOS 8 too. CheersNewsstand
I need scrolling=no only when necessary, otherwise scrolling=yes. So what should I be detecting? Is this an iOS issue? or a webkit issue? or...?Elinaelinor
@ggwarpig this is a iOS issue, where the iOS Safari automatically turnes the seamless attribute on and you can't overwrite it. If you have control over the content, then you need to modify the contents in order to have scrolling="yes" otherwise there is no way to correct this, for the fix to work on IFRAME only you need to have scrolling="no" on the IFRAMELiberalism
Can you help me how can I use iFrame Youtube embeding, here's an iFrame for example: <iframe width="(view.frame.height)" height="(view.frame.width)" src="youtube-nocookie.com/embed/…" frameborder="0" allowfullscreen></iframe> , I'm switching the height and width because I'm in landscape mode, but this is not getting the real values, what should I add to fix it? ThanksArdeliaardelis
This is the solution that wound up working for me, circa April 2018: github.com/ampproject/amphtml/issues/11133 - Setting width & height to 0, then min- and max- for both w & h to 100%. Especially frustrating to troubleshoot since both Chrome 65 & Safari 11.1 show everything as looking fine in device emulation mode, while the real devices (iPhone SE, 6) have portrait overflow issues.Tatouay
If you set scrolling="no" on the iframe, but the content needs to scroll (for example if the content is larger than the container), this solution does not work. Essentially this solution only works if the content of the iframe fits the container exactly, or is smaller.Abebi
M
24

The problem, it seems, is that Mobile Safari will refuse to obey the width of your iFrame if the document it contains is wider than what you have specified. Example:

http://jsbin.com/hapituto/1

On a desktop browser, you will see an iFrame and a Div both set to 300px. The contents is wider so you can scroll the iFrame.

On mobile safari, however, you will notice that the iFrame is auto-expanded to the width of the content.

My guess is that this is a workaround for long-standing issues with scrolling content within a page. In the past, if you had a large scrolling iframe on a touch device, you'd get 'stuck' in the iframe as that would be scrolling instead of the page itself. It appears Apple has decided that the default behavior of an iFrame is 'no scroll' and expands to prevent it.

One option may be this workaround. Instead of assuming the iFrame will scroll, place the iframe in a DIV that you do have control over and let that scroll.

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

Example markup:

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

On mobile safari, you can now scroll the contents of the now fully-expanded iFrame via the div that is containing it.

The catch: This looks really ugly on a desktop browser, as now you have double scrollbars. So you may have to do some browser detection with JS to get around this.

Maunder answered 17/4, 2014 at 3:2 Comment(4)
I would still maintain that this is not really in the scope of the question, because the solution you showed here is the standard way how to fake the hole iframe scrolling in iOS Safari, but taking into consideration this iOS problem is an issue regarding IFrame scrolling (content or otherwise) then its nice to have it here.Liberalism
I guess I don't fully understand your question. From what I understand, the problem you are having is that in iOS, Mobile Safari tries to prevent an iFrame from scrolling in the first place and forces a width upon it. Am I misunderstanding your problem?Maunder
In essence that is the problem, its just the required solution is different. In the initial problem, the IFrame content was responsive, while having horizontally scrolling content so the question was not how to emulate the iframe scrolling, but how to get the iframe width to be 100% i.e. responsive, while you have horizontally scrolling content with in that iframe. That's why the above approach does not work in this case, because the designed responsiveness has been broken and you need to scroll around to see the full content, even in places were by design you normally would not need to.Liberalism
I do apologize, I realized that I misled you on one of the comments. The iframe is not scrolling. That was the point, the iframe was not supposed to be scrolling only parts of it's content i.e. the div#ScrolledArea (in green) in my example. I just misread before. But the iframe should not be scrolling only resizing itself based on the container element i.e. have width: 100%;Liberalism
E
18

I needed a cross-browser solution. Requirements were:

  • needed to work on both iOS and elsewhere
  • don't have access to the content in the iFrame
  • need it to scroll!

Building off what I learned from @Idra regarding scrolling="no" on iOS and this post about fitting iFrame content to the screen in iOS here's what I ended up with. Hope it helps someone =)

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

}
Elinaelinor answered 28/4, 2015 at 23:47 Comment(1)
upvoted, but... why the IE6 rule in the "ios" class ? :-)Eaglet
B
12

The problem with all these solutions is that the height of the iframe never really changes.

This means you won't be able to center elements inside the iframe using Javascript, position:fixed;, or position:absolute; since the iframe itself never scrolls.

My solution detailed here is to wrap all the content of the iframe inside a div using this CSS:

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

This way Safari believes the content has no height and lets you assign the height of the iframe properly. This also allows you to position elements in any way you wish.

You can see a quick and dirty demo here.

Bridie answered 22/7, 2016 at 19:27 Comment(5)
This is the only solution that worked for me. Of course, it can only be used if you control the contents of the iframe, but in my case, I do. Cheers!Zampardi
Hmm. Your example doesn't seem to be responsive on iOS?Timmons
It was 2 years ago when I wrote this. Can you file an issue in the repo?Bridie
after wasting hours and hours on this issue with Ionic/Cordova on iOS, this is the only thing that worked. thanks!Gordan
This is awesome, the only that worked, I've spent 1 day searching for a solution like this @Bridie 100pts to youPantheon
S
5

This issue is also present on iOS Chrome.

I glanced through all the solutions above, most are very hacky.

If you don't need support for older browsers, just set the iframe width to 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 */
}

Note : Check support for viewport units https://caniuse.com/#feat=viewport-units

Stolzer answered 13/9, 2018 at 8:33 Comment(1)
Chrome for iOS is just Safari underneath. It uses WKWebView. No other web rendering engine is allowed in iOS.Bridie
U
3

I am working with ionic2 and system config is as below-


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

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



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

For me this issue got resolved with this code-
for html iframe tag-

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

See css of the same as-


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

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

Position property play a vital role here in my case.
position:relative;

It may help you too!!!

Urnfield answered 16/11, 2016 at 12:25 Comment(0)
P
1

I had an issue with width on the content pane creating a horizontal scroll bar for the iframe. It turned out that an image was holding the width wider than expected. I was able to solve it by setting the all of the images css max-width to a percent.

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

img {
        max-width: 100%;
        height:auto;
    }
Perpetua answered 18/8, 2015 at 20:56 Comment(1)
that actually did the job for me without need for cssEscargot
V
0

CSS only solution

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

Another demo here with HTML page in iframe

Variegate answered 15/4, 2014 at 12:27 Comment(3)
Maybe I am implementing your solution incorrectly, but when I tried it with my isolated test case, then it did not work, at all in iOS Safari 7.1 iPhone 4. Could you elaborate on how this should work?Liberalism
OK it seams like you misunderstood the issue, check this link out it's your new demo iframe content integrated without any additional CSS applied to the iframe. And if you look it over in iOS Safari, then it is still responsive, this is because this page does not have the any horizontal scrolling that would force the iframe width to be wider than the viewport. As described in the question, on a site like this you do not need to do anything for the iframe to be responsive.Liberalism
so what exactly you want it to behave, give example for your given link?Variegate
A
0

in fact for me just worked in ios disabling the scroll

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

and treating the OS via script.

Ardenardency answered 17/5, 2018 at 20:48 Comment(0)
T
0

For me CSS solutions didn't work. But setting the width programmatically does the job. On iframe load set the width programmatically:

 $('iframe').width('100%');
Tews answered 25/6, 2019 at 13:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.