本文介绍了跨域IFrame element.scrollIntoView()Safari问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个困扰整个Google的问题,但是所提供的解决方案均无法正常工作.我认为这些解决方案中的大多数都不能解决跨域问题.

I have ran into an issue that is plagued all over google but none of the provided solutions work correctly. I assume the majority of these solutions do not account for cross domain.

我有一个网站,我想指示用户使用(整页)iframe嵌入他们的网站.问题仅在某些版本的Safari上存在. IFrame中的元素无法滚动到视图中.

I have a website which I would like to instruct users to embed into their site with a (full page) IFrame. The problem is on some versions of Safari only. Elements within the IFrame can not scroll themselves into view.

我注意到,如果我进行相同的域测试,则iframe可以使用window.parent.scrollTo(0,element.top)进行滚动.这可行,但不能跨域.另一个奇怪的是,没有其他浏览器需要window.parent方法来滚动IFrame,仅需要Safari.所有其他浏览器都可以在IFrame中使用element.scrollIntoView().请注意,我已经使用 JavaScript解决方法来使用带有跨协议IFrame的Safari.

I notice that if I do a same domain test the IFrame can scroll itself using window.parent.scrollTo(0,element.top). This works, but not cross domain. Another odd thing is that no other browser requires the window.parent method to scroll the IFrame, only Safari. All other browsers can use element.scrollIntoView() from within the IFrame. Note that I already use the JavaScript workaround to please Safari with cross-protocol IFrames.

我仅在IFrame内部的Safari Mobile上看到的另一个问题是,向下滚动时,Bootstrap Modals在IFrame的顶部看不见.虽然,我确定如果可以正确设置滚动位置,那么我们也应该能够设置模式位置.

Another issue I've only seen on Safari Mobile inside IFrame is that Bootstrap Modals appear out of view at the top of the IFrame when scrolled down. Although, I'm sure if we can correctly set the scroll position we should be able to set the modal position as well.

这就是我尝试过的;

 1. window.frames['IFrameName'].document.
    getElementById("elmId").scrollIntoView();
  1. 补偿技巧
  2. Velocity.js

(我认为)我最后的选择是在IFrame中使用postMessage通知父域以设置框架的滚动位置.

My last resort here (I think) is to use postMessage from within my IFrame to notify the parent domain to set the scroll position of the frame.

在我看来,这个问题已经存在了很长时间.有没有比这更好的方法了?

It seems to me that this issue has been around for an awful long time. Is there a better approach than this?

推荐答案

这最终比代码更多的研究.发生的是-我有一些代码根据内容调整了IFrame的大小.

This ended up being a lot more research than code. What was going on was - I had code that resized the IFrame based on the content.

在所有其他浏览器中,它可以正常工作,并消除了滚动条.事实证明,Safari浏览器自动调整iframe的大小,仅保留滚动条.在我的应用程序中,静态页面为零.这给我留下了无法使用链接中所述的scrolling=no修复程序的问题.

In all other browsers this works fine and eliminates the scroll bars. Turns out that Safari automatically sizes the Iframe leaving scrolls of it's own. In my application there are zero static pages. This leaves me with the issue of not being able to use the scrolling=no fix described in the link.

确切地了解了所发生的情况之后,我采用了另一种方法来修复elm.scrollIntoView().该代码是注释,然后是重要部分;

After discovering exactly what was going on I took a different approach to fixing elm.scrollIntoView(). The code is more comments then anything but the important parts are;

  1. 检测何时使用RequiresIframeScrollFix
  2. 应用iframe修订
  3. 使用elm.getBoundingClientRect().top从iframe中获取滚动位置.
  4. 与父母沟通以滚动window.parent.postMessage
  5. 使用window.addEventListener('message',...)
  6. 在父级中接收邮件
  1. Detecting when to apply the Iframe fix with RequiresIframeScrollFix
  2. Using elm.getBoundingClientRect().top to get our scroll position from within the Iframe.
  3. Communicating to the parent to scroll with window.parent.postMessage
  4. Receiving the message in the parent with window.addEventListener('message',...)

