如何使iOS Safari中的IFrame具有响应式?

143

问题在于,当您需要使用IFrames将内容插入网站时,在现代网络世界中,IFrame也被期望是响应式的。理论上很简单,只需使用<iframe width="100%"></iframe>或将CSS宽度设置为iframe { width: 100%; },然而在实践中并不是那么简单,但它是可以实现的。

如果iframe内容是完全响应式的,并且可以调整大小而不需要内部滚动条,那么iOS Safari将重新调整iframe而没有任何真正的问题。

如果您考虑以下代码:

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

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

在iOS 7.1 Safari中,这个功能可以正常工作。您可以在横屏和竖屏之间自由切换而不会出现任何问题。

输入图像描述 输入图像描述

然而,通过简单地更改Content.html的CSS,添加以下内容:

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

您会看到以下内容:

enter image description here enter image description here

正如您所看到的,即使 Content.html 的内容完全响应(div#ScrolledArea设置了overflow: scroll) 并且 iframe 宽度为100%,iframe 仍然占据整个 div#ScrolledArea 的宽度,就好像溢出根本不存在一样。Demo

在这种情况下,当 iframe 内容具有水平滚动区域时,问题就变成如何使 iframe 响应式。这里的问题不在于 Content.html 不响应式,而是在于 iOS Safari 简单地调整 iframe 的大小,以便完全显示 div#ScrolledArea


@DA 我已经为问题和解决方案都添加了演示。而且,white-space: nowrap 本身并不是问题所在。我只是用它来获得 div#ScrolledArea 的极端宽度。当 IFrame 内容中存在可水平滚动的区域时,问题就出现了。如果是这种情况,iOS Safari 就会忽略您的宽度设置,并显示整个内容,破坏站点的响应性。 - Idra
当然,这只是一个特例,你所说的可能是正确的(取决于实现方式,对我们有效),大多数网站没有水平滚动区域,但是当你需要时……你甚至无法想象我花了多少时间来解决这个问题。但是即使你有隐藏并通过按钮或类似方式滚动的图像,这也可能是一个问题。 - Idra
看起来有关于这个问题的相关问题:https://dev59.com/i2435IYBdhLWcg3wtCSQ。似乎这是移动Safari的一个“特性”...它试图确保内容以一种用户仍然可以与之交互的方式进行大小调整。如果您在滚动的iframe中有滚动内容,我不确定会发生什么... Safari如何解释嵌套滚动元素内的滑动? - DA.
@DA 是的,我知道这一点,但那是另一种情况。我本来也可以涉及到那个问题,但是...太长了,超出了这个问题的范围。 - Idra
我认为这与此有关。实际上,我认为问题很简单,即移动Safari将强制iFrame始终与其中的内容一样宽。示例:http://jsbin.com/hapituto/1 - DA.
显示剩余3条评论
10个回答

296
这个问题的解决方案其实相当简单,有两种方法可以处理。如果您控制着Content.html,那么只需将div#ScrolledArea的宽度CSS更改为:
width: 1px;
min-width: 100%;
*width: 100%;
    

这里的思路很简单,将width设置为小于viewport(在这种情况下是iframe宽度),然后用min-width: 100%覆盖它,以允许实际width: 100%,因为iOS Safari默认会覆盖它。 *width: 100%; 是为了使代码保持IE6兼容性,但如果您不关心IE6,则可以省略它。 演示

enter image description here enter image description here

现在可以看到,div#ScrolledArea的宽度实际上是100%,并且overflow: scroll;可以进行滚动隐藏溢出的内容。如果您可以访问iframe内容,则最好使用此方法。

但是,如果您无法访问iframe内容(由于某种原因),则实际上可以在iframe本身上使用相同的技术。只需在iframe上使用相同的CSS:

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

然而,这种方法有一个限制,你需要在iframe中加入scrolling="no"来关闭滚动条才能使它生效:
<iframe height="950" width="100%" scrolling="no" src="Content.html"></iframe>

如果允许滚动条,则此方法将不再在 iframe 上起作用。尽管如此,如果您改变 Content.html ,则可以保留 iframe 中的滚动条。 演示

1
就像@NickGottlieb提到的那样,我不得不在width属性中添加!important,以便在iOS 7上的iPhone 4上使iframe具有响应式网页设计。 - malisokan
我只需要在必要时设置scrolling=no,否则设置scrolling=yes。那么我应该检测什么?这是iOS问题吗?还是Webkit问题?或者...? - gerbz
@ggwarpig 这是一个iOS问题,其中iOS Safari会自动打开seamless属性,您无法覆盖它。如果您可以控制内容,则需要修改内容以便具有“scrolling =”yes“”,否则没有办法纠正此问题。要仅在IFRAME上修复,请在IFRAME上使用“scrolling =”no“”。 - Idra
你能帮助我如何使用 iFrame 嵌入Youtube视频吗?这是一个例子:<iframe width=" \(view.frame.height)" height="\(view.frame.width)" src="https://www.youtube-nocookie.com/embed/QAwL0O5nXe0?rel=0&controls=0&showinfo=0" frameborder="0" allowfullscreen></iframe>,我正在交换高度和宽度,因为我处于横向模式,但是这并没有得到真实的值,我应该添加什么来修复它?谢谢。 - Ennabah
如果您在iframe上设置了scrolling="no",但内容需要滚动(例如,如果内容大于容器),则此解决方案将无法正常工作。本质上,此解决方案仅适用于iframe的内容恰好适合容器或小于容器的情况。 - alexr89
显示剩余3条评论

24

问题似乎在于移动版Safari,如果iFrame中包含的文档宽度超过了您指定的宽度,则会拒绝遵守iFrame的宽度。例如:

http://jsbin.com/hapituto/1

在桌面浏览器上,您将看到一个iFrame和一个Div,两者都设置为300px。内容更宽,因此可以滚动iFrame。

然而,在移动版Safari上,您会注意到iFrame被自动扩展到内容的宽度。

我猜这是解决长期存在的页面内滚动内容问题的一种解决方法。过去,在触摸设备上有一个大的滚动iFrame时,您会“卡住”在iFrame中,因为它会滚动而不是页面本身。苹果似乎已经决定iFrame的默认行为是“不滚动”,并扩展以防止滚动。

其中一种解决方法可能是这个变通方法。不要假设iFrame会滚动,而是将iFrame放置在您可以控制其滚动的DIV中。

示例:http://jsbin.com/zakedaja/1

示例标记:

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

在移动版的safari浏览器中,现在可以通过包含它的div来滚动完全展开的iFrame内容。

但是需要注意的是,在桌面浏览器上看起来非常丑陋,因为现在你有了双重滚动条。因此,你可能需要使用JS进行一些浏览器检测以解决这个问题。


1
我仍然认为这不是问题的范围,因为你在这里展示的解决方案是模拟iOS Safari中iframe滚动的标准方式,但考虑到这个iOS问题涉及IFrame滚动(内容或其他),所以把它放在这里还是很好的。 - Idra
1
我想我没有完全理解你的问题。据我所知,你遇到的问题是在iOS中,移动Safari首先尝试防止iFrame滚动,并强制给它一个宽度。我是否误解了你的问题? - DA.
本质上这就是问题所在,只是需要的解决方案不同。在最初的问题中,IFrame内容是响应式的,同时具有水平滚动内容,因此问题不在于如何模拟iframe滚动,而在于如何使iframe宽度为100%,即响应式,同时在该iframe中具有水平滚动内容。这就是为什么上述方法在这种情况下不起作用,因为设计的响应性已被破坏,您需要滚动才能查看完整的内容,即使在通常不需要的地方也是如此。 - Idra
1
非常抱歉,我意识到我在其中一条评论中误导了您。iframe 不会滚动。这就是重点,iframe 不应该滚动,只有它的部分内容,即我的示例中的 div#ScrolledArea(绿色)应该滚动。我之前看错了。但是 iframe 不应该滚动,只应根据容器元素调整大小,即具有 width: 100%; - Idra

18

我需要一个跨浏览器的解决方案。要求如下:

  • 需要在iOS和其他地方都能正常工作
  • 无法访问iFrame中的内容
  • 需要可以滚动!

在借鉴了关于iOS上scrolling="no"的@Idra的经验和这篇文章中有关在iOS中适配iFrame内容到屏幕大小的方法后,我最终得到了以下解决方案。希望对大家有所帮助 =)

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

