IFRAME 和 iPad 上的 Safari 浏览器,用户如何滚动内容?

根据苹果 iOS 的咒语,用两个手指拖动 IFRAME 应该可以滚动它的内容。不幸的是,在 iPad 上运行最新版本的 iOS 时,我还没有找到一个使用这种方法滚动的 IFRAME 网站,也没有出现滚动条。

有人知道用户应该如何用移动 Safari 滚动 IFRAME 的内容吗?

159049 次浏览

似乎 iframe 没有正确显示和滚动。您可以使用一个对象标记来替换一个 iframe,内容将可以用两个手指滚动。这里有一个简单的例子:

<html>
<head>
<meta name="viewport" content="minimum-scale=1.0; maximum-scale=1.0; user-scalable=false; initial-scale=1.0;"/>
</head>
<body>
<div>HEADER - use 2 fingers to scroll contents:</div>
<div id="scrollee" style="height:75%;" >
<object id="object" height="90%" width="100%" type="text/html" data="http://en.wikipedia.org/"></object>
</div>
<div>FOOTER</div>
</body>
</html>

经过一番努力,我发现了如何在我的 ipad 上滚动 iframe。秘诀是在 iframe 区域的左侧(也许稍微在边界之外)做一个垂直的手指滑动(单指就可以了)。在笔记本电脑或个人电脑上,滚动条在右边,所以很自然地,我花了很多时间在我的 iPad 上试验右边的手指动作。只有当我尝试左侧 iframe 卷轴。

IOS5添加了以下样式,这些样式可以添加到父 div 中,以便滚动工作。

-webkit-overflow-scrolling:touch

overflow: auto;添加到样式和两个手指滚动应工作。

这就是我为了让 iframe 在 iPad 上滚动而做的事情。请注意,这个解决方案只有在您控制显示在 iframe 内部的 html 时才有效。

它实际上关闭了默认的 iframe 滚动,而是导致 iframe 内部的 body 标记滚动。

.html 主要内容 :

<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#container {
position: absolute;
top: 50px;
left: 50px;
width: 400px;
height: 300px;
overflow: hidden;
}
#iframe {
width: 400px;
height: 300px;
}
</style>
</head>
<body>


<div id="container">
<iframe src="test.html" id="iframe" scrolling="no"></iframe>
</div>


</body>
</html>

.html :

<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
body {
height: 100%;
overflow: auto;
-webkit-overflow-scrolling: touch;
margin: 0;
padding: 8px;
}
</style>
</head>
<body>
…
</body>
</html>

如果您愿意,也可以使用 jQuery 完成同样的任务:

$("#iframe").contents().find("body").css({
"height": "100%",
"overflow": "auto",
"-webkit-overflow-scrolling": "touch"
});

我使用这个解决方案让 TinyMCE (wordpress 编辑器)在 iPad 上正确滚动。

下面的代码对我很有用(感谢 Christopher Zimmermann 的博客文章 http://dev.magnolia-cms.com/blog/2012/05/strategies-for-the-iframe-on-the-ipad-problem/):

  1. 没有滚动条让用户知道他们可以滚动
  2. 用户必须使用两指滚动
  3. PDF 文件没有居中(仍在处理中)

    <!DOCTYPE HTML>
    <html>
    <head>
    <title>Testing iFrames on iPad</title>
    <style>
    div {
    border: solid 1px green;
    height:100px;
    }
    
    
    .scroller{
    border:solid 1px #66AA66;
    height: 400px;
    width: 400px;
    overflow: auto;
    text-align:center;
    
    
    }
    </style>
    

    <table>
    <tr>
    <td><div class="scroller">
    <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
    </td>
    <td><div class="scroller">
    <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
    </td>
    </tr>
    <tr>
    <td><div class="scroller">
    <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
    </td>
    <td><div class="scroller">
    <iframe width="400" height="400" src="http://www.supremecourt.gov/opinions/11pdf/11-393c3a2.pdf" ></iframe>
    </div>
    </td>
    </tr>
    </table>
    <div> Here are some additional contents.</div>
    

正如在其他文章中提到的,组合的 css 溢出值: 自动; & - webkit-溢出-滚动: 触摸;

当应用于有问题的 iframe 和它的父 div 时,可以正常工作

非触摸浏览器上双滚动条的不幸副作用。

我使用的解决方案是通过 javascript/jquery 添加这些 css 值。它允许我对所有浏览器使用基本的 css

if (isSafariBrowser()){
$('#parentDivID').css('overflow', 'auto');
$('#parentDivID').css('-webkit-overflow-scrolling', 'touch');
$('#iframeID').css('overflow', 'auto');
$('#iframeID').css('-webkit-overflow-scrolling', 'touch');
}

其中 isSafariBrowser ()的定义如下..。

var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
var is_safari = navigator.userAgent.indexOf("Safari") > -1;


function isSafariBrowser(){
if (is_safari){
if (is_chrome)  // Chrome seems to have both Chrome and Safari userAgents
return false;
else
return true;
}
return false;
}

这使得我的应用程序可以在 iPad 上运行 注意 1)未在其他 ios 系统上测试 2)没有在平板电脑上的 Android 浏览器上测试,可能需要进一步的修改

