Mobile Safari, scrollIntoView doesn't work

2020-04-07 04:31发布

问题:

I have problem with scroll to element on mobile Safari in iframe(it works on other browsers, including Safari on mac).

I use scrollIntoView. I want to scroll when all contnet has been rendered. Here is my code:

var readyStateCheckInterval = setInterval(function () {
    if (document.readyState === "complete") {
       clearInterval(readyStateCheckInterval);
        $browser.notifyWhenNoOutstandingRequests(function () {
            if (cinemaName != null && eventId == null) {
                scrollToCinema();
            } else {
                scrollToEvent();
            }
        });
     }
}, 10);


function scrollToEvent() {
    var id = eventId;
    var delay = 100;

    if (cinemaName != null) {
        id = cinemaName + "#" + eventId;
    }

    if ($rootScope.eventId != null) {
        id = $rootScope.cinemaId + "#" + $rootScope.eventId;
    }

    $timeout(function () {
        var el = document.getElementById(id);
        if (el != null)
        el.scrollIntoView(true);    
        $rootScope.eventId = null;
    }, delay);
}

回答1:

ScrollIntoView does not work (currently). But you can manually calculate the position of the element and scroll to it. Here is my solution

const element = document.getElementById('myId')

Pass the element to this function

/** Scrolls the element into view
 * Manually created since Safari does not support the native one inside an iframe
*/
export const scrollElementIntoView = (element: HTMLElement, behavior?: 'smooth' | 'instant' | 'auto') => {

  let scrollTop = window.pageYOffset || element.scrollTop

   // Furthermore, if you have for example a header outside the iframe 
   // you need to factor in its dimensions when calculating the position to scroll to
   const headerOutsideIframe = window.parent.document.getElementsByClassName('myHeader')[0].clientHeight

  const finalOffset = element.getBoundingClientRect().top + scrollTop + headerOutsideIframe

  window.parent.scrollTo({
    top: finalOffset,
    behavior: behavior || 'auto'
  })
}

Pitfalls: Smooth scroll also does not work for ios mobile, but you can complement this code with this polyfill



回答2:

Your most likely having the exact same issue I just debugged. Safari automatically resizes the frame to fit it's contents. Therefore, the parent of the Iframe will have the scrollbars in Safari. So calling scrollintoview from within the Iframe itself 'fails'.

If Iframe is cross domain accessing the parent document via window.parent.document will be denied.

If you need a cross domain solution check my answer here.

Basically I use post message to tell the parent page to do the scrolling itself when inside Mobile Safari cross domain.