Enable smooth scrolling for my website in all browsers
Asked Answered
P

6

31

I'm developing a parallax scrolling website using the Stellar and Skrollr libraries. The website behaves perfectly in Firefox because of Firefox's smooth scrolling feature, but in Chrome, scrolling with the mouse wheel is jerky, and the parallax effect is almost ruined. Is there any way to get the smooth scrolling with the mouse wheel in all browsers while maintaining performance?

Paly answered 13/10, 2013 at 19:20 Comment(2)
Could you post a demo of your code? The plugins' own sites appear to animate their scrolling smoothly, the issue is likely with your implementation of their code. We can't help without seeing that.Convulsive
Please don't do this, any time I see this on a site I close out. Laggy in Chrome on a gaming PC on any site I've seen it on.Glottal
V
43

I found two jQuery plugins that may do what you want.

Simplr-SmoothScroll // Source: SE Question

jQuery SmoothWheel


edit: Struck out SmoothWheel because of comments - it hasn't been updated in ages, and SmoothScroll seems well maintained.

Vanderbilt answered 30/10, 2013 at 14:47 Comment(2)
Simplr-SmoothScroll is very good but when you use track-pad of mac or any laptop it behaves abruptly and will scroll whole window with a single swipe.Behnken
There is a big problem of Simplr-SmoothScroll When you use track-pad so please check that issue before using.Abandoned
C
12

If you are Cargo cult programmer, go with jQuery. Proceed only if you are Real programmer.

Screw jQuery.animate(), understand the math behind and pick an algorithm. Robert Penner has a nice demo, I picked EaseOutQuad.

Read how to handle mouse wheel cross-browser style here, then do some more reading.

In this code, I choose not to support IE 8 and older. The idea is to hook up the wheel event, prevent it (since the default behavior is jerky jump) and perform own smooth jump

Math.easeOutQuad = function (t, b, c, d) { t /= d; return -c * t*(t-2) + b; };

(function() { // do not mess global space
var
  interval, // scroll is being eased
  mult = 0, // how fast do we scroll
  dir = 0, // 1 = scroll down, -1 = scroll up
  steps = 50, // how many steps in animation
  length = 30; // how long to animate
function MouseWheelHandler(e) {
  e.preventDefault(); // prevent default browser scroll
  clearInterval(interval); // cancel previous animation
  ++mult; // we are going to scroll faster
  var delta = -Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); // cross-browser
  if(dir!=delta) { // scroll direction changed
    mult = 1; // start slowly
    dir = delta;
  }
  // in this cycle, we determine which element to scroll
  for(var tgt=e.target; tgt!=document.documentElement; tgt=tgt.parentNode) {
    var oldScroll = tgt.scrollTop;
    tgt.scrollTop+= delta;
    if(oldScroll!=tgt.scrollTop) break;
    // else the element can't be scrolled, try its parent in next iteration
  }
  var start = tgt.scrollTop;
  var end = start + length*mult*delta; // where to end the scroll
  var change = end - start; // base change in one step
  var step = 0; // current step
  interval = setInterval(function() {
    var pos = Math.easeOutQuad(step++,start,change,steps); // calculate next step
    tgt.scrollTop = pos; // scroll the target to next step
    if(step>=steps) { // scroll finished without speed up - stop animation
      mult = 0; // next scroll will start slowly
      clearInterval(interval);
    }
  },10);
}

// nonstandard: Chrome, IE, Opera, Safari
window.addEventListener("mousewheel", MouseWheelHandler, false); 
// nonstandard: Firefox
window.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
})();

As you can see in this demo, I prefer as little easing as possible, just to avoid jerky scrolling. Read the comments above and design your own scrolling which suits your project.

Note: mousewheel also hooks to touchpad, but not to up/down keys. You should consider to hook key events, too.

Cental answered 5/12, 2015 at 20:16 Comment(5)
This is awesome code with explanation! How would I add smooth scrolling when the user scroll with the actual scroll bar? (I.e. not with the mouse wheel, but actually clicks and drags the scroll bar)Taxeme
Also, say the user scrolled all the way to the top (or bottom). How can you automatically scroll a bit farther down, then bounce back? Sort of like elastic scrollingTaxeme
@Taxeme then I suggest to pick the out back cubic algorithm from here, just make sure to leave enough empty space at the bottom of the page. In the future I believe every browser will support a nice scroll feel, so this script will become obsolete. See the Chrome announcement. Tough luck with scrollbar scrolling :-/ It's a browser feature, there is no "onscrollbarscroll" event.Newsmonger
@JanTuroň Thanks! Hopefully the browsers will implement that! Anyway, I tried it out, jsfiddle.net/jgeqda91 and it bounces at every scroll, and doesn't bounce at the top and bottom. I only want it to bounce when it hits all the way to the top or bottom. How can I implement that? (Or should I just ask a new question?)Taxeme
@Taxeme I guess you need to add a condition if the end position is at (or very close) top or bottom excluding the padding left for bounce, the use out back cubic, else use only out cubic. Would you try?Newsmonger
V
3

