27

I'm using this to get a smooth scroll to a particular section when a user clicks on a button:

window.scroll({
  top: $(this).data('y'),
  left: 0,
  behavior: 'smooth'
});

This works great everywhere (including Android phones) but on Safari (desktop and iphone). In those cases it scrolls to the correct position but it isn't smooth, it's like it jumps.

I made a small demo on Codepen available here. Just click on the nav menu options and it will scroll there. This will be smooth on Chrome but not on Safari.

Is this not supported? (it doesn't seem to be the case looking at the doc) What are the supported options?

Thanks!

moondaisy
  • 4,303
  • 6
  • 41
  • 70
  • 1
    Possible duplicate of [Javascript - window.scroll({ behavior: 'smooth' }) not working in Safari](https://stackoverflow.com/questions/51229742/javascript-window-scroll-behavior-smooth-not-working-in-safari) – Jun Feb 28 '19 at 09:37
  • There is an official bug in the safari bug tracker for it: https://bugs.webkit.org/show_bug.cgi?id=188043 and https://bugs.webkit.org/show_bug.cgi?id=189907 – jantimon Aug 29 '19 at 14:18

3 Answers3

64

window.scroll is supported, but scroll-behavior CSS is not.

https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior

Pending support, consider using the smoothscroll-polyfill which adds smooth scrolling support for Safari, IE, and Edge.

Beau Smith
  • 33,433
  • 13
  • 94
  • 101
tyriker
  • 2,290
  • 22
  • 31
  • 6
    Not sure why of the downvote on this as this is correct and links to a top resource for more information. Up-voting to negate. – Robert Brisita Jun 18 '19 at 22:50
  • JFYI, the`smoothscroll-polyfill` doesn't work if you want to scroll a div with `overflow: hidden`, but this other one does - https://www.npmjs.com/package/seamless-scroll-polyfill – Dr. Freddy Dimethyltryptamine Aug 19 '22 at 13:58
7

I recently wrote down my ideas into a function, which is kind of polyfill for lacking smooth scroll feature support in IOS browsers and desktop Safari as well. Some may call it a bloody workaround, but hey, it's working. It doesn't require jQuery, it's pure javascript.

var fnc_scrollto = function(to,id){
    var smoothScrollFeature = 'scrollBehavior' in document.documentElement.style;
    var articles = document.querySelectorAll("ul#content > li"), i;
    if (to == 'elem') to = articles[id].offsetTop;
    var i = parseInt(window.pageYOffset);
    if ( i != to ) {
        if (!smoothScrollFeature) {
            to = parseInt(to);
            if (i < to) {
                var int = setInterval(function() {
                    if (i > (to-20)) i += 1;
                    else if (i > (to-40)) i += 3;
                    else if (i > (to-80)) i += 8;
                    else if (i > (to-160)) i += 18;
                    else if (i > (to-200)) i += 24;
                    else if (i > (to-300)) i += 40;
                    else i += 60;
                    window.scroll(0, i);
                    if (i >= to) clearInterval(int);
                }, 15);
            }
            else {
                var int = setInterval(function() {
                    if (i < (to+20)) i -= 1;
                    else if (i < (to+40)) i -= 3;
                    else if (i < (to+80)) i -= 8;
                    else if (i < (to+160)) i -= 18;
                    else if (i < (to+200)) i -= 24;
                    else if (i < (to+300)) i -= 40;
                    else i -= 60;
                    window.scroll(0, i);
                    if (i <= to) clearInterval(int);
                }, 15);
            }
        }
        else {
            window.scroll({
                top: to,
                left: 0,
                behavior: 'smooth'
            });
        }
    }
};

You may pass arguments to the function as numeric value (scollTo-position in pixels) or as a call of an element with index (in my case LI nodes in an UL --> "articles").

<a class="active" href="javascript:fnc_scrollto(0)">Home</a>
<a class="active" href="javascript:fnc_scrollto(457)">anywhere</a>
<a href="javascript:fnc_scrollto('elem',0)">element 1</a>
<a href="javascript:fnc_scrollto('elem',1)">element 2</a>

You may play around with the numbers to adapt the smooth effect to your needs. If you have a sticky navbar on top, you need to adapt the line

if (to == 'elem') to = articles[id].offsetTop;

to your needs like e.g.

if (to == 'elem') to = parseInt(articles[id].offsetTop-navbar.clientHeight);

Hope you like it :-)

Community
  • 1
  • 1
ddlab
  • 918
  • 13
  • 28
3

More specifically in a JavaScript context, the unsupported part is the behavior parameter on scrollToOptions as detailed here:

https://developer.mozilla.org/en-US/docs/Web/API/Window/scroll

EoghanM
  • 25,161
  • 23
  • 90
  • 123