翻译为:

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

}

1
点赞了,但是……为什么在“ios”类中有IE6规则呢? :-) - J. Bruni

12
所有这些解决方案的问题在于iframe的高度从未真正改变。
这意味着您将无法使用JavaScript、position:fixed;position:absolute;来居中iframe内的元素,因为iframe本身从不滚动。
我的解决方案在此处详细说明是将div包装在iframe的所有内容中,使用以下CSS:
#wrap {
    position: fixed;
    top: 0;
    right:0;
    bottom:0;
    left: 0;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
}

这样,Safari会认为内容没有高度,使你能够正确地分配iframe的高度。这也允许你以任何希望的方式定位元素。

你可以在这里看到一个快速而简单的演示。


1
这是唯一适用于我的解决方案。当然,它只能在您控制“iframe”的内容时使用,但在我的情况下,我可以。 干杯! - Vince
嗯,你的示例在iOS上似乎没有响应? - BrandonReid
这是我两年前写的。你能在仓库中提交一个问题吗? - Pier
在iOS上,花了几个小时甚至更长时间来解决Ionic/Cordova的问题,最终只有这个方法起作用。谢谢! - Andrew
1
这太棒了,这是唯一有效的方法,我花了一天时间寻找像这样的解决方案。@Pier 给你100分。 - CREM

