可见性更改时,IFrame 滚动条在 chrome 上消失

Posted

技术标签:

【中文标题】可见性更改时,IFrame 滚动条在 chrome 上消失【英文标题】:IFrame scrollbar disappears on chrome when visibility changes 【发布时间】:2016-11-28 05:14:20 【问题描述】:

Windows 上的 Google Chrome 在呈现 iframe 滚动条时是否存在问题?

我写了一个非常简单的代码来显示正在发生的事情(至少我在 chrome 52.0.2743.82 m 上):

  <button>Toggle visibility</button>
  <br />
  <iframe scrolling="yes" seamless src="https://en.wikipedia.org/wiki/Lorem_ipsum" frameborder="0" style="width: 700px; height: 300px"></iframe>

  <script type="text/javascript">
    $("button").on("click", function() 
      $("iframe").toggle();
    );
  </script>

Plunker link to code

当页面加载时,iframe 作为它的滚动条是可见的。

点击按钮隐藏和显示 iframe。滚动条消失。

这个问题显然只发生在 chrome 中。

有人也遇到过这种情况吗?有任何修复/解决方法吗?

【问题讨论】:

Chrome 52.0.2743.82 似乎出现了该错误:googlechromereleases.blogspot.fr/2016/07/… 【参考方案1】:

我将 Dai 的示例改编为我自己的 React IFrame 组件。我在选项卡面板中有一个 iframe,它本身位于可折叠面板中。当其中任何一个被切换时,我会强制 iframe 重新绘制。效果很好。

private iframe: htmlIFrameElement;
private displayObserver: MutationObserver;

componentDidMount() 
    // Detect style attribute changes for the containing collapsible components
    // If the display goes from 'none' to something else, then we need to redraw the iframe
    // so we get the scrollbar back as it should be.
    if (isChrome()) 
        this.displayObserver = new MutationObserver(this.onContentMutated);
        const options =  attributes: true, childList: false, characterData: false, subtree: false, attributeFilter: ['style'] ;

        const tabPanelAncestor = this.findAncestor(this.iframe, '.tab-panel-content');
        if (tabPanelAncestor) 
            this.displayObserver.observe(tabPanelAncestor, options);
        
        const collapsibleAncestor = this.findAncestor(this.iframe, '.collapsible');
        if (collapsibleAncestor) 
            this.displayObserver.observe(collapsibleAncestor, options);
        
    


private readonly onContentMutated = (mutations: Array<MutationRecord>) => 

    R.forEach( (mutation) => 
        const targetElement = mutation.target as Element;
        const style = targetElement.getAttribute('style');
        if (style && !style.match(/display: none/)) 
            this.iframe.contentWindow.location.reload(true);
        
    , mutations);


private readonly findAncestor = (element: HTMLElement, sel: string): Node | null => 
    if (typeof element.closest === 'function') 
        return element.closest(sel) || null;
    
    let ancestor: HTMLElement | null = element;
    while (ancestor) 
        if (ancestor.matches(sel)) 
            return ancestor;
        
        ancestor = ancestor.parentElement;
    
    return null;

【讨论】:

【参考方案2】:

显然设置src在chrome中刷新iframe,给定的示例代码将是:

<script type="text/javascript">
    $("button").on("click", function() 
        $('iframe').toggle().attr('src', function(i, val)  return val; );
    );
</script>

【讨论】:

想解释一下它为什么有效,而不是只发布代码?【参考方案3】:

我在 Chrome 上遇到了类似的问题,其中 iframe 嵌入到 jQuery UI 选项卡中。首次显示包含 iframe 的选项卡时,会出现滚动条。但是当我切换到另一个选项卡并返回到带有 iframe 的选项卡时,滚动条就会消失。这里提出的所有解决方案都不适合我。 这是我为解决此问题所做的工作: 首先,我创建标签:

$("#mytabs").tabs();

然后我将一个函数绑定到事件“tabsactivate”并检查目标选项卡是否是包含 iframe 的选项卡。如果是这种情况,我将调用稍后描述的函数 fixChromeScrollBar():

$("#mytabs").on("tabsactivate", function(event, ui) 
    if ($(event.originalEvent.target).attr("href") == "#mytab-with-iframe") 
        fixChromeScrollBar();
    
);

最后是函数 fixChromeScrollBar(),它将 iframe 主体的溢出样式属性(如前所述)设置为“滚动”或“自动”。我注意到,当我只定义“自动”或“滚动”值时,如果我切换到另一个选项卡并返回 iframe,我会丢失滚动条。维护它们的唯一方法是每次 iframe 出现时在两个值之间交替。这很奇怪,但它有效:

function fixChromeScrollBar() 
    var iFrameBody = $("#myiframe").contents().find("body");
    var originalOverflow = $(iFrameBody).css("overflow");
    if (originalOverflow == "visible" || originalOverflow == "auto") 
        $(iFrameBody).css("overflow", "scroll");
     else 
        $(iFrameBody).css("overflow", "auto");
    

