4

When the user clicks a button on my page it creates a new element below it and then scrolls downwards towards it. I'd like this to be done smoothly, and that can be accomplished like so:

window.scroll({ top: document.body.scrollHeight, behavior: "smooth" });

However, this does not work on Safari, so it appears that I need to use a custom function instead to get this functionality.

I searched around and found this (current answer, but suboptimal):

doScrolling = (elementY, duration) => { 
  let startingY = window.pageYOffset;
  let diff = elementY - startingY;
  var start;

  // Bootstrap our animation - it will get called right before next frame shall be rendered.
  window.requestAnimationFrame(function step(timestamp) {
    if (!start) { start = timestamp; }
    // Elapsed milliseconds since start of scrolling.
    let time = timestamp - start;
    // Get percent of completion in range [0, 1].
    let percent = Math.min(time / duration, 1);

    window.scrollTo(0, startingY + diff * percent);

    let isScrollAtBottom = (window.innerHeight + window.pageYOffset) >= document.body.scrollHeight - 3;

    if (isScrollAtBottom) { return; }

    // Proceed with animation as long as we wanted it to.
    if (time < duration) {
      window.requestAnimationFrame(step);
    }
  })
}

Called like: this.doScrolling(document.body.scrollHeight, 750);

Which seems to work, but it doesn't seem to have the same semantics as window.scroll.

For one, you need to specify a duration, whereas with window.scroll it's implied.

Secondly, it seems as if window.scroll uses a different transition type? It's hard to tell, but it feels more like an ease as opposed to a linear transition, where it starts off slow, then goes fast, and then slows to a stop.

Is it possible to modify the above function to mimic the exact semantics of window.scroll such that you can't tell the difference between calling the two?

To clarify, I don't need to clone all the functionalities of window.scroll. The only thing I require is the ability to scroll to a given position (in my case it's always the end of the page) in a smooth manner. The function I provided above in my question is almost perfect, except that it's slightly janky and doesn't feel as smooth as window.scroll. I think it may be the animation style? It's kind of hard to tell why it looks "worse" since it's so fast.

Ryan Peschel
  • 9,095
  • 18
  • 57
  • 101
  • 2
    Click to body: https://jsfiddle.net/d30n2fao/ – biziclop Sep 26 '20 at 22:39
  • **a crazy thought:** one can surely use some fancy JS requestAnimationFrames, but… what if we did this via a css animation? I know, it's sounds insane. And IDK if it'll work. You add a special class on your root element, it activates `ease-in` position animation on the root, say 1s long. After 1s JS timeout removes that class and sets window.scroll to 100% ‍♂️ Though, you shouldn't do this, JS implementation would be better. It's just a thought (P.S: @biziclop, nice!) – kos Sep 26 '20 at 22:41
  • @biziclop Thanks, that is definitely a step in the right direction. It still feels slightly different from Chrome's implementation though. It's extremely subtle, but it's still slightly less smooth (although much more smooth than my answer). I'm going to try and find out exactly how long it takes Chrome to scroll. I assume it's 1000 milliseconds but I'm not sure, and maybe that's what's causing the visual difference. – Ryan Peschel Sep 26 '20 at 22:51
  • Update: so unless I'm doing something wrong, it looks like it takes around 380-390 milliseconds for Chrome to scroll to the bottom of the page using `window.scroll`, but when I try passing `380` as the duration to `doScrolling` it looks _a lot_ faster. I'm not sure why this is? Different easing function? – Ryan Peschel Sep 26 '20 at 23:02
  • Oh, it's because the duration passed to `doScrolling` is much higher than the actual time it takes. When I passed in 500 it only took 200 ms to get to the bottom of the page. That might be affecting things. – Ryan Peschel Sep 26 '20 at 23:09
  • Similar question https://stackoverflow.com/questions/45098593/mobile-safari-scrollintoview-doesnt-work – Rayees AC Sep 27 '20 at 01:17

5 Answers5

4

You could try using AnimeJS

add <script src="path/to/anime.min.js"></script> to your HTML page

or via CDN at https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.0/anime.min.js

And then

doScrolling = (elementY) => {
  const startingY = window.pageYOffset
  const diff = elementY - startingY

  const obj = {
    pos: startingY
  }

  const anime({
    targets: obj,
    pos: startingY + diff,
    round: 1,
    easing: 'easeInOutQuad',
    update: function() {
      window.scrollTo(0, obj.pos)
    }
  }).play()
}
oldboy
  • 4,533
  • 2
  • 18
  • 59
Jason
  • 289
  • 8
1

There was already an almost duplicate of this question (actually asking for what you need in a better way) that you should probably read.

You can't really write a script that does the same as the browser's implementations, because every browser has a different behavior.
Chrome for instance will ease in out the scrolling, i.e it will go slower at the beginning and the end of the animation, Firefox on the other hand uses a linear interpolation (a constant speed). Testing this accurately is near impossible.
But that's not a problem, because you don't need a script that does the same, you need a polyfill, which will add the missing feature only to the ones that need it, and let the original one of the browser that already support it.

So as pointed out in CDK's answer, there is a polyfill available, heavily tested and not too big (429 lines 11.1KB unminified with commments).

But I also did wrote a smaller version for that question, that fits here in about 100 lines:

