Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
}
like image 736
kszram Avatar asked Jul 14 '17 08:07

kszram


3 Answers

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

like image 95
David Pascoal Avatar answered Nov 15 '22 18:11

David Pascoal


In my experience scrollIntoView() fails sometimes on my iphone and my ipad and sometimes it works (on my own web sites). I'm not using iframes. This is true both with safari and firefox on the above devices.

The solution that works for me is to pop the element you need to scroll to inside a DIV eg. as the first element in that DIV. Hey presto it then works fine! Seems like a dodgy implementation by Apple.

like image 42
Dave Gott Avatar answered Nov 15 '22 19:11

Dave Gott


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.

like image 40
clamchoda Avatar answered Nov 15 '22 18:11

clamchoda