I had not a lot of time, but I tried to write a (cross browser & dirty) smooth scrolling functionality on the fly. When you stop scrolling it smoothly decelerates. You can rewrite it a little bit so it fits your needs.

Give it a try here:

Smooth scrolling:

function getScrollTop(){
    if(typeof pageYOffset!= 'undefined'){
        //most browsers except IE before #9
        return pageYOffset;
    } else {
        var B = document.body; //IE 'quirks'
        var D = document.documentElement; //IE with doctype
        D = (D.clientHeight) ? D : B;
        return D.scrollTop;
    }
}

var timeouts = [];
var scrolling = false;
var scroller;
var scrollTop = getScrollTop();
var timeMs;
var alter = false;
var speed = 5;
window.onscroll = function() {
    if(alter) {
        var timeDif = new Date().getMilliseconds() - timeMs;
        speed = 5 - (timeDif / 50);
        console.log(speed);
    }
    timeMs = new Date().getMilliseconds();
    alter = !alter;
    var scrollDirection = getScrollTop() - scrollTop;
    scrollDirection = scrollDirection / Math.abs(scrollDirection);
    scrollTop = getScrollTop();
    clearTimeout(scroller);
    scroller = setTimeout(function(){
        console.log('smooth scrolling active');
        if(!scrolling) {
            timeouts.length = 0;
            scrolling = true;
            var steps = 50;
            var delay = 6;
            for(var i = 0; i < steps; i++) {
                (function(i){
                    var timeout = setTimeout(function(){
                        var perc = i / steps; 
                        var val = (perc == 1) ? 1 : (-Math.pow(2, -10 * perc) + 1); 
                        var scrollY = val * speed * scrollDirection;
                        window.scrollTo(0, getScrollTop() + scrollY);
                        setTimeout(function(){
                            if(i == (steps - 1)) scrolling = false;
                        }, steps * delay);
                    }, (i * delay));
                    timeouts.push(timeout);
                })(i);
            }
        }
    }, 50);
};

http://jsfiddle.net/ubawR/4/

Vladi answered 31/10, 2013 at 10:42 Comment(0)
D
1

for chrome only try this - https://github.com/im4aLL/chromeSmoothScroll only 1 KB

Demarcation answered 27/3, 2014 at 17:21 Comment(1)
I found this script best of them all for my parallax site. Benefits include: browser specific(I only targeted Chrome), keyboard functionality built in, and no additional libraries needed (Simplr-SmoothScroll required JQuery mousewheel). I did find that adjusting the speed to 200 from default 800 gave the closest to FireFox effect. Also noticed that the speed of mouse wheel scrolling was accounted for. Big spin gave big scroll. Other scripts specified scroll distance no matter what the mouse wheel action was (large or short scroll).Lani
M
1

Simplr-SmoothScroll have one bug - it is not working with body, when body height is not auto.

I found another plugin and it is became perfect solution for me. https://github.com/inuyaksa/jquery.nicescroll

download library (demo) and add to the begining

// 1. Simple mode, it styles document scrollbar:
$(document).ready(function() {  
    $("body").niceScroll();
});
Moreau answered 3/6, 2016 at 10:51 Comment(1)
thanks!we use this plugin as well due to trackpad issue, working fine on our side too.Psychotherapy
D
0

Basically scroll causes jerky because of repaints and reflows. if you can check and reduce those reflows you might get the scroll performance.

and check the onScroll event callback function whether its executing any expensive logic . and are there any memory leakage.

Chrome developer tool bar heap snap shot will be useful for detecting memory leaks and to see repaints and reflows.

Dart answered 28/10, 2013 at 6:13 Comment(2)
I know that can cause jerky scrolling, but what I'm looking for is a way to smooth scrolling with the mouse wheel in general. For example, on a simple text page, scrolling one turn goes about 3 lines down by default, all in one jump. I want it to go the same distance but smoothly.Paly
yeah I got it now, I have added a sample code here in js fiddle. which works fine for chrome. if you don't have any problem with firefox you an remove that related if condition. [link] (jsfiddle.net/Y6xZM/1) and you can use MOUSE_WHEEL_GAIN to increase scroll amount.Dart

© 2022 - 2024 — McMap. All rights reserved.