/* Polyfills the Window#scroll(options) & Window#scrollTo(options) */
(function ScrollPolyfill() {

  // Safari incorrectly goes through the "behavior" member
  // making @nlawson"s solution failing there...
  // so we go back to ugly CSS check
  if (!('scrollBehavior' in document.documentElement.style)) {
    attachPolyfill();
  }

  function attachPolyfill() {
    var original = window.scroll, // keep the original method around
      animating = false, // will keep our timer's id
      dx = 0,
      dy = 0,
      target = null;

    // override our methods
    window.scrollTo = window.scroll = function polyfilledScroll(user_opts) {
      // if we are already smooth scrolling, we need to stop the previous one
      // whatever the current arguments are
      if (animating) {
        clearAnimationFrame(animating);
      }

      // not the object syntax, use the default
      if (arguments.length === 2) {
        return original.apply(this, arguments);
      }
      if (!user_opts || typeof user_opts !== 'object') {
        throw new TypeError("value can't be converted to a dictionnary");
      }

      // create a clone to not mess the passed object
      // and set missing entries
      var opts = Object.assign({
          left: window.pageXOffset,
          top: window.pageYOffset,
          behavior: 'auto'
        },
        user_opts
      );

      if (opts.behavior !== 'instant' && opts.behavior !== 'smooth') {
        // parse 'auto' based on CSS computed value of 'smooth-behavior' property
        // But note that if the browser doesn't support this variant
        // There are good chances it doesn't support the CSS property either...
        opts.behavior = window.getComputedStyle(document.scrollingElement || document.body)
          .getPropertyValue('scroll-behavior') === 'smooth' ?
          'smooth' : 'instant';
      }
      if (opts.behavior === 'instant') {
        // not smooth, just default to the original after parsing the oject
        return original.call(this, opts.left, opts.top);
      }

      // update our direction
      dx = (opts.left - window.pageXOffset) || 0;
      dy = (opts.top - window.pageYOffset) || 0;

      // going nowhere
      if (!dx && !dy) {
        return;
      }
      // save passed arguments
      target = opts;
      // save the rAF id
      animating = anim();

    };
    // the animation loop
    function anim() {
      var freq = 16 / 300, // whole anim duration is approximately 300ms @60fps
        posX, poxY;
      if ( // we already reached our goal on this axis ?
        (dx <= 0 && window.pageXOffset <= +target.left) ||
        (dx >= 0 && window.pageXOffset >= +target.left)
      ) {
        posX = +target.left;
      } else {
        posX = window.pageXOffset + (dx * freq);
      }

      if (
        (dy <= 0 && window.pageYOffset <= +target.top) ||
        (dy >= 0 && window.pageYOffset >= +target.top)
      ) {
        posY = +target.top;
      } else {
        posY = window.pageYOffset + (dx * freq);
      }
      // move to the new position
      original.call(window, posX, posY);
      // while we are not ok on both axis
      if (posX !== +target.left || posY !== +target.top) {
        requestAnimationFrame(anim);
      } else {
        animating = false;
      }
    }
  }
})();

