How do I fallback from scrollIntoViewOptions for compatibility with Safari?

3.6k views Asked by At

I have an onclick that triggers this function:

 function thread2M() {
        
  var elmnt = document.getElementById("scroll2");
  elmnt.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});

}

which scrolls the page to a particular pixel (a div) and centers it. Of course, scrollIntoViewOptions doesn't work in Safari, so I'd like to fall back to scrollIntoView() or scrollTo().

I've tried:

function thread2M() { 
    var elmnt = document.getElementById("scroll2");
    try {
        elmnt.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});
}    catch {
        elmnt.scrollIntoView(true);
}
}

and

function thread2M() {
            if (typeof document.body.scrollIntoView === 'function') {
  var elmnt = document.getElementById("scroll2");
  elmnt.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});}

  else {window.scrollTo(782, 280);}
 
}

but no scroll is initiated. I don't even have basic knowledge of how JS works, so the answer is probably related to fundamentals, but I can't find the solution out there. I think I just need to test if scrollIntoViewOptions works, if true, run one script, if false, run another.

Answers appreciated, thank you.

1

There are 1 answers

1
mugwhump On BEST ANSWER

That first attempt looks workable. Try looking in the console to see what's happening:

function thread2M() { 
    var elmnt = document.getElementById("scroll2");
    try {
        console.log("Calling scrollIntoView");
        elmnt.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});
    }    catch (error) {
        console.log("Error scrolling: " + error.message);
        elmnt.scrollIntoView(true);
    }
}

(If you can't find safari's log you could replace "console.log" with "alert" and the message will pop up on the screen.)

The second one won't work because Safari does have a scrollIntoView function; it just doesn't accept the options argument that other browsers do.

There's three other options you could try. The first is to check the existence of the CSS scrollbehavior property (which isn't quite the same thing, but is highly related):

function thread2M() { 
    var elmnt = document.getElementById("scroll2");
    if('scrollBehavior' in document.documentElement.style) {
        elmnt.scrollIntoView({behavior: "smooth", block: "center", inline: "center"});
    } else {
        elmnt.scrollIntoView(true);
    }
}

Or you could try using a getter to overwrite the behavior of scrollIntoViewOptions. (credit to nlawson for using this to test scrollTo support). Above your thread2M function try adding this:

function testSupportsSmoothScroll () {
  var supports = false
  try {
    var div = document.createElement('div')
    div.scrollIntoView({
      get behavior () {
        supports = true
        return 'smooth'
      }
    })
  } catch (err) {}
  return supports
}

Then replace the if test in thread2M with if (testSupportsSmoothScroll()). Note that I haven't been able to test any of this on a browser without scrollIntoViewOptions, but it does seem to work on chrome/ff.

Lastly you could try using a polyfill script which will (hopefully) detect and smooth out browser differences. I've never tried this myself but you could try seamless scroll polyfill. Import the script in your header:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/es5/seamless.js"></script>

Then modify thread2M like so:

function thread2M() { 
    var elmnt = document.getElementById("scroll2");
    seamless.elementScrollIntoView(elmnt, {behavior: "smooth", block: "center", inline: "center"});
}

Although with this approach you do need to load another 32KB script, but that's not so bad.