(因此这个解决方案可能不完整)

答案中提到的 -webkit-overflow-scrolling:touch实际上是可能的解决方案。

<div style="overflow:scroll !important; -webkit-overflow-scrolling:touch !important;">
<iframe src="YOUR_PAGE_URL" width="600" height="400"></iframe>
</div>

但是如果您无法在 iframe 中上下滚动,如下图所示, enter image description here

你可以试试用两个手指斜着滚动像这样,

enter image description here

这在我的案例中确实起作用了,所以如果你还没有找到解决方案的话,就分享一下吧。

基于 这篇文章,我整合了以下代码片段,它提供了一些非常基本的功能:

<div id = "container"></div>
<script>
function setPDFHeight(){
$("#pdfObject")[0].height = $("#pdfObject")[0].offsetHeight;
}
$('#container').append('<div align="center" style="width: 100%; height:100%; overflow: auto !important; -webkit-overflow-scrolling: touch !important;">\
<object id="pdfObject" width="100%" height="1000000000000" align="center" data="content/lessons/12/t.pdf" type="application/pdf" onload="setPDFHeight()">You have no plugin installed</object></div>');
</script>

显然它远非完美(因为它实际上将页面高度扩展到了无穷大) ,但它是我迄今为止发现的唯一可行的解决方案。

到目前为止,没有一个解决方案在我尝试的时候完全奏效(有时候,只是在二次加载时出现 bug) ,但是作为一个解决方案,使用这里描述的 object 元素,然后包装成一个可滚动的 div,然后将对象设置到一个非常高的高度(5000px) ,这样的工作就完成了。这是一个很大的变通方法,并且不能很好地工作(对于初学者来说,超过5000px 的页面会导致问题——尽管10000px 对我来说完全破坏了它) ,但是在我的一些测试用例中它似乎可以完成工作:

var style = 'left: ...px; top: ...px; ' +
'width: ...px; height: ...px; border: ...';


if (isIOs) {
style += '; overflow: scroll !important; -webkit-overflow-scrolling: touch !important;';
html = '<div style="' + style + '">' +
'<object type="text/html" data="http://example.com" ' +
'style="width: 100%; height: 5000px;"></object>' +
'</div>';
}
else {
style += '; overflow: auto;';
html = '<iframe src="http://example.com" ' +
'style="' + style + '"></iframe>';
}

希望苹果能够解决 Safari iFrame 的问题。

这不是我的答案,但我只是从 https://gist.github.com/anonymous/2388015复制它只是因为答案是令人敬畏的,并完全修复了问题。这完全归功于匿名作者。

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
if (/iPhone|iPod|iPad/.test(navigator.userAgent))
$('iframe').wrap(function(){
var $this = $(this);
return $('<div />').css({
width: $this.attr('width'),
height: $this.attr('height'),
overflow: 'auto',
'-webkit-overflow-scrolling': 'touch'
});
});
})
</script>

问题

我帮助维护一个庞大、复杂、凌乱的旧站点,其中 一切(字面意思)嵌套在多个 iframe 级别中——其中许多都是动态创建的,并且/或者有一个动态 src。这就产生了以下挑战:

  1. 对 HTML 结构的任何更改都有可能破坏多年未动过的脚本和样式表。
  2. 手动查找和修复所有 iframe 和 src 文档将花费太多的时间和精力。

到目前为止发布的解决方案中,这个是我见过的唯一一个能够克服挑战1的。不幸的是,它似乎不能在一些 iframe 上工作,当它工作时,滚动是非常小故障(这似乎导致页面上的其他错误,如无响应链接和表单控件)。

解决方案

如果上述情况与您的情况相似,您可以尝试使用下面的脚本。它放弃了本地滚动,而是使所有的 iframe 在其 viewport 的边界内可拖动。您只需要将它添加到包含顶级 iframe 的文档中; 它将根据需要对它们及其后代应用补丁。

这是一个工作 小提琴 * ,这是代码:

