Search code examples
javascriptiosiframesafarimobile-safari

Mobile Safari, scrollIntoView doesn't work


I have a 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 content 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);
}

Solution

  • 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