Mobile Safari, scrollIntoView doesn't work
Asked Answered
G

4

17

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);
}
Gorman answered 14/7, 2017 at 8:47 Comment(0)
F
15

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

Flyn answered 18/5, 2018 at 12:11 Comment(1)
Update 2022 from own experience: it works - but weirdly only about 1 out of 10 (or more) times. And i cannot recreate or understand what makes it work when it does.Menu
M
5

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.

Mulvaney answered 9/7, 2020 at 20:28 Comment(0)
U
4

The scrollIntoView method worked inconsistently for me in Safari on iOS. It would work every second time that I tap an input element into focus, otherwise it scrolls below the input element. It seems the issue is with the iOS keyboard that pops up. My solution was to set a timer on scrollIntoView to fire after the keyboard appears.

const inputRef = useRef(null);

const handleFocus = () => {
    setTimeout(() => {
        inputRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }, 100);
};
Understate answered 28/6, 2023 at 13:14 Comment(0)
O
1

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.

Orpine answered 11/2, 2019 at 1:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.