(function() {
var mouse = false //Set mouse=true to enable mouse support
, iOS = /iPad|iPhone|iPod/.test(navigator.platform);
if(mouse || iOS) {
(function() {
var currentFrame
, startEvent, moveEvent, endEvent
, screenY, translateY, minY, maxY
, matrixPrefix, matrixSuffix
, matrixRegex = /(.*([\.\d-]+, ?){5,13})([\.\d-]+)(.*)/
, min = Math.min, max = Math.max
, topWin = window;
if(!iOS) {
startEvent = 'mousedown';
moveEvent = 'mousemove';
endEvent = 'mouseup';
}
else {
startEvent = 'touchstart';
moveEvent = 'touchmove';
endEvent = 'touchend';
}
setInterval(scrollFix, 500);
function scrollFix() {fixSubframes(topWin.frames);}
function fixSubframes(wins) {for(var i = wins.length; i; addListeners(wins[--i]));}
function addListeners(win) {
try {
var doc = win.document;
if(!doc.draggableframe) {
win.addEventListener('unload', resetFrame);
doc.draggableframe = true;
doc.addEventListener(startEvent, touchStart);
doc.addEventListener(moveEvent, touchMove);
doc.addEventListener(endEvent, touchEnd);
}
fixSubframes(win.frames);
}
catch(e) {}
}
function resetFrame(e) {
var doc = e.target
, win = doc.defaultView
, iframe = win.frameElement
, style = getComputedStyle(iframe).transform;
if(iframe===currentFrame) currentFrame = null;
win.removeEventListener('unload', resetFrame);
doc.removeEventListener(startEvent, touchStart);
doc.removeEventListener(moveEvent, touchMove);
doc.removeEventListener(endEvent, touchEnd);
if(style !== 'none') {
style = style.replace(matrixRegex, '$1|$3|$4').split('|');
iframe.style.transform = style[0] + 0 + style[2];
}
else iframe.style.transform = null;
iframe.style.WebkitClipPath = null;
iframe.style.clipPath = null;
delete doc.draggableiframe;
}
function touchStart(e) {
var iframe, style, offset, coords
, touch = e.touches ? e.touches[0] : e
, elem = touch.target
, tag = elem.tagName;
currentFrame = null;
if(tag==='TEXTAREA' || tag==='SELECT' || tag==='HTML') return;
for(;elem.parentElement; elem = elem.parentElement) {
if(elem.scrollHeight > elem.clientHeight) {
style = getComputedStyle(elem).overflowY;
if(style==='auto' || style==='scroll') return;
}
}
elem = elem.ownerDocument.body;
iframe = elem.ownerDocument.defaultView.frameElement;
coords = getComputedViewportY(elem.clientHeight < iframe.clientHeight ? elem : iframe);
if(coords.elemTop >= coords.top && coords.elemBottom <= coords.bottom) return;
style = getComputedStyle(iframe).transform;
if(style !== 'none') {
style = style.replace(matrixRegex, '$1|$3|$4').split('|');
matrixPrefix = style[0];
matrixSuffix = style[2];
offset = parseFloat(style[1]);
}
else {
matrixPrefix = 'matrix(1, 0, 0, 1, 0, ';
matrixSuffix = ')';
offset = 0;
}
translateY = offset;
minY = min(0, offset - (coords.elemBottom - coords.bottom));
maxY = max(0, offset + (coords.top - coords.elemTop));
screenY = touch.screenY;
currentFrame = iframe;
}
function touchMove(e) {
var touch, style;
if(currentFrame) {
touch = e.touches ? e.touches[0] : e;
style = min(maxY, max(minY, translateY + (touch.screenY - screenY)));
if(style===translateY) return;
e.preventDefault();
currentFrame.contentWindow.getSelection().removeAllRanges();
translateY = style;
currentFrame.style.transform = matrixPrefix + style + matrixSuffix;
style = 'inset(' + (-style) + 'px 0px ' + style + 'px 0px)';
currentFrame.style.WebkitClipPath = style;
currentFrame.style.clipPath = style;
screenY = touch.screenY;
}
}
function touchEnd() {currentFrame = null;}
function getComputedViewportY(elem) {
var style, offset
, doc = elem.ownerDocument
, bod = doc.body
, elemTop = elem.getBoundingClientRect().top + elem.clientTop
, elemBottom = elem.clientHeight
, viewportTop = elemTop
, viewportBottom = elemBottom + elemTop
, position = getComputedStyle(elem).position;
try {
while(true) {
if(elem === bod || position === 'fixed') {
if(doc.defaultView.frameElement) {
elem = doc.defaultView.frameElement;
position = getComputedStyle(elem).position;
offset = elem.getBoundingClientRect().top + elem.clientTop;
viewportTop += offset;
viewportBottom = min(viewportBottom + offset, elem.clientHeight + offset);
elemTop += offset;
doc = elem.ownerDocument;
bod = doc.body;
continue;
}
else break;
}
else {
if(position === 'absolute') {
elem = elem.offsetParent;
style = getComputedStyle(elem);
position = style.position;
if(position === 'static') continue;
}
else {
elem = elem.parentElement;
style = getComputedStyle(elem);
position = style.position;
}
if(style.overflowY !== 'visible') {
offset = elem.getBoundingClientRect().top + elem.clientTop;
viewportTop = max(viewportTop, offset);
viewportBottom = min(viewportBottom, elem.clientHeight + offset);
}
}
}
}
catch(e) {}
return {
top: max(viewportTop, 0)
,bottom: min(viewportBottom, doc.defaultView.innerHeight)
,elemTop: elemTop
,elemBottom: elemBottom + elemTop
};
}
})();
}
})();

* jsfiddle 为测试目的启用了鼠标支持。