跨域 IFrame element.scrollIntoView() Safari 问题

cla*_*oda 4 javascript safari iframe jquery

我遇到了一个困扰整个谷歌的问题,但提供的解决方案都没有正常工作。我假设这些解决方案中的大多数都没有考虑跨域。

我有一个网站,我想指导用户将(整页)IFrame 嵌入到他们的网站中。问题仅出现在某些版本的 Safari 上。IFrame 中的元素无法将自身滚动到视图中。

在此处输入图片说明

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

我只在 IFrame 中的 Safari Mobile 上看到的另一个问题是,当向下滚动时,Bootstrap Modals 出现在 IFrame 的顶部。尽管如此,我确信如果我们可以正确设置滚动位置,我们也应该能够设置模态位置。

这是我尝试过的;

 1. window.frames['IFrameName'].document.
    getElementById("elmId").scrollIntoView();
Run Code Online (Sandbox Code Playgroud)
  1. 偏移技巧
  2. 速度.js

我最后的手段(我认为)是在我的 IFrame 中使用 postMessage 来通知父域设置框架的滚动位置。

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

cla*_*oda 7

这最终导致了比代码更多的研究。发生了什么 - 我有根据内容调整 IFrame 大小的代码。

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

在确切地发现发生了什么之后,我采取了不同的方法来修复elm.scrollIntoView(). 代码比其他任何东西都多,但重要的部分是;

  1. 检测何时应用 Iframe 修复 RequiresIframeScrollFix
  2. 使用elm.getBoundingClientRect().top从iframe内,让我们的滚动位置。
  3. 与父母沟通以滚动 window.parent.postMessage
  4. 在父级中接收消息 window.addEventListener('message',...)

这是它的样子。

iframe 网站

我们的 iframe 网站目前将其元素滚动到视图elm.scrollIntoView();中,如下所示。我们已将其更改为以下内容。

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.
Run Code Online (Sandbox Code Playgroud)

可选:使用elm.getBoundingClientRect().top.

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

RequiresIframeScrollFix() 主要由围绕 SO 的一些良好的文档代码组成,以确定我们是否在 iPad 或 iPhone 上的 Iframe 中。

// 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 (/sf/answers/543760451/)
        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 (/sf/ask/414183031/)
        // 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);
    }
}

// (/sf/ask/22824861/)
function inIframe() {
    try {
        return window.self !== window.top;
    } catch (e) {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

父站点

我们的父站点包含由 Safari Mobile 自动调整大小的 IFrame。因此,父站点现在拥有自己的滚动条,而不是 IFrame。我们在父站点内设置我们的侦听器,当它从 IFramed 站点接收到消息时滚动自身。

// 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);
}
Run Code Online (Sandbox Code Playgroud)

希望这有助于其他人剖析移动设备上的 Safari Iframe 问题。另外,如果我忽略了更好的解决方案,请告诉我。