当URL包含片段时,iframe会导致父元素在Google Chrome上向上滚动

时间:2014-09-24 13:18:06

标签: html google-chrome iframe jsfiddle

在谷歌浏览器(37.0.2062.122,OSX / Windows)上,带有包含片段的URL的iframe会导致父元素向上滚动。

这只发生在Chrome中(在Safari和Firefox中测试过)。

这是一个显示问题的小提琴:http://jsfiddle.net/wmz5cu1y/1/(您必须点击Run 两次。)

如您所见,包含iframe的整个<body>已向上滚动。标题是隐藏的,因为它现在位于窗口上方,并且页面底部有一个意外的空白区域。

如何避免这种情况?

Bounty提供了非js变通方法​​或更简单的html文档来重现这个问题。

iframe overflows body

5 个答案:

答案 0 :(得分:16)

正如其他答案已经提到的,这里的问题是JSFiddle特有的。我可以通过在此问题的StackOverflow片段中简单地包含相同的代码来轻松地向您展示:

&#13;
&#13;
iframe {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
&#13;
<iframe src="https://news02ycombinator02com2.mentionusercontent.net/item?id=8357207#up_8360397" width="100%" height="100%"></iframe>
&#13;
&#13;
&#13;


更简单的HTML文档

在JSFiddle上传递给iframe的每个片段URL都会出现此问题。因此,我们可以复制此问题,只需创建一个单独的JSFiddle演示并链接到我们iframe中的演示。

我在这里创建了这个新的JSFiddle演示:http://fiddle.jshell.net/JamesD/k5vk2u9h/1/show/light/#test

如您所见,此处的片段为#test。现在可以使用以下标记在新的JSFiddle演示中复制此问题:

<iframe src="http://fiddle.jshell.net/JamesD/k5vk2u9h/1/show/light/#test"></iframe>

heightwidth属性无关紧要,因为如果没有它们,问题仍会出现。

JSFiddle demo


解决方法

这里的另一个答案表明修复是修改JSFiddle自己的HTML,以便正确地重新呈现页面。这不是一个很好的解决方案,因为在现实世界的情况下(即将某人链接到JSFiddle演示时),他们可能没有专业知识来实现​​这一点。

我们可以使用JavaScript解决这个问题。由于我创建的新HTML文档位于同一个域(http://jshell.net),因此我们可以在iframe内执行JavaScript。手动设置location.hash属性也会触发此问题,因此我们可以做的是将iframe直接滚动到我们希望关注的元素。

首先,从src的{​​{1}}属性中删除网址中的片段:

iframe

如上所述,我使用的片段是<iframe src="http://fiddle.jshell.net/JamesD/k5vk2u9h/1/show/light/"></iframe> 是&#34; test&#34;的元素。这意味着获取元素的最简单方法是通过id属性选择它:

id

此处,var frame = frames[0], elem = frame.document.querySelector('#test'), 是我们自己的文档中对frame的引用,iframe是我们的elem元素。我们可以使用#test

来获取匹配元素的位置
getBoundingClientRect()

这将为我们提供如下的ClientRect对象:

ClientRect

有了这个,我们现在知道我们的 position = elem.getBoundingClientRect(); 元素位于距#test顶部3034px处。使用此功能,我们现在可以使用iframe将页面滚动到此位置(在这种情况下window.scrollTo()的{​​{1}}保存在我们的window变量中):< / p>

iframe

JSFiddle demo

请注意,此解决方案仅在frame指向同一域上托管的网址或在frame.scrollTo(0, position.top); 嵌入的网页上启用了CORS时才有效。


最佳选择

完成所有这些之后,最好的办法是简单地通知JSFiddle的开发人员这是一个错误。我已在此处将其作为GitHub存储库中的问题提出:https://github.com/jsfiddle/jsfiddle-issues/issues/547

答案 1 :(得分:7)

修订答案

此处显示两个错误

  1. 在使用片段加载iFrame时,JSFiddle丢失了部分标题。这在其他答案和我的旧答案&#34;部分。并且已经提出了一个github问题。
  2. Chrome上的iFrame严重处理碎片。它们会导致父级滚动。 (这可能是理想的行为)。
  3. Chrome iFrame问题

    运行此窗口时,窗口将滚动,以便窗口中的片段位于页面顶部:

    &#13;
    &#13;
    <iframe src="https://news02ycombinator02com2.mentionusercontent.net/item?id=8357207#up_8360397" width="100%" height="100%"></iframe>
    &#13;
    &#13;
    &#13;

    您可以想象,这会导致某些固定高度网站(例如jsfiddle)出现问题。它也是Chrome独有的(我只在FF上测试,而不是IE),Firefox没有滚动父窗口。有人讨论它不在FF here

    Chrome iFrame父级滚动修复

    Fiddle

    将onload事件添加到调用以下函数的iframe中。并且不要使用原始片段:

    &#13;
    &#13;
    <script>
        function loadorder() {
        document.getElementById("iframename").src= "https://news02ycombinator02com2.mentionusercontent.net/item?id=8357207#up_8360397";
        window.scrollTo(0,0);
    }
    </script>
    <iframe width="830" src="https://news02ycombinator02com2.mentionusercontent.net/item?id=8357207" height="500" id="iframename"  onLoad="loadorder();"></iframe>
    &#13;
    &#13;
    &#13;

    正如您在小提琴和上面的片段中看到的那样,父窗口不再滚动,现在FF和Chrome的行为相同。

    <强> Source for fix.

    旧答案(jsfiddle的替代修复)

      

    好的,所以我做了一些测试:

         
        
    • 仅在Chrome上发布
    •   
    • 任何片段链接页面都会出现问题:example
    •   
    • 问题特定于jsfiddle。 CodePenjsbin工作正常。
    •   
         

    因此,作为临时解决方法,请使用其中一个或注入此方法   进入jsfiddle&#39; html:

    margin-top: 30px; into the header bar like:
    
    <div id="header" style="margin-top: 30px;">
    
         

    虽然每次加载都需要完成,但有点痛苦   jsfiddle(但不是每次你操作小提琴)。

         

    要解决问题,应该在jsfiddle github上报告   页面:https://github.com/jsfiddle/jsfiddle-issues/issues

         

    修改

         

    这是一种在Chrome上自动化它的方法:下载stylebot   扩展,并将此样式添加到jsfiddle.com(或具体   小提琴):

    #header {
        margin-top: 30px;
    }
    
         

    效果很好。

答案 2 :(得分:3)

问题不是在iframe网址中包含#,如果您尝试使用示例中的下一个网址,则会看到没有滚动: http://www.w3.org/TR/scxml/#scxml

所以,我查看了您正在展示的页面,看看是否有奇怪的东西: https://news02ycombinator02com2.mentionusercontent.net/item?id=8357207#up_8360397

如果你检查JS它有类似下一个:

      var e = window,
    g = document,
    h = "documentElement",
    k = "CriticalImages",
    l = "scrollTop",
    n = "prototype",
    p = "body",
    q = "getAttribute",

有一个名为“scrollTop”的功能,我认为这是一个很好的调查对象。

如果你再检查一下代码,你会发现JS在某些时候获得了offsetTop和offsetParent:

 u = function(a, b) {
        var c = b[q]("pagespeed_lazy_position");
        if (c) return parseInt(c, 0);
        var c = b.offsetTop,
            d = b.offsetParent;
        d && (c += u(a, d));
        c = Math.max(c, 0);
        b.setAttribute("pagespeed_lazy_position", c);
        return c
    },

结论:问题在于您尝试在iframe中显示的页面,而不是网页中的小提琴,Chrome或#。

我希望这有帮助。


修改

在查看wiki示例后,我看到小提琴中有一些js(所以第一个答案是对的)。

要使用js避免这种情况,您只需将其包括在内:

$( window.parent ).scroll(function(event) {
   // debugger;
  console.log('SCROLL',event);
  var scrollTop=$(this).scrollTop();
  if(scrollTop>0){
      console.log('fix scroll');
      $(this).scrollTop(0);
  }

});

例:
http://fiddle.jshell.net/xbnt3Lu6/21/

我会尝试检查哪些j导致问题。

答案 3 :(得分:1)

好吧它不仅是Chrome,所有浏览器都会遇到同样的问题,看起来该网站有大量的js脚本,不知道它如何影响你放置iframe的网站,解决它的最简单方法是删除<强大的>#up_8360397 来自链接。 第二种方法是在iframe中禁用javascript。但是你不能自动将其向下滚动到你想要的帖子,你必须手动设置滚动位置。

答案 4 :(得分:0)

重现脚本

找到了重现错误的最小方法:http://jsfiddle.net/4oytgwon/1/embedded/result/(您可以在点击&#34后看到错误发生;加载iframe&#34;)。

它也发生在jsfiddle之外,使用以下代码:

<!doctype html>
<html>
    <head>
        <style>
            body, html {
                padding: 0;
                border: 0;
                margin: 0;
                height: 100%;
                overflow: hidden;
            }
            #header {
                height: 50px;
                background: blue;
            }
            #content {
                position: absolute;
                top: 50px;
                right: 0;
                bottom: 0;
                left: 0;
            }
            #overflow {
                position: absolute;
                height: 50px;
                bottom: -50px;
            }
        </style>
        <script>
            function loadIframe() {
                var ifr = document.createElement('iframe');
                ifr.src = 'https://en.wikipedia.org/wiki/Stack_overflow#See_also';
                var content = document.getElementById('content');
                while (content.firstChild) {
                    content.removeChild(content.firstChild);
                }
                content.appendChild(ifr);
            }
            window.onload = function () {
                document.getElementById('btn').onclick = loadIframe;
            };
        </script>
    </head>
    <body>
        <div id=header>
            <button id=btn>load iframe</button>
        </div>
        <div id=content>
        </div>
        <div id=overflow>
            overflow
        </div>
    </body>
</html>