// How to use
function scrollWin() {
  window.scrollTo({
    left: 1000,
    top: 1000,
    behavior: 'smooth'
  });
}
body {
  height: 5000px;
  width: 5000px;
  /* https://stackoverflow.com/a/51054396/3702797 */
  background-image: linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)), linear-gradient(to right, black 50%, white 50%), linear-gradient(to bottom, black 50%, white 50%);
  background-blend-mode: normal, difference, normal;
  background-size: 20px 20px;
}
<p>Click the button to scroll the document window to 1000 pixels.</p>
<button onclick="scrollWin()">Click me to scroll!</button>
Kaiido
  • 87,051
  • 7
  • 143
  • 194
  • This is rather complex (overrides the original scroll function and also supports scrolling in the X axis). I'd prefer if this were just a stand-alone function, but I can just do that on my end. I'm trying it out right now though to see if it works. Also, does it use the quadratic easing like the answer in the linked post or is it just linear? – Ryan Peschel Sep 27 '20 at 01:09
  • @RyanPeschel that's a polyfill so it does override the original only where this original lacks the feature, i.e in your Chrome it would not touch anything. This way, once installed, you just have to call the same and only `elem.scroll()`from any browser. And yes, the implementation in the snippet is the linear one, the one linked is eased. – Kaiido Sep 27 '20 at 01:43
  • Yeah, I just prefer to not override the browser functionality (even conditionally) considering the function isn't even a perfect polyfill to begin with (the easing is incorrect). I'd prefer to just have a simple function that accomplishes this as this is the only place in the application where I need this type of smooth scrolling. It seems as if the solution could be had if the easing function of the browser's could be discovered (Chrome's specifically, as the linear one used by Firefox is less appealing) – Ryan Peschel Sep 27 '20 at 02:06
  • What do you mean "the easing is incorrect"? Did you read my answer? Per specs there is no easing being defined, that's just a browser implementation detail and browsers do differ here. Linear is the default behavior of Firefox, eased is the default behavior of Chrome, but both **are correct**. And once again, it doesn't modify the browser's functionality, it only adds on Safari and IE a feature that they dont' have. And the polyfill linked does have the eased version. But you can't be sure that when Safari will implement the smooth behavior they'll use the same as Chrome anyway. – Kaiido Sep 27 '20 at 02:09
  • Right, I wasn't aware that the browsers differed in their easing implementations. I'll amend my question to note that I am looking to replicate Chrome's easing implementation. – Ryan Peschel Sep 27 '20 at 02:44
  • Please don't, editing a question in a way that invalidates an answer is frowned upon and very unethical. And anyway, I already pointed to a [polyfill](http://iamdustan.com/smoothscroll) that does that. – Kaiido Sep 27 '20 at 02:51
  • I mean I'm probably going to give you the bounty regardless since the other answer is invalid and you found some good links. It's just unfortunate that the polyfill you linked to doesn't have the same implementation as Chrome (from my tests they feel different). Oh well, if no one knows how they do their implementation then I guess I'll just use this one instead. – Ryan Peschel Sep 27 '20 at 02:59
  • @oldboy what doesn't work anymore? – Kaiido Dec 30 '20 at 02:35
  • whatever 'pollyfill available' links to (http://iamdustan.com/smoothscroll/) – oldboy Dec 30 '20 at 02:36
  • @oldboy so first, next time try to be explicit in your comments. And then, I don't know what firewall you're under, but here this link works fine. https://www.isitdownrightnow.com/iamdustan.com.html – Kaiido Dec 30 '20 at 02:40
  • uhhh, the link works fine. the library does not... – oldboy Dec 30 '20 at 02:44
  • @oldboy What browser? did you consider opening an issue on their [github repo](https://github.com/iamdustan/smoothscroll/issues)? Are you sure you did install it correctly? From my Safari browser (14.0.2), which is the browser this question was about, this polyfill still works very well. – Kaiido Dec 30 '20 at 02:49
  • their demo on their own website does not work in chrome 87 on windows 10. do not have the time since i am busy developing my own website. – oldboy Dec 30 '20 at 02:52
  • @oldboy and you think we are not busy doing our own jobs? And Chrome does support **natively** smooth scrolling since v45. The polyfill should not do anything on that browser. If you don't have the smooth scrolling enabled it's because **you** did disable it as part of your browser or OS settings. See https://stackoverflow.com/questions/62150827/how-to-make-element-scrollintoview-on-chromium-based-browsers-not-depend-on-sm/62483914#62483914 – Kaiido Dec 30 '20 at 02:57
1

I use a lot of Pixelarity templates for my clients' websites, and there is a script that (I think) does what you're looking for and is browser cross-compatible. It's called scrolly.js.

I've copied it below (since I also use RequireJS, I encapsulate it in a requires call), and you can also see it in action in many Pixelarity templates including Visualize and Atmosphere

requirejs(['jquery'],function(e){
    function u(s,o){
        var u,a,f;
        if((u=e(s))[t]==0) return n;
        a=u[i]()[r];
        switch(o.anchor){
            case"middle":
                f=a-(e(window).height()-u.outerHeight())/2;
                break;
            default:
            case r:
                f=Math.max(a,0)
        }
        return typeof o[i]=="function"?f-=o[i]():f-=o[i], f
    }
    var t="length",n=null,r="top",i="offset",s="click.scrolly",o=e(window);
    e.fn.scrolly=function(i){
        var o,a,f,l,c=e(this);
        if(this[t]==0) return c;
        if(this[t]>1){
            for(o=0; o<this[t]; o++) e(this[o]).scrolly(i);
            return c
        }
        l=n, f=c.attr("href");
        if(f.charAt(0)!="#"||f[t]<2) return c;
        a=jQuery.extend({
            anchor:r,
            easing:"swing",
            offset:0,
            parent:e("body,html"),
            pollOnce:!1,
            speed:1e3
        },i), a.pollOnce&&(l=u(f,a)), c.off(s).on(s,function(e){
            var t=l!==n?l:u(f,a);
            t!==n&&(e.preventDefault(), a.parent.stop().animate({scrollTop:t},a.speed,a.easing))
        })
    }
});

and you can invoke it on specific elements via jQuery like so (assuming you assign the scrolly class to those anchor elements:

$('.scrolly').scrolly();

I personally also have a header nav that comes down after you scroll down the page, so I include an offset to get the scroll destination just right...

$('.scrolly').scrolly({
    offset:function(){
        return $('.header').height();
    }
});
CJHolowatyj
  • 143
  • 8
0

After some close inspection of the timings of window.scroll i would propose the following changes for the doScrolling function.

Use window.scrollBy and set ScrollToOptions.behavior to smooth. it seems that a rate of 2px-2.5px per millisecond is kept in window.scroll after some time, and the timing function is ease-out, since at the first 200 milliseconds a slower rate is kept. You may adjust that rate and timing function by changing the calculation of totalTime.

The above changes mean that you will only have to change three lines of your code and add one.

Please do check the timings of each method supplied in the console.

function doScrolling(elementY) {
let start;
let startingY = window.pageYOffset || document.documentElement.scrollTop;
let diff = elementY - startingY;
let totalTime;
  window.requestAnimationFrame(function step(timestamp) {    
    if (!start) {
      start = timestamp;
    }
    // Elapsed milliseconds since start of scrolling.
    let time = timestamp - start;
    if(time < 200) { // this will set the proper totalTime but it adds a delay of about 600ms
      totalTime = diff/0.75;
    } else {
      totalTime = diff/2;
    }
    // Get percent of completion in range [0, 1].
    let percent = Math.min(time/totalTime, 1);

    window.scrollBy({ top: diff * percent, behavior: "smooth" });

    let isScrollAtBottom = (window.innerHeight + window.pageYOffset) >= document.body.scrollHeight - 3;

    if (isScrollAtBottom) {
      return;
    }

    // Proceed with animation as long as we wanted it to.
    if (time < totalTime) {
      window.requestAnimationFrame(step);
    }
  })
}
doScrolling(document.body.scrollHeight);

You could try both methods in the following examples to test for your own.

function doScrolling(elementY) {
  
  let start;
  let startingY = window.pageYOffset || document.documentElement.scrollTop;
  let diff = elementY - startingY;
  let totalTime;
  
  window.requestAnimationFrame(function step(timestamp) {
    if (!start) {
      start = timestamp;
    }
    // Elapsed milliseconds since start of scrolling.
    let time = timestamp - start;
    if(time < 200) { 
      totalTime = diff/0.75; // what to do the first 200 ms
    } else {
      totalTime = diff/0.125; // this will set the proper totalTime but it adds a delay of about 600ms
    }
    // Get percent of completion in range [0, 1].
    let percent = Math.min(time/totalTime, 1);
    
    console.info(parseInt(time),parseInt(diff * percent));
    
    window.scrollBy({
      left: 0,
      top: diff * percent,
      behavior: "auto"
    });

    let isScrollAtBottom = (window.innerHeight + window.pageYOffset) >= document.body.scrollHeight - 3;

    if (isScrollAtBottom) {
      return;
    }

    // Proceed with animation as long as we wanted it to.
    
    if (time < totalTime) {
      window.requestAnimationFrame(step);
    }
  })
}
/*const testStart = new Date().getTime();
window.addEventListener('scroll', () => {
  let now = new Date().getTime();
  let currentScrollOffset = window.pageYOffset || document.documentElement.scrollTop;
  console.log(now-testStart, currentScrollOffset);
});*/
doScrolling(document.body.scrollHeight);
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec quis aliquam libero. Vestibulum eu neque non augue tristique fermentum. Ut vulputate molestie metus in maximus. Integer a condimentum nisl, a vulputate nisl. Fusce vitae nulla a diam hendrerit ornare ac et ante. Aenean ac tortor turpis. Proin facilisis convallis iaculis. Maecenas vestibulum mauris mi, sit amet gravida augue malesuada at. Ut efficitur magna nunc, ac consequat ipsum interdum nec. Etiam vel ante vitae odio ornare luctus. Curabitur nunc ipsum, porttitor id enim ut, pellentesque vestibulum lorem. Sed tincidunt turpis ac ex tempus finibus. Praesent eget imperdiet ex. Morbi hendrerit pretium libero sit amet mattis. Sed a purus nec sapien mollis venenatis et vitae sem. Curabitur quis congue massa, pellentesque malesuada enim.

Quisque blandit quam posuere hendrerit venenatis. Vestibulum quis dictum felis. Aliquam non bibendum quam. Donec aliquam ex vel metus tristique tincidunt. Duis condimentum felis lacus. Integer gravida eu arcu sed placerat. Sed placerat, est nec luctus gravida, odio nisl vehicula risus, a aliquet massa sem eget leo. Nulla quis turpis ut lectus consequat tincidunt id sit amet lacus. Sed congue, massa fringilla venenatis iaculis, mi erat vulputate est, a vestibulum odio odio sit amet elit. Nulla suscipit rhoncus nisi, a lobortis arcu. Mauris malesuada placerat purus, eget molestie nisi. Nam luctus, odio a aliquam varius, ipsum ante malesuada augue, in congue metus eros id nibh. In varius justo et nunc maximus, vel blandit leo ullamcorper. Phasellus sit amet mi non dui consectetur porta sed vitae ex. Integer mauris diam, vulputate vel turpis ac, ornare auctor massa.

In hac habitasse platea dictumst. Proin id justo erat. Integer pretium luctus quam id congue. Aenean blandit rhoncus accumsan. Nulla ut luctus quam, nec vehicula ligula. Proin finibus sit amet dolor sit amet fringilla. Donec sodales iaculis dolor, sit amet egestas nisi. Aliquam nec scelerisque dolor. Donec maximus nulla eu quam posuere, nec condimentum nisl tristique. Aliquam venenatis massa cursus, scelerisque risus vitae, mattis quam.

Aliquam rhoncus quam quis erat ornare cursus. Vivamus et risus at risus pellentesque fermentum id ac eros. Phasellus vel molestie lacus, eget facilisis orci. Sed efficitur velit molestie nulla scelerisque elementum. Vestibulum luctus nibh justo, at venenatis purus tincidunt at. Pellentesque feugiat condimentum lorem, et accumsan odio. Nam sagittis lorem ut orci dictum fermentum. Integer non augue a sapien semper dictum sit amet ut orci. Aliquam a ultrices risus, non tincidunt enim. Aliquam neque metus, dapibus sed elit a, tempus pretium ante. Nullam non ex in leo tempus facilisis. Duis tempor, nibh at porta euismod, augue est auctor nisi, vitae ornare ante sem semper dolor. Duis hendrerit aliquet luctus.

Sed aliquet sem massa, vitae sodales eros fringilla quis. Quisque non dictum mi, quis facilisis augue. Ut scelerisque laoreet tellus, sed elementum metus pulvinar at. Maecenas faucibus id lorem faucibus maximus. Praesent efficitur, diam quis accumsan posuere, nunc diam porta est, sit amet facilisis velit urna non urna. Vivamus aliquet justo lorem. In hac habitasse platea dictumst. Curabitur auctor ornare sapien, id scelerisque mi posuere in. Morbi nec nisi tortor. Nulla et nisl odio. Integer nec consequat enim.

Integer dui diam, interdum bibendum velit at, accumsan fringilla libero. Suspendisse ac turpis et libero ullamcorper pretium. Etiam non mauris sapien. Nulla non massa turpis. Vestibulum accumsan metus risus, eget pretium nisi auctor in. Pellentesque imperdiet neque lacus, vitae dictum lorem iaculis sit amet. Donec at lacinia metus. Vivamus feugiat non quam non pulvinar. Sed eget eleifend dolor. Fusce suscipit, orci vitae vehicula sollicitudin, mi sem luctus lorem, tempor volutpat purus metus eget ipsum. Duis accumsan tellus non metus ultrices tempus. Etiam ut eros vitae purus pharetra interdum. Morbi a odio nibh. Proin gravida quam elit, at sollicitudin ipsum tristique et. In nec dolor pharetra, consequat dui ut, rutrum enim. Donec mollis felis consectetur turpis interdum, eu pellentesque nisi gravida.

Vivamus mollis, sem vitae finibus pretium, nunc sapien pulvinar est, quis sodales ligula augue nec ipsum. Duis ut faucibus elit, tincidunt interdum sem. Fusce semper enim eget augue lacinia mattis. Aliquam venenatis pretium tellus. Fusce rutrum magna sed erat varius, sit amet luctus dui rutrum. Sed finibus vestibulum massa at porttitor. Vestibulum in commodo ex, eu dictum diam. Aenean congue sem nec hendrerit faucibus.

Etiam viverra nulla sed massa accumsan facilisis. Vivamus fermentum luctus nulla eu tempor. Sed sit amet velit in purus egestas elementum nec gravida sapien. Nullam elementum porttitor nisi vitae posuere. Donec quis nulla at elit consequat gravida. Nulla ac tristique augue, nec molestie quam. Aenean sodales molestie metus, et vulputate sapien facilisis eu. Morbi posuere, orci ac pellentesque vestibulum, eros libero porttitor dolor, sed aliquam tortor neque id purus. Vestibulum non porttitor orci. Maecenas aliquet, nulla sed laoreet tempor, urna augue aliquam augue, quis convallis tellus enim vel justo. Sed eu aliquam ligula, id feugiat leo. Phasellus id cursus sapien. Duis imperdiet, dui eu commodo ultrices, felis mauris malesuada lacus, a dictum nisl quam eget nulla. Vivamus tristique imperdiet purus ac pretium. In suscipit ac justo nec congue. Duis gravida elit pharetra ante posuere, sed eleifend mi mattis.

Vestibulum sit amet nunc in augue consequat lobortis at eu mauris. Nunc congue nisl lorem, vel hendrerit velit condimentum a. Nulla commodo nisl pulvinar elementum viverra. Integer sed ipsum sit amet est egestas porta. Quisque aliquet eu dolor nec mattis. Sed felis leo, imperdiet at efficitur in, volutpat vitae lacus. Nunc vulputate vulputate quam, id molestie neque laoreet in.

In dapibus fermentum lectus, a porta velit. Aenean nec mollis sapien. Vivamus a arcu vulputate risus pulvinar tincidunt. Fusce sed bibendum purus, sed consequat eros. Praesent accumsan nisl a sagittis vestibulum. Vivamus nisi ante, aliquet nec lacus sit amet, luctus maximus ipsum. Suspendisse scelerisque accumsan luctus. Sed eros risus, viverra in ligula non, varius condimentum lacus. Sed dictum pharetra ex, sed finibus ipsum bibendum et.

Nullam sodales cursus scelerisque. Etiam nibh est, lacinia rhoncus tristique a, pretium vitae quam. Praesent urna nisi, placerat nec viverra quis, pharetra vel sapien. In sed imperdiet lectus. Aliquam scelerisque massa eget augue sodales egestas. Suspendisse feugiat massa sed lacus rhoncus, sed accumsan sem eleifend. Sed sed semper lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.

Donec cursus ex a pretium venenatis. Praesent fringilla leo eu posuere sagittis. Suspendisse lacinia, leo a volutpat vehicula, mauris purus semper est, condimentum bibendum justo eros nec mauris. Aliquam erat volutpat. Aliquam vitae ultrices sapien, a aliquet sapien. Nunc id ligula sit amet nisi porta egestas. Proin lacinia congue mauris, in semper nunc pretium vitae. Nunc convallis dolor id neque vulputate, vitae eleifend dui tincidunt. Maecenas in viverra sapien. Maecenas egestas ex quis turpis ornare, eget auctor lacus condimentum. Vestibulum maximus tellus metus, nec laoreet nisl imperdiet eu. Duis nec finibus lacus, ut sagittis dui. Praesent accumsan, tellus in blandit mollis, sem metus dapibus magna, id imperdiet mauris nisi sed est. Phasellus sed mollis diam. Morbi sagittis arcu in mi ultrices, sit amet pretium sapien volutpat. Duis pellentesque urna quis urna tristique gravida.

</div>

function doScrolling(elementY) {
  
  let start;
  let startingY = window.pageYOffset || document.documentElement.scrollTop;
  let diff = elementY - startingY;
  let totalTime;
  
  window.requestAnimationFrame(function step(timestamp) {
    if (!start) {
      start = timestamp;
    }
    // Elapsed milliseconds since start of scrolling.
    let time = timestamp - start;
    if(time < 200) { 
      totalTime = diff/0.75; // what to do the first 200 ms
    } else {
      totalTime = diff/185; // this will break scroll height to larger chunks and remove the delay, in this example it will scroll all the height (1 chunk)
    }
    // Get percent of completion in range [0, 1].
    let percent = Math.min(time/totalTime, 1);
    console.info(parseInt(time),parseInt(diff * percent));
    window.scrollBy({
      top: diff * percent,
      behavior: "smooth"
    });

    let isScrollAtBottom = (window.innerHeight + window.pageYOffset) >= document.body.scrollHeight - 3;

    if (isScrollAtBottom) {
      return;
    }

    // Proceed with animation as long as we wanted it to.
    
    if (time < totalTime) {
      window.requestAnimationFrame(step);
    }
  })
}
const testStart = new Date().getTime();
window.addEventListener('scroll', () => {
  let now = new Date().getTime();
  let currentScrollOffset = window.pageYOffset || document.documentElement.scrollTop;
  console.log(now-testStart, currentScrollOffset);
});
doScrolling(document.body.scrollHeight);
<div>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec quis aliquam libero. Vestibulum eu neque non augue tristique fermentum. Ut vulputate molestie metus in maximus. Integer a condimentum nisl, a vulputate nisl. Fusce vitae nulla a diam hendrerit
  ornare ac et ante. Aenean ac tortor turpis. Proin facilisis convallis iaculis. Maecenas vestibulum mauris mi, sit amet gravida augue malesuada at. Ut efficitur magna nunc, ac consequat ipsum interdum nec. Etiam vel ante vitae odio ornare luctus. Curabitur
  nunc ipsum, porttitor id enim ut, pellentesque vestibulum lorem. Sed tincidunt turpis ac ex tempus finibus. Praesent eget imperdiet ex. Morbi hendrerit pretium libero sit amet mattis. Sed a purus nec sapien mollis venenatis et vitae sem. Curabitur quis
  congue massa, pellentesque malesuada enim. Quisque blandit quam posuere hendrerit venenatis. Vestibulum quis dictum felis. Aliquam non bibendum quam. Donec aliquam ex vel metus tristique tincidunt. Duis condimentum felis lacus. Integer gravida eu arcu
  sed placerat. Sed placerat, est nec luctus gravida, odio nisl vehicula risus, a aliquet massa sem eget leo. Nulla quis turpis ut lectus consequat tincidunt id sit amet lacus. Sed congue, massa fringilla venenatis iaculis, mi erat vulputate est, a vestibulum
  odio odio sit amet elit. Nulla suscipit rhoncus nisi, a lobortis arcu. Mauris malesuada placerat purus, eget molestie nisi. Nam luctus, odio a aliquam varius, ipsum ante malesuada augue, in congue metus eros id nibh. In varius justo et nunc maximus,
  vel blandit leo ullamcorper. Phasellus sit amet mi non dui consectetur porta sed vitae ex. Integer mauris diam, vulputate vel turpis ac, ornare auctor massa. In hac habitasse platea dictumst. Proin id justo erat. Integer pretium luctus quam id congue.
  Aenean blandit rhoncus accumsan. Nulla ut luctus quam, nec vehicula ligula. Proin finibus sit amet dolor sit amet fringilla. Donec sodales iaculis dolor, sit amet egestas nisi. Aliquam nec scelerisque dolor. Donec maximus nulla eu quam posuere, nec
  condimentum nisl tristique. Aliquam venenatis massa cursus, scelerisque risus vitae, mattis quam. Aliquam rhoncus quam quis erat ornare cursus. Vivamus et risus at risus pellentesque fermentum id ac eros. Phasellus vel molestie lacus, eget facilisis
  orci. Sed efficitur velit molestie nulla scelerisque elementum. Vestibulum luctus nibh justo, at venenatis purus tincidunt at. Pellentesque feugiat condimentum lorem, et accumsan odio. Nam sagittis lorem ut orci dictum fermentum. Integer non augue a
  sapien semper dictum sit amet ut orci. Aliquam a ultrices risus, non tincidunt enim. Aliquam neque metus, dapibus sed elit a, tempus pretium ante. Nullam non ex in leo tempus facilisis. Duis tempor, nibh at porta euismod, augue est auctor nisi, vitae
  ornare ante sem semper dolor. Duis hendrerit aliquet luctus. Sed aliquet sem massa, vitae sodales eros fringilla quis. Quisque non dictum mi, quis facilisis augue. Ut scelerisque laoreet tellus, sed elementum metus pulvinar at. Maecenas faucibus id
  lorem faucibus maximus. Praesent efficitur, diam quis accumsan posuere, nunc diam porta est, sit amet facilisis velit urna non urna. Vivamus aliquet justo lorem. In hac habitasse platea dictumst. Curabitur auctor ornare sapien, id scelerisque mi posuere
  in. Morbi nec nisi tortor. Nulla et nisl odio. Integer nec consequat enim. Integer dui diam, interdum bibendum velit at, accumsan fringilla libero. Suspendisse ac turpis et libero ullamcorper pretium. Etiam non mauris sapien. Nulla non massa turpis.
  Vestibulum accumsan metus risus, eget pretium nisi auctor in. Pellentesque imperdiet neque lacus, vitae dictum lorem iaculis sit amet. Donec at lacinia metus. Vivamus feugiat non quam non pulvinar. Sed eget eleifend dolor. Fusce suscipit, orci vitae
  vehicula sollicitudin, mi sem luctus lorem, tempor volutpat purus metus eget ipsum. Duis accumsan tellus non metus ultrices tempus. Etiam ut eros vitae purus pharetra interdum. Morbi a odio nibh. Proin gravida quam elit, at sollicitudin ipsum tristique
  et. In nec dolor pharetra, consequat dui ut, rutrum enim. Donec mollis felis consectetur turpis interdum, eu pellentesque nisi gravida. Vivamus mollis, sem vitae finibus pretium, nunc sapien pulvinar est, quis sodales ligula augue nec ipsum. Duis ut
  faucibus elit, tincidunt interdum sem. Fusce semper enim eget augue lacinia mattis. Aliquam venenatis pretium tellus. Fusce rutrum magna sed erat varius, sit amet luctus dui rutrum. Sed finibus vestibulum massa at porttitor. Vestibulum in commodo ex,
  eu dictum diam. Aenean congue sem nec hendrerit faucibus. Etiam viverra nulla sed massa accumsan facilisis. Vivamus fermentum luctus nulla eu tempor. Sed sit amet velit in purus egestas elementum nec gravida sapien. Nullam elementum porttitor nisi vitae
  posuere. Donec quis nulla at elit consequat gravida. Nulla ac tristique augue, nec molestie quam. Aenean sodales molestie metus, et vulputate sapien facilisis eu. Morbi posuere, orci ac pellentesque vestibulum, eros libero porttitor dolor, sed aliquam
  tortor neque id purus. Vestibulum non porttitor orci. Maecenas aliquet, nulla sed laoreet tempor, urna augue aliquam augue, quis convallis tellus enim vel justo. Sed eu aliquam ligula, id feugiat leo. Phasellus id cursus sapien. Duis imperdiet, dui
  eu commodo ultrices, felis mauris malesuada lacus, a dictum nisl quam eget nulla. Vivamus tristique imperdiet purus ac pretium. In suscipit ac justo nec congue. Duis gravida elit pharetra ante posuere, sed eleifend mi mattis. Vestibulum sit amet nunc
  in augue consequat lobortis at eu mauris. Nunc congue nisl lorem, vel hendrerit velit condimentum a. Nulla commodo nisl pulvinar elementum viverra. Integer sed ipsum sit amet est egestas porta. Quisque aliquet eu dolor nec mattis. Sed felis leo, imperdiet
  at efficitur in, volutpat vitae lacus. Nunc vulputate vulputate quam, id molestie neque laoreet in. In dapibus fermentum lectus, a porta velit. Aenean nec mollis sapien. Vivamus a arcu vulputate risus pulvinar tincidunt. Fusce sed bibendum purus, sed
  consequat eros. Praesent accumsan nisl a sagittis vestibulum. Vivamus nisi ante, aliquet nec lacus sit amet, luctus maximus ipsum. Suspendisse scelerisque accumsan luctus. Sed eros risus, viverra in ligula non, varius condimentum lacus. Sed dictum pharetra
  ex, sed finibus ipsum bibendum et. Nullam sodales cursus scelerisque. Etiam nibh est, lacinia rhoncus tristique a, pretium vitae quam. Praesent urna nisi, placerat nec viverra quis, pharetra vel sapien. In sed imperdiet lectus. Aliquam scelerisque massa
  eget augue sodales egestas. Suspendisse feugiat massa sed lacus rhoncus, sed accumsan sem eleifend. Sed sed semper lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec cursus ex a pretium venenatis.
  Praesent fringilla leo eu posuere sagittis. Suspendisse lacinia, leo a volutpat vehicula, mauris purus semper est, condimentum bibendum justo eros nec mauris.
</div>

const testStart = new Date().getTime();
window.scroll({
  top: document.body.scrollHeight,
  behavior: "smooth"
});
window.addEventListener('scroll', () => {
  let now = new Date().getTime();
  let currentScrollOffset = window.pageYOffset || document.documentElement.scrollTop;
  console.log(now-testStart, currentScrollOffset);
});
<div>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec quis aliquam libero. Vestibulum eu neque non augue tristique fermentum. Ut vulputate molestie metus in maximus. Integer a condimentum nisl, a vulputate nisl. Fusce vitae nulla a diam hendrerit
  ornare ac et ante. Aenean ac tortor turpis. Proin facilisis convallis iaculis. Maecenas vestibulum mauris mi, sit amet gravida augue malesuada at. Ut efficitur magna nunc, ac consequat ipsum interdum nec. Etiam vel ante vitae odio ornare luctus. Curabitur
  nunc ipsum, porttitor id enim ut, pellentesque vestibulum lorem. Sed tincidunt turpis ac ex tempus finibus. Praesent eget imperdiet ex. Morbi hendrerit pretium libero sit amet mattis. Sed a purus nec sapien mollis venenatis et vitae sem. Curabitur quis
  congue massa, pellentesque malesuada enim. Quisque blandit quam posuere hendrerit venenatis. Vestibulum quis dictum felis. Aliquam non bibendum quam. Donec aliquam ex vel metus tristique tincidunt. Duis condimentum felis lacus. Integer gravida eu arcu
  sed placerat. Sed placerat, est nec luctus gravida, odio nisl vehicula risus, a aliquet massa sem eget leo. Nulla quis turpis ut lectus consequat tincidunt id sit amet lacus. Sed congue, massa fringilla venenatis iaculis, mi erat vulputate est, a vestibulum
  odio odio sit amet elit. Nulla suscipit rhoncus nisi, a lobortis arcu. Mauris malesuada placerat purus, eget molestie nisi. Nam luctus, odio a aliquam varius, ipsum ante malesuada augue, in congue metus eros id nibh. In varius justo et nunc maximus,
  vel blandit leo ullamcorper. Phasellus sit amet mi non dui consectetur porta sed vitae ex. Integer mauris diam, vulputate vel turpis ac, ornare auctor massa. In hac habitasse platea dictumst. Proin id justo erat. Integer pretium luctus quam id congue.
  Aenean blandit rhoncus accumsan. Nulla ut luctus quam, nec vehicula ligula. Proin finibus sit amet dolor sit amet fringilla. Donec sodales iaculis dolor, sit amet egestas nisi. Aliquam nec scelerisque dolor. Donec maximus nulla eu quam posuere, nec
  condimentum nisl tristique. Aliquam venenatis massa cursus, scelerisque risus vitae, mattis quam. Aliquam rhoncus quam quis erat ornare cursus. Vivamus et risus at risus pellentesque fermentum id ac eros. Phasellus vel molestie lacus, eget facilisis
  orci. Sed efficitur velit molestie nulla scelerisque elementum. Vestibulum luctus nibh justo, at venenatis purus tincidunt at. Pellentesque feugiat condimentum lorem, et accumsan odio. Nam sagittis lorem ut orci dictum fermentum. Integer non augue a
  sapien semper dictum sit amet ut orci. Aliquam a ultrices risus, non tincidunt enim. Aliquam neque metus, dapibus sed elit a, tempus pretium ante. Nullam non ex in leo tempus facilisis. Duis tempor, nibh at porta euismod, augue est auctor nisi, vitae
  ornare ante sem semper dolor. Duis hendrerit aliquet luctus. Sed aliquet sem massa, vitae sodales eros fringilla quis. Quisque non dictum mi, quis facilisis augue. Ut scelerisque laoreet tellus, sed elementum metus pulvinar at. Maecenas faucibus id
  lorem faucibus maximus. Praesent efficitur, diam quis accumsan posuere, nunc diam porta est, sit amet facilisis velit urna non urna. Vivamus aliquet justo lorem. In hac habitasse platea dictumst. Curabitur auctor ornare sapien, id scelerisque mi posuere
  in. Morbi nec nisi tortor. Nulla et nisl odio. Integer nec consequat enim. Integer dui diam, interdum bibendum velit at, accumsan fringilla libero. Suspendisse ac turpis et libero ullamcorper pretium. Etiam non mauris sapien. Nulla non massa turpis.
  Vestibulum accumsan metus risus, eget pretium nisi auctor in. Pellentesque imperdiet neque lacus, vitae dictum lorem iaculis sit amet. Donec at lacinia metus. Vivamus feugiat non quam non pulvinar. Sed eget eleifend dolor. Fusce suscipit, orci vitae
  vehicula sollicitudin, mi sem luctus lorem, tempor volutpat purus metus eget ipsum. Duis accumsan tellus non metus ultrices tempus. Etiam ut eros vitae purus pharetra interdum. Morbi a odio nibh. Proin gravida quam elit, at sollicitudin ipsum tristique
  et. In nec dolor pharetra, consequat dui ut, rutrum enim. Donec mollis felis consectetur turpis interdum, eu pellentesque nisi gravida. Vivamus mollis, sem vitae finibus pretium, nunc sapien pulvinar est, quis sodales ligula augue nec ipsum. Duis ut
  faucibus elit, tincidunt interdum sem. Fusce semper enim eget augue lacinia mattis. Aliquam venenatis pretium tellus. Fusce rutrum magna sed erat varius, sit amet luctus dui rutrum. Sed finibus vestibulum massa at porttitor. Vestibulum in commodo ex,
  eu dictum diam. Aenean congue sem nec hendrerit faucibus. Etiam viverra nulla sed massa accumsan facilisis. Vivamus fermentum luctus nulla eu tempor. Sed sit amet velit in purus egestas elementum nec gravida sapien. Nullam elementum porttitor nisi vitae
  posuere. Donec quis nulla at elit consequat gravida. Nulla ac tristique augue, nec molestie quam. Aenean sodales molestie metus, et vulputate sapien facilisis eu. Morbi posuere, orci ac pellentesque vestibulum, eros libero porttitor dolor, sed aliquam
  tortor neque id purus. Vestibulum non porttitor orci. Maecenas aliquet, nulla sed laoreet tempor, urna augue aliquam augue, quis convallis tellus enim vel justo. Sed eu aliquam ligula, id feugiat leo. Phasellus id cursus sapien. Duis imperdiet, dui
  eu commodo ultrices, felis mauris malesuada lacus, a dictum nisl quam eget nulla. Vivamus tristique imperdiet purus ac pretium. In suscipit ac justo nec congue. Duis gravida elit pharetra ante posuere, sed eleifend mi mattis. Vestibulum sit amet nunc
  in augue consequat lobortis at eu mauris. Nunc congue nisl lorem, vel hendrerit velit condimentum a. Nulla commodo nisl pulvinar elementum viverra. Integer sed ipsum sit amet est egestas porta. Quisque aliquet eu dolor nec mattis. Sed felis leo, imperdiet
  at efficitur in, volutpat vitae lacus. Nunc vulputate vulputate quam, id molestie neque laoreet in. In dapibus fermentum lectus, a porta velit. Aenean nec mollis sapien. Vivamus a arcu vulputate risus pulvinar tincidunt. Fusce sed bibendum purus, sed
  consequat eros. Praesent accumsan nisl a sagittis vestibulum. Vivamus nisi ante, aliquet nec lacus sit amet, luctus maximus ipsum. Suspendisse scelerisque accumsan luctus. Sed eros risus, viverra in ligula non, varius condimentum lacus. Sed dictum pharetra
  ex, sed finibus ipsum bibendum et. Nullam sodales cursus scelerisque. Etiam nibh est, lacinia rhoncus tristique a, pretium vitae quam. Praesent urna nisi, placerat nec viverra quis, pharetra vel sapien. In sed imperdiet lectus. Aliquam scelerisque massa
  eget augue sodales egestas. Suspendisse feugiat massa sed lacus rhoncus, sed accumsan sem eleifend. Sed sed semper lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec cursus ex a pretium venenatis.
  Praesent fringilla leo eu posuere sagittis. Suspendisse lacinia, leo a volutpat vehicula, mauris purus semper est, condimentum bibendum justo eros nec mauris. Aliquam erat volutpat. Aliquam vitae ultrices sapien, a aliquet sapien. Nunc id ligula sit
  amet nisi porta egestas. Proin lacinia congue mauris, in semper nunc pretium vitae. Nunc convallis dolor id neque vulputate, vitae eleifend dui tincidunt. Maecenas in viverra sapien. Maecenas egestas ex quis turpis ornare, eget auctor lacus condimentum.
  Vestibulum maximus tellus metus, nec laoreet nisl imperdiet eu. Duis nec finibus lacus, ut sagittis dui. Praesent accumsan, tellus in blandit mollis, sem metus dapibus magna, id imperdiet mauris nisi sed est. Phasellus sed mollis diam. Morbi sagittis
  arcu in mi ultrices, sit amet pretium sapien volutpat. Duis pellentesque urna quis urna tristique gravida. Duis ut finibus elit, sed suscipit nibh. Proin tristique, velit ut mattis blandit, tortor nisl rhoncus enim, id scelerisque enim lacus et ante.
</div>
  • 1
    Safari doesn't support behavior: "smooth", that's the very reason of this question to begin with. – Kaiido Oct 03 '20 at 05:18
  • @Kaiido the 1st snippet works with `auto` now. Not that `smooth` as the actual scroll but somehow similar, perhaps a bit quicker. I think this small function could provide some solution up to a point. –  Oct 03 '20 at 08:32
0

function myFunction() {

  var inputCount = $(".demo").children("input").length;
  var idInput = inputCount + 1
  $(".demo").append( "<input id="+idInput+" type='text'>");
  var inputLast = $('.demo').children().last().attr('id');
  
    $('html, body').animate({
        scrollTop: $("#" + inputLast).offset().top
    }, 500);
  
  
}
.demo input {
width: 100%;
margin: 0 0 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>



<button onclick="myFunction()">Click me</button>

<p class="demo"><input id="1" type="text"></p>
Ishita Ray
  • 654
  • 8