Полоса прокрутки IFrame исчезает в chrome при изменении видимости

У Google Chrome в Windows возникают проблемы с отображением полос прокрутки 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 ссылка на код

при загрузке страницы отображается iframe в виде полосы прокрутки.

скрыть и показать iframe, нажав кнопку. Полоса прокрутки исчезает.

эта проблема, по-видимому, возникает только в хром.

кто-нибудь испытывает это тоже? Любые исправления / обходные пути?

8 ответов


кажется, что ошибка появилась с обновлением Chrome 52.0.2743.82 (http://googlechromereleases.blogspot.fr/2016/07/stable-channel-update.html)

одним из возможных способов является использование атрибута visibility с position: absolute вместо display показать или скрыть iframe.

билет ошибки chrome существует для этого элемента:https://bugs.chromium.org/p/chromium/issues/detail?id=641881


у меня была эта проблема, и с помощью visibility вместо display: none не вариант.

мое решение было установить overflow: scroll на <body> документа, отображаемого в iframe, всякий раз, когда я устанавливаю 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> элементы в закладке Foundation-control.

я MutationObserver наблюдать, когда <iframe>родительский элемент (a Foundation div.tabs-content div.content элемент) становится active, затем я переключаю iframe'документа " с"overflow собственность. Эффект времени выполнения непостижим.

я изначально хотел observe на <iframe> сразу, однако никакие события мутации DOM не были подняты когда сам iframe изменился display свойство, я думаю, потому что технически говоря element.style значения не являются частью собственно структуры DOM.

вот мой код (ваниль.js, no 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 );
    }
}

для данного примера можно сделать:
$("iframe").toggle(1)

В моем случае это сработало, установив высоту:
$("iframe").css("height", "100%")


у меня была аналогичная проблема в 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 (как уже было сказано) либо "прокрутка", либо "авто". Я заметил, что когда я только определяю значение "auto" или "scroll", то, если я переключусь на другую вкладку и вернусь к 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, поэтому, если вы нажмете несколько раз на этой вкладке без переключения на другой, этот код будет выполнен только в первый раз.


видимо задание src обновляет iframe в chrome, для данного примера код будет:

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

я адаптировал пример 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;
}

добавить

iframe { overflow-y: scroll; }

для вашего CSS