Smooth scrolling in javascript?

2019-02-26 10:01发布

问题:

In jQuery you can do things like

$('html, body').stop().animate({
    'scrollTop': $target.offset().top
}, 1000);

And I'm interested how to handle this in Javascript only?

Thanks!

回答1:

This question is usually answered with a function utilizing setInterval / setTimeout and scrolling the element in tiny increments, see: Cross browser JavaScript (not jQuery...) scroll to top animation

I'd like to propose another, more modern way of doing it using dynamically added CSS transition, which should be smoother and less CPU-hungry. It animates the body using CSS, JavaScript only calculates and sets translateY() transform on the element. After the CSS animation finishes the transform is removed and scroll position is set.

Demo: http://jsfiddle.net/00uw1Lq9/4/ (updated link after cross-browser fixes).

Works only in browsers with unprefixed transitions and transforms (tested in IE11, current Chrome and Firefox), for older versions you may need to add prefix detection. It's also probably broken in some ways, treat it as a starting point, not a solution.

// this function self-initializes and attaches an event listener to the root element
var smoothScroll = (function(root){
     //keep track of the target element between scrolling function and transitionend callback
     var targetElement;
    // called when the CSS transition finishes
    root.addEventListener('transitionend', function(e){
        // remove transition and transform
        root.style['transition'] = '';
        root.style['transform'] = '';
        // do the actual scrolling
        targetElement.scrollIntoView();
    });
    // this function fill be available as the smoothScroll function
    return function(element, time){
        // get the top position of target element
        var offset = element.offsetTop - root.scrollTop;
        // if the element is very low it can't get scrolled up to the top of the window
        offset = Math.min( offset, root.offsetHeight - document.documentElement.clientHeight );
        // save reference to the target element for callback
        targetElement = element;
        // set transfor/transition CSS properties
        root.style['transition'] = 'transform';
        root.style['transition-duration'] = time;
        // this fakes the scrolling animation by animating transform on the element
        root.style['transform'] = 'translateY(' + offset * -1 +'px)';
    }
}(document.body));

Usage: smothScroll( DOMNodeReference, time ), where time is a string valid for CSS transition-duration property (for example '300ms' or '2.5s').