Cross Domain IFrame element.scrollIntoView() Safari Issue

半城伤御伤魂 提交于 2019-12-21 17:27:08

问题


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.

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.

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.

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.

Here's what I've tried;

 1. window.frames['IFrameName'].document.
    getElementById("elmId").scrollIntoView();
  1. Offset trick
  2. Velocity.js

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?


回答1:


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.

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.

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. 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',...)

Here's what it looks like.

Iframe Site

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.

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

Parent Site

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

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



来源:https://stackoverflow.com/questions/54603497/cross-domain-iframe-element-scrollintoview-safari-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!