您会注意到,只有当您切换到包含 iframe 的选项卡时才会调用此方法,因此如果您在此选项卡上多次单击而不切换到另一个选项卡,则只会在第一次执行此代码。

【讨论】:

【参考方案4】:

对于给定的示例,您可以这样做:$("iframe").toggle(1) 在我的情况下,它通过设置高度来工作:$("iframe").css("height", "100%")

【讨论】:

【参考方案5】:

Chrome 52.0.2743.82 (http://googlechromereleases.blogspot.fr/2016/07/stable-channel-update.html) 更新似乎出现了这个错误

一种可能的解决方法是使用属性visibilityposition: absolute 而不是display 来显示或隐藏iframe

此项目存在 chrome bug 票证:https://bugs.chromium.org/p/chromium/issues/detail?id=641881

【讨论】:

关于这个的问题,显示属性是至关重要的,没有它我的网站就无法工作,有什么办法可以解决这个错误?还有关于谷歌可能修复的任何信息吗?他们知道吗? 我可以在 Chrome 54 中重现此问题,但我在 bugs.chromium.org 中找不到任何报告的错误 - 它是否存在或者我应该提交一个新错误?【参考方案6】:

这是我为正在构建的应用程序开发的解决方法。它在 Foundation 选项卡控件中有多个 &lt;iframe&gt; 元素。

我使用MutationObserver 观察&lt;iframe&gt; 的父元素(基础div.tabs-content div.content 元素)何时变为active,然后切换iframe 的文档的overflow 属性。运行时效果难以察觉。

我最初想直接observe &lt;iframe&gt;,但是当 iframe 本身更改 display 属性时没有引发 DOM 突变事件,我猜是因为从技术上讲 element.style 值不是 DOM 结构的一部分正确的。

这是我的代码(Vanilla.js,没有 jQuery)。如果您在您的应用程序中使用,您需要将我的可见性检测代码替换为适用于您的文档的代码:

window.addEventListener('DOMContentLoaded', function(e) 

    var observer = new MutationObserver( onContentMutated );
    var options =  attributes: true, childList: false, characterData: false, subtree: false, attributeFilter: ['class'] ;

    var iframeContainers = document.querySelectorAll('.tabs-content .content');
    for(var i = 0; i < iframeContainers.length; i++) 

        observer.observe( iframeContainers[i], options );
    
);

function onContentMutated(mutations) 

    for(var i = 0; i < mutations.length; i++) 
        var m = mutations[i];

        var thisIsNowAnActiveTab = m.target.classList.contains('active');
        if( thisIsNowAnActiveTab ) 
            // get the corresponding iframe and fiddle with its DOM

            var iframes = m.target.getElementsByTagName("iframe");
            if( iframes.length == 0 ) continue;
            var iframe = iframes[0];

            iframe.contentWindow.document.documentElement.style.overflow = 'hidden';

            // the timeout is to trigger Chrome to recompute the necessity of the scrollbars, which makes them visible again. Because the timeout period is 0 there should be no visible change to users.
            setTimeout( function(s) 

                s.overflow = 'auto';

            , 0, iframe.contentWindow.document.documentElement.style );
        

        console.log( m.type );
    

【讨论】:

【参考方案7】:

我遇到过这个问题,并且不能使用 visibility 代替 display: none

我的解决方法是在 iframe 中显示的文档的 &lt;body&gt; 上设置 overflow: scroll,每当我将 iframe 设置为再次可见时。这似乎迫使滚动条再次出现在 iframe 上。然后,您可以将 overflow 重置为其旧值,滚动条将保留在 iframe 上。不过,您需要等待重绘才能重置overflow,因此我将其设置为延迟为 0 的超时。

function showIframe(iframe) 
    var iframeBody = iframe.contentDocument.body;
    $(iframe).show();
    var oldOverflow = iframeBody.css("overflow");
    iframeBody.css("overflow", "scroll");
    window.setTimeout(function () 
        iframeBody.css("overflow", oldOverflow);
    , 0);

如果有问题的 iframe 不需要滚动,则此解决方法会出现滚动条的“闪烁”,因此在需要重绘的短暂时刻使用 visibility 解决方法可能是值得的,避开闪光灯。

【讨论】:

以上是关于可见性更改时,IFrame 滚动条在 chrome 上消失的主要内容,如果未能解决你的问题,请参考以下文章

在鼠标悬停时更改 DataGrid ScrollBar 的可见性?

使滚动条在移动浏览器中可见

检查滚动条可见性

如何使水平滚动条在 DT::datatable 中可见

滚动条在 jquery 移动应用程序中不可见

使滚动条在uiscrollview中始终可见[重复]