2016-07-24 36 views
7

Czy Google Chrome w systemie Windows ma problemy z wyświetlaniem pasków przewijania w ramkach iframe?Pasek wskaźnika IFrame znika na chromie, gdy zmienia się widoczność.

Napisałem bardzo prosty kod, aby pokazać, co dzieje się (przynajmniej u mnie na 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

Po załadowaniu strony, iframe, jak to paski przewijania są widoczne.

Ukryj i pokaż element iframe, klikając przycisk. Pasek przewijania znika.

Ten problem widocznie pojawia się tylko w chrome.

Ktoś też tego doświadcza? Jakieś poprawki/obejścia?

+0

Wydaje się, że błąd wystąpił z Chrome 52.0.2743.82: http://googlechromereleases.blogspot.fr/2016/07/stable-channel-update.html – lepix

Odpowiedz

4

Wydaje się, że błąd wystąpił z aktualizacją Chrome 52.0.2743.82 (http://googlechromereleases.blogspot.fr/2016/07/stable-channel-update.html)

Możliwym rozwiązaniem jest użyć atrybutu visibility z position: absolute zamiast z display, aby pokazać lub ukryć iframe.

Istnieje bug chrom bilet dla tej pozycji: https://bugs.chromium.org/p/chromium/issues/detail?id=641881

+0

Pytanie dotyczące tego, atrybut display jest kluczowa i mój strona internetowa nie może bez niej działać, alternatywy do obejścia tego błędu? a także czy są jakieś informacje dotyczące możliwej poprawki przez Google? czy są tego świadomi? –

+0

Mogę odtworzyć ten problem w Chrome 54, ale nie mogę znaleźć żadnego zgłoszonego błędu na stronie https://bugs.chromium.org - czy istnieje, czy powinienem złożyć nowy? – Dai

-2

Dodaj

iframe { overflow-y: scroll; } 

do swojego CSS

3

miałem tego problemu, a przy użyciu visibility zamiast display: none nie było opcji.

Moim obejściem było ustawienie overflow: scroll na <body> dokumentu wyświetlanego w elemencie iframe, ilekroć ustawię element iframe, aby był widoczny ponownie. Wygląda na to, że pasek przewijania ponownie pojawi się na elemencie iframe. Następnie możesz zresetować overflow do starej wartości, a pasek przewijania pozostanie na elemencie iframe. Trzeba czekać na repaint, zanim będzie można zresetować overflow, choć, więc kładę to na timeout z opóźnieniem 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); 
} 

Jest „Flash” z paska przewijania z tego obejścia jeśli iframe w pytaniu nie trzeba jednak przewijać, dlatego warto użyć obejścia tymczasowego dla krótkiego momentu, w którym wymagane jest odświeżenie, aby uniknąć flashowania.

1

Oto rozwiązanie, które opracowałem dla aplikacji, którą buduję. Ma wiele elementów w zakładce Control.

użyłem MutationObserver obserwować kiedy jest elementem dominującym (element Fundacja div.tabs-content div.content) staje active, potem przełączam iframe 's dokumentu overflow nieruchomości. Efekt środowiska wykonawczego jest nie do zauważenia.

Początkowo chciałem observe bezpośrednio, jednak żadne zdarzenia DOM mutacji pojawiły się, kiedy sama iframe zmieniło display własności, chyba dlatego, że z technicznego punktu widzenia element.style wartości nie są częścią DOM-struktury właściwej.

Oto mój kod (Vanilla.js, bez jQuery). Jeśli używasz w swojej aplikacji będziemy chcieli, aby zastąpić mój kod wykrywania widoczność z czymś, co jest stosowane w dokumencie:

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

Na podanym przykładzie można zrobić:
$("iframe").toggle(1)

W moim przypadek, że pracował przez ustawienie z powrotem wysokość:
$("iframe").css("height", "100%")

0

miałem podobny problem w Chrome z iframe osadzonych w karcie jQuery UI. Po wyświetleniu karty zawierającej element iframe zostanie wyświetlony pasek przewijania. Ale kiedy przełączam się na inną kartę i powracam do zakładki z ramką iframe, pasek przewijania znika. Wszystkie proponowane tutaj rozwiązania nie działają dla mnie. Oto co zrobiłem, aby rozwiązać ten problem: pierwsze, tworzyć zakładki:

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

Następnie wiążę funkcję do zdarzenia „tabsactivate” i sprawdzić, czy karta cel jest jeden zawierający iframe . Jeśli jest to przypadek nazywam fixChromeScrollBar function() opisane później:

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

I wreszcie Oto fixChromeScrollBar function(), która ustawia atrybut stylu przelewowy ciała iframe (jak już wspomniano) albo " przewiń "lub" auto ". Zauważyłem, że gdy definiuję tylko wartość "auto" lub "scroll", to jeśli przełączyłem się na inną kartę i powróciłem do elementu iframe, tracę paski przewijania. Jedynym sposobem ich utrzymania jest przełączanie się między tymi dwiema wartościami za każdym razem, gdy pojawia się element iframe. To dziwne, ale to działa:

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"); 
    } 
} 

Można zauważyć, że metoda ta jest wywoływana tylko po przełączeniu na zakładkę zawierającą iframe więc jeśli klikniesz wielokrotnie na tej karcie bez przełączania na inny kod będzie tylko wykonać za pierwszym razem.

0

Najwyraźniej ustawienie src odświeża iframe w chromie, na przykład dany kod będzie:

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

Chcesz wyjaśnić, dlaczego to działa, a nie tylko publikować kod? –

0

I dostosowany przykład Dai do własnego React komponentu iframe. Mam element iframe w panelu kart, który sam jest w panelu zwijanym. Kiedy któryś z nich się przełącza, zmuszam iframe do odświeżenia. Działa wspaniale.

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; 
}