这是它的样子.

iframe网站

我们的iframe网站当前将其元素滚动到这样的视图中elm.scrollIntoView();我们已将其更改为以下内容.

Our Iframe site currently scrolls it's elements into view like this elm.scrollIntoView(); We've changed that to the following.

if (RequiresIframeScrollFix())
     window.parent.postMessage(elm.getBoundingClientRect().top, "*"); // Tell IFrame parent to do the scrolling. If this is not a test environment, replace "*" with the parent domain.
 else
     elm.scrollIntoView(); // If not scroll into view as usual.

可选:使用elm.getBoundingClientRect().top修复了IOS IFrame中的引导模式定位.

Optional: fix for bootstrap modal positioning in IOS IFrames using elm.getBoundingClientRect().top.

$('#modalId').css('top', elm.getBoundingClientRect().top); // This fixes modal not in view on Safari Iframes.

RequiresIframeScrollFix()主要由一些很好的文档代码组成,这些代码围绕SO来确定我们是否位于IPad或IPhone上的iframe中.

RequiresIframeScrollFix() is mostly made up of some well document code laying around SO to determine if we're in an Iframe on the IPad or IPhone.

// Used to help identify problematic userAgents.
var debugNavigator = false;

// Detects an issue on mobile where the Parent is an iframe which cannot have it's scroll bars removed.
// Presumably not a bug as safari will autosize it's iframes: https://salomvary.com/iframe-resize-ios-safari.html
// Can use "scrolling=no" fix instead if the parent knows the initial size of your iframe.
function RequiresIframeScrollFix() {
    try {
        // Debug navigator Agent
        if (debugNavigator)
            alert(navigator.userAgent);

        // We know this issue happens inside an IFrame on;
        // Safari iPhone
        // Safari iPad
        // Safari Desktop Works fine.

        // Check for safari
        var is_safari = navigator.userAgent.indexOf("Safari") > -1;
        // Chrome has Safari in the user agent so we need to filter (https://stackoverflow.com/a/7768006/1502448)
        var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
        if ((is_chrome) && (is_safari)) { is_safari = false; }

        // If we need to narrow this down even further we can use a more robust browser detection (https://stackoverflow.com/questions/5916900)
        // Problematic browsers can be adjusted here.
        if (is_safari && inIframe() && (
                navigator.userAgent.match(/iPad/i) ||
                navigator.userAgent.match(/iPhone/i)
                ))
            return true;
        else
            return false;

    } catch (e) {
        alert(e.message);
    }
}

// (https://stackoverflow.com/questions/326069/)
function inIframe() {
    try {
        return window.self !== window.top;
    } catch (e) {
        return true;
    }
}

父网站

我们的父网站拥有由Safari Mobile自动调整大小的IFrame.因此,父网站现在拥有自己的滚动条,而不是IFrame.我们在父网站内部设置了侦听器,以在其从IFramed网站接收到消息时进行滚动.

Our parent site holds the IFrame that was automatically sized by Safari Mobile. Therefore the parent site now has scroll bars of it's own, and not the IFrame. We set our listener up inside the parent site to scroll itself when it receives a message from the IFramed site.

// Safari Mobile Iframe Cross Domain Scroll Fix.
window.onload = function () {
     // Calback function to process our postMessages.
     function receiveMessage(e) {
          try {
               // Set the scroll position from our postMessage data.
               // Non-Test pages should uncomment the line below.
               //if (e.origin.includes("your-iframe-domain.com"))
               window.scrollTo(0, e.data);
           }
           catch (err) {
           }
      }

      // Setup and event to receives messages form our iframe (or window)
      window.addEventListener('message', receiveMessage);
}

希望这可以帮助其他人在移动设备上解决Safari Iframe问题.另外,让我知道是否我忽略了更好的解决方案.

Hopefully this helps someone else dissect Safari Iframe problems on mobile. Also, let me know if I've overlooked a better solution.

这篇关于跨域IFrame element.scrollIntoView()Safari问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 04:59