scrollTop animation without jquery [duplicate]
Asked Answered
B

1

100

I'm trying to make an animated "scroll to top" effect without using jQuery.

In jQuery, I usually use this code:

$('#go-to-top').click(function(){ 
      $('html,body').animate({ scrollTop: 0 }, 400);
      return false; 
});

How do I animate scrollTop without using jQuery?

Beckiebeckley answered 31/1, 2014 at 7:30 Comment(7)
named anchor would do this for you btw, other than javascript.Electromyography
anchor doesn't animate the scrollBeckiebeckley
And what did you try? And by the way, do you really have multiple go-to-top elements (an ID is unique)?Havana
Elegant approach https://mcmap.net/q/41253/-how-to-scroll-to-top-of-page-with-javascript-jquerySalpingitis
Sounds like a job for CSS3 to me.Flare
@jfriend00: Since scrollTop is not a CSS property, I don’t see how you would animate it with CSS.Phosphate
An idea with CSS: #17631917 and an example with plain JS: itnewb.com/tutorial/….Flare
H
188

HTML:

<button onclick="scrollToTop(1000);"></button>

1# JavaScript (linear):

function scrollToTop (duration) {
    // cancel if already on top
    if (document.scrollingElement.scrollTop === 0) return;

    const totalScrollDistance = document.scrollingElement.scrollTop;
    let scrollY = totalScrollDistance, oldTimestamp = null;

    function step (newTimestamp) {
        if (oldTimestamp !== null) {
            // if duration is 0 scrollY will be -Infinity
            scrollY -= totalScrollDistance * (newTimestamp - oldTimestamp) / duration;
            if (scrollY <= 0) return document.scrollingElement.scrollTop = 0;
            document.scrollingElement.scrollTop = scrollY;
        }
        oldTimestamp = newTimestamp;
        window.requestAnimationFrame(step);
    }
    window.requestAnimationFrame(step);
}

2# JavaScript (ease in and out):

function scrollToTop (duration) {
    // cancel if already on top
    if (document.scrollingElement.scrollTop === 0) return;

    const cosParameter = document.scrollingElement.scrollTop / 2;
    let scrollCount = 0, oldTimestamp = null;

    function step (newTimestamp) {
        if (oldTimestamp !== null) {
            // if duration is 0 scrollCount will be Infinity
            scrollCount += Math.PI * (newTimestamp - oldTimestamp) / duration;
            if (scrollCount >= Math.PI) return document.scrollingElement.scrollTop = 0;
            document.scrollingElement.scrollTop = cosParameter + cosParameter * Math.cos(scrollCount);
        }
        oldTimestamp = newTimestamp;
        window.requestAnimationFrame(step);
    }
    window.requestAnimationFrame(step);
}
/* 
  Explanation:
  - pi is the length/end point of the cosinus intervall (see below)
  - newTimestamp indicates the current time when callbacks queued by requestAnimationFrame begin to fire.
    (for more information see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)
  - newTimestamp - oldTimestamp equals the delta time

    a * cos (bx + c) + d                        | c translates along the x axis = 0
  = a * cos (bx) + d                            | d translates along the y axis = 1 -> only positive y values
  = a * cos (bx) + 1                            | a stretches along the y axis = cosParameter = window.scrollY / 2
  = cosParameter + cosParameter * (cos bx)  | b stretches along the x axis = scrollCount = Math.PI / (scrollDuration / (newTimestamp - oldTimestamp))
  = cosParameter + cosParameter * (cos scrollCount * x)
*/

Note:

  • Duration in milliseconds (1000ms = 1s)
  • Second script uses the cos function. Example curve:

enter image description here

3# Simple scrolling library on Github

Helenahelene answered 3/7, 2014 at 17:8 Comment(9)
Keep in mind that const is not part of EcmaScript 5, but 6 with different semantics. Currently only Firefox and Chrome support it somehow. Read more here: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Nobukonoby
Yes true, good object. So using var might be the better option untill all browsers are supporting const.Helenahelene
Can I see a JSFIDDLE of this in action? I can't seem to get it to work . . .Poling
Thanks for this! I extended it a bit to allow scrolling to a specific element and a polyfill for browsers without performance.now() ... gist.github.com/joshcanhelp/a3a669df80898d4097a1e2c01dea52c1Watchdog
This is awesome @Helenahelene I created a simple scroll-element module based on the linear function above. github.com/StevenIseki/scroll-elementErwinery
I created a small library for that. Provides a few more things like callbacks and the ability to stop the animation as well as using different easing effects. And of course, keeping it small!Eduino
This is not working in IE11. I don't like IE, but still there are 2% o 3% of people using it. How can I fix it?Orosco
Ok, I've found a fix for this: use pageYOffset instead of scrollY, and it will work even in IE.Orosco
This is brilliant, but has one bug. Sometimes the cosine's product does not equal exactly 0, resulting in multiple iterations of the scroll's round trip. Solution, along with a mod to support all elements is here: linkLoewe

© 2022 - 2024 — McMap. All rights reserved.