当可见性发生变化时,IFrame滚动条会在Chrome上消失

问题描述 投票:7回答:7

Windows上的Google Chrome浏览器是否存在渲染iframe滚动条的问题?

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

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

有人也在经历这个吗?任何修复/解决方法?

javascript html google-chrome iframe scrollbar
7个回答
4
投票

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

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

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


3
投票

我有这个问题,使用visibility而不是display: none不是一个选择。

我的解决方法是每当我将iframe设置为再次可见时,在iframe中显示的文档的overflow: scroll上设置<body>。这似乎迫使滚动条再次出现在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解决方法可能是值得的,以避免闪光。


1
投票

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

我使用MutationObserver来观察当<iframe>的父元素(一个基础div.tabs-content div.content元素)变成active时,然后我切换iframe的文档的overflow属性。运行时效果是不可思议的。

我最初想直接observe <iframe>,但是当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 );
    }
}

1
投票

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


0
投票

我在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体的溢出样式属性(如前所述)设置为“scroll”或“auto”。我注意到,当我只定义“自动”或“滚动”值时,如果我切换到另一个选项卡并返回到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的选项卡时才会调用此方法,因此如果您在此选项卡上多次单击而不切换到另一个选项卡,则此代码将仅在第一次执行时执行。


0
投票

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

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

0
投票

我将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;
}
© www.soinside.com 2019 - 2024. All rights reserved.