如何在移动版Safari中正确显示iFrame

55
我正在尝试在我的移动web应用程序中显示一个iframe,但我无法限制iframe的大小为iPhone屏幕的尺寸。奇怪的是,iframe元素上的高度和宽度属性似乎没有效果。将其包围在div中可以限制它,但是那样我就无法在iframe内滚动。
有人在移动safari中处理过iframes吗?有什么想法可以开始吗?

1
不知道他在做什么,开始争论是否是正确的事情有点毫无意义。有时候需要使用iframe。 - crappish
如果您可以访问嵌入的页面,则可以执行以下操作:https://dev59.com/NHjZa4cB1Zd3GeqPfIrV - user1470118
这是Chris Coyier最近发表的一篇文章,我觉得很有趣:blog.codepen.io/2017/12/01/stupid-iframes-stupid-ios - Ryan
请看这里:https://dev59.com/lF8e5IYBdhLWcg3wJXrm#32993873 这个解决方案对我很有用。 - Peter T.
10个回答

20

没错,你无法通过设置iframe的高度和宽度来限制其大小。你需要将其放入一个div中。如果你控制iframe中的内容,可以在其中加入一些JS代码,以便在收到触摸事件时通知父级滚动div。

就像这样:

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

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>

如果您无法控制iframe内容,您可以以类似的方式在iframe上使用遮罩层,但是除了滚动它之外,您不能与iframe内容进行交互 - 因此,例如,您不能单击iframe中的链接。

以前您可以使用两个手指在iframe中滚动,但现在不再适用。

更新:iOS 6破坏了我们的解决方案。我一直在尝试找到一个新的解决方法,但还没有成功。另外,由于引入了Remote Web Inspector,需要Mac才能使用,因此不再可能在设备上调试javascript。


好的,我在主页面上有一个子iframe..这个子iframe在主页面内无法滚动..你可以查看http://ipad.atwebpages.com/table/try2.html - copenndthagen
不确定为什么链接对您来说无法工作。但是,是的,在主页面中,我有包含iframe元素的滚动条div并将JS代码放在iframe页面内...但iframe仍然无法滚动...您是否有在线工作示例,以便我可以用作参考...再次感谢您对此的帮助.. - copenndthagen
4
你上面的示例对我有效,但是滚动会非常抖动,因为你使用了 event.pageX 和 pageY,它们包含滚动信息(然后你又改变了它们,导致抖动)。改用 event.screenX 和 screenY 对我来说可以实现平滑滚动。 - Martamius
如果您可以访问嵌入页面:https://dev59.com/NHjZa4cB1Zd3GeqPfIrV,我有一个解决方案。 - user1470118
@Martamius 的滞后是由于 overflow: auto 引起的,请在这里查看 https://dev59.com/TWkw5IYBdhLWcg3w4eiS#9585204 - TecHunter
显示剩余7条评论

12

仅当您控制外部页面和 iframe 页面时才能使用此方法。

在外部页面上,使 iframe 不可滚动。

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

在 iframe 页面中,添加此内容。

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

这能够起作用是因为现代浏览器使用 html 确定高度,所以我们只需给其固定高度并使 body 成为可滚动节点即可。


3
我爱你,你愿意嫁给我吗? - sebas sierra

11

如果 iFrame 的内容不是你自己的,则下面的解决方案将不起作用。

对于 Android,你只需要将 iFrame 包裹在一个 DIV 中,并将该 DIV 的高度设置为 document.documentElement.clientHeight。然而,iOS 则是另外一回事。虽然我还没有尝试 Sharon 的解决方案,但它似乎是一个好的解决方案。我找到了一个更简单的解决方案,但它仅适用于 iOS 5.+。

将 iframe 元素包裹在一个 DIV 中(假设我们称其为 scroller),设置 DIV 的高度,并确保新 DIV 具有以下样式:

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

这个方法可以生效,但你会发现在大多数实现中,当滚动时iframe中的内容会变空,基本上就无法使用了。据我了解,这个问题早在iOS 5.0时就被报告给Apple作为一个bug。为了绕过这个问题,在iframe中找到body元素并添加-webkit-transform','translate3d(0, 0, 0)即可:

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

如果你的应用程序或iframe占用了大量内存,可能会出现卡顿的滚动条,这时你可能需要使用Sharon的解决方案。


4

我将@Sharon的代码整合到了下面的代码中,在iPad上进行双指滚动时可以正常工作。唯一需要更改的是iframe标签中的src属性(我使用了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>

你好,我在某个地方读到说几次更新之前移除了双指滚动,这个解决方案对你仍然有效吗? - somdow
是的,我可以确认它有效,我正在使用它与jQuery colorbox插件。它支持单指滚动,尽管没有滚动条。 - Ian Stanway

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

我正在构建我的第一个网站,这篇文章帮助我使所有使用 iframe 嵌入的网站正常工作。
感谢您!

1

Sharon的方法对我很有效,但是当在iframe中跟随链接并按下浏览器返回按钮时,会加载页面的缓存版本,而iframe不再可滚动。为了克服这个问题,我使用了一些代码来刷新页面,如下所示:

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

0

我已经实现了以下功能,并且它工作良好。基本上,我根据 iFrame 内容的大小设置了 body 的尺寸。这意味着我们的非 iFrame 菜单可能会滚动到屏幕外,但这可以使我们的网站在 iPad 和 iPhone 上正常工作。"workbox" 是我们 iFrame 的 ID。

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

不要滚动IFrame页面或其内容,而是滚动父页面。如果您控制IFrame内容,则可以使用iframe-resizer库将iframe元素本身转换为适当的块级元素,并具有自然/正确/本地高度。此外,请勿尝试在父页面中定位(固定,绝对)您的iframe,或在模态窗口中呈现iframe,特别是如果它具有表单元素。

我还怀疑iOS Safari具有非标准行为,会将您的iframe高度扩展到其自然高度,就像桌面浏览器将使用iframe-resizer库一样,这些浏览器似乎会将响应式iframe内容呈现为高度0px或150px或其他不实用的默认值。如果需要限制宽度,请在iframe内部尝试max-width样式。


0

纯粹使用 MSchimpf 和 Ahmad 的代码,我进行了调整,以便将 iframe 放在 div 内部,从而在页面上保留头部和尾部用于返回按钮和品牌推广。更新的代码:

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

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

-2

解决方案是在iframe上使用Scrolling =“no”

就是这样。


2
我不知道最新的iOS版本是否存在此问题,但是我无论如何都无法让动态创建的iframe正常工作。 - crappish
3
更准确地说,使用 scrolling="no" 和 width:100% 时,iframe 仍然会自动调整大小。只有当我将宽度设置为 inherit 或特定像素值时,它才停止调整大小。 - crappish
这对我没有任何影响。 - elsurudo

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