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.

Idra
  • 5,777
  • 4
  • 22
  • 33
  • 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? – DA. Apr 16 '14 at 02:03
  • @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. – Idra Apr 16 '14 at 10:50
  • 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. – DA. Apr 16 '14 at 15:02
  • @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. – Idra Apr 16 '14 at 18:35
  • It looks like there are related questions about this: http://stackoverflow.com/questions/5267996/how-to-properly-display-an-iframe-in-mobile-safari 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? – DA. Apr 16 '14 at 19:01
  • @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. – Idra Apr 17 '14 at 02:17
  • 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: http://jsbin.com/hapituto/1 – DA. Apr 17 '14 at 02:46
  • Does this answer your question? [Making an iframe responsive](https://stackoverflow.com/questions/17838607/making-an-iframe-responsive) – Michael Freidgeim Jul 16 '20 at 00:15

10 Answers10

296

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

SuperStormer
  • 4,997
  • 5
  • 25
  • 35
Idra
  • 5,777
  • 4
  • 22
  • 33
  • 1
    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 7 – malisokan Jan 08 '15 at 16:05
  • @ЮнгвиртТони 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. – Idra Jan 08 '15 at 16:21
  • I didn't need !important either. Works great on iOS 8 too. Cheers – Sam Potts Mar 12 '15 at 06:00
  • 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...? – gerbz Apr 28 '15 at 04:37
  • @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 IFRAME – Idra Apr 28 '15 at 11:30
  • Can you help me how can I use iFrame Youtube embeding, here's an iFrame for example: , 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? Thanks – Ennabah Jun 10 '17 at 06:18
  • This is the solution that wound up working for me, circa April 2018: https://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. – handwovensole Apr 17 '18 at 06:57
  • 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. – alexr89 Feb 11 '21 at 12:12
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.

DA.
  • 39,848
  • 49
  • 150
  • 213
  • 1
    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. – Idra Apr 17 '14 at 12:41
  • 1
    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? – DA. Apr 17 '14 at 13:49
  • 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. – Idra Apr 17 '14 at 14:00
  • 1
    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%;` – Idra Apr 17 '14 at 17:18
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);

}
Nicholas Tsaoucis
  • 1,381
  • 2
  • 17
  • 39
gerbz
  • 1,000
  • 1
  • 11
  • 27
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.

Pier
  • 10,298
  • 17
  • 67
  • 113
  • 1
    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! – Vince Aug 24 '16 at 19:18
  • Hmm. Your example doesn't seem to be responsive on iOS? – BrandonReid May 07 '18 at 15:51
  • It was 2 years ago when I wrote this. Can you file an issue in the repo? – Pier May 07 '18 at 17:56
  • after wasting hours and hours on this issue with Ionic/Cordova on iOS, this is the only thing that worked. thanks! – Andrew Aug 21 '18 at 01:50
  • 1
    This is awesome, the only that worked, I've spent 1 day searching for a solution like this @Pier 100pts to you – CREM Jun 17 '19 at 19:42
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

  • 1
    Chrome for iOS is just Safari underneath. It uses WKWebView. No other web rendering engine is allowed in iOS. – Pier Jun 18 '19 at 20:06
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!!!

S.Yadav
  • 4,273
  • 3
  • 37
  • 44
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;
    }
Dr. Aaron Dishno
  • 1,859
  • 1
  • 29
  • 24
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

4dgaurav
  • 11,360
  • 4
  • 32
  • 59
  • 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? – Idra Apr 15 '14 at 12:43
  • OK it seams like you misunderstood the issue, [check this link out](http://www.idra.pri.ee/sample/t1.html) 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. – Idra Apr 16 '14 at 12:03
  • so what exactly you want it to behave, give example for your given link? – 4dgaurav Apr 16 '14 at 12:08
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.

Luiz Rossi
  • 772
  • 5
  • 19
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%');
Umer Qureshi
  • 1,736
  • 2
  • 20
  • 22