5

这个问题也存在于iOS Chrome浏览器中。

我浏览了上面提供的所有解决方案,大多数都非常不规范。

如果您不需要支持旧版浏览器,请将iframe宽度设置为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 */
}

注意:检查对视口单位的支持。 https://caniuse.com/#feat=viewport-units

1
Chrome for iOS只是在Safari的基础上构建的,它使用WKWebView。在iOS中不允许使用其他的Web渲染引擎。 - Pier

3
我正在使用ionic2,并且系统配置如下 -
******************************************************

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



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

对于我来说,这个问题通过以下代码得到了解决 -
对于HTML的iframe标签 -
<div class="iframe_container">
      <iframe class= "animated fadeInUp" id="iframe1" [src]='page' frameborder="0" >
        <!--  <img src="img/video-icon.png"> -->
      </iframe><br>
   </div>

查看相同的CSS-


.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属性起着至关重要的作用。
position:relative;

这也可能对你有所帮助!!!


1

我在内容窗格上遇到了宽度问题,导致iframe出现了水平滚动条。后来发现一个图像的宽度比预期的要大。我通过将所有图像的CSS最大宽度设置为百分比来解决了这个问题。

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

img {
        max-width: 100%;
        height:auto;
    }

这实际上为我完成了工作,无需使用CSS。 - MSaudi

0

对我来说,CSS 解决方案不起作用。但是通过编程设置宽度可以解决问题。 在 iframe 加载时通过编程设置宽度:

 $('iframe').width('100%');

0

CSS的唯一解决方案

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

演示

在 iframe 中的另一个 演示页面


也许我没有正确地实现您的解决方案,但当我尝试在我的隔离测试用例中使用它时,在iOS Safari 7.1 iPhone 4上根本不起作用。您能详细说明一下应该如何工作吗? - Idra
好的,看起来你误解了问题,请查看此链接,这是你的新演示iframe内容,没有应用任何额外的CSS到iframe上。如果你在iOS Safari中查看它,那么它仍然是响应式的,这是因为这个页面没有任何水平滚动,会强制iframe宽度比视口更宽。如问题所述,在这样的网站上,你不需要做任何事情来使iframe响应式。 - Idra
那么你想让它如何表现,可以给出你提供的链接的例子吗? - 4dgaurav

0

实际上,对我来说只需要在iOS中禁用滚动即可。

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

并通过脚本处理操作系统。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接