3

I tried not to reinvent the wheel by writing my own scolling script, but everything I found used jQuery (I don't want to mess my code with it), wasn't working, didn't support key scrolling or div scrolling... nothing was good enough.

I run on Windows 7: Opera and Chrome doesn't scroll smooth, so I wrote code that gives smooth scrolling experience. However in Explorer 11, which has smooth scrolling by default, my script made it hypersensitive. My friend running Chrome on Mac OS told me the scrolling there is also smooth.

I guess my question can be answered either by list of browser x OS which need javascript scrolling enhancement (I don't have access to everything), or by improving my code to avoid ugly behavior under browsers that do not need enhancement.

Required features are

  • no jQuery
  • smooth up/down key scrolling
  • scrolling divs, not only main window
  • no jQuery (this is important to me, so I mentioned it twice)
  • no MooTools, no frameworks, native JS only (perharps Modernizr or other lean tools are acceptable)

Any advice regarding the code is appreciated, too (I know I should use requestAnimationFrame, soon)

For time being, my code is

// easeOutQuad by Robert Penner
Math.easeOut = 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
  keyDelta = 0;
function KeyWheelHandler(e) {
  if(e.which!=38 && e.which!=40) return;
  keyDelta = e.which==38 ? -1 : 1;
  mult = 4;
  MouseWheelHandler(e);
}
function MouseWheelHandler(e) {
  e.preventDefault(); // prevent default browser scroll
  clearInterval(interval); // cancel previous animation
  ++mult; // we are going to scroll faster
  var delta = keyDelta || -Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
  if(dir!=delta) { // scroll direction changed
    if(!keyDelta) mult = 1; // start slowly
    dir = delta;
  }
  // get the closest scrollable parent
  for(var tgt=e.target; tgt!=document.documentElement; tgt=tgt.parentNode) {
    var oldScroll = tgt.scrollTop;
    tgt.scrollTop+= delta;
    if(oldScroll!=tgt.scrollTop) break;
  }
  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 = 2; // current step, not less than 2, see the (t-2) in EaseOut
  interval = setInterval(function() {
    var pos = Math.easeOut(step++,start,change,steps);
    tgt.scrollTop = pos;
    if(step>=steps) { // scroll finished without speed up - stop
      mult = keyDelta = 0;
      clearInterval(interval);
    }
  },15);
}
if(window.chrome) { // Opera and Chrome
  window.addEventListener("mousewheel", MouseWheelHandler);
  //window.addEventListener("DOMMouseScroll", MouseWheelHandler); // FF
  document.documentElement.addEventListener("keydown", KeyWheelHandler);
}
})();
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169
  • I'd use the `wheel` event as the default, it's the modern cross browser version. Looks like you're not passing the event in the listeners by the way so the part of the functions that uses that won't work. – Shikkediel Dec 07 '15 at 22:44
  • Not passing the event? Could you please mention where exactly? – Jan Turoň Dec 08 '15 at 07:01
  • `window.addEventListener("mousewheel", MouseWheelHandler);` – Shikkediel Dec 08 '15 at 13:16
  • The `MouseWheelHandler` function itself takes `e` as an argument, like with the others... – Shikkediel Dec 08 '15 at 13:16
  • Of course, the `e` is passed with the system call (except for old Explorers). If I miss something, please answer it with comments in the code. If you have some better solution, you might want to answer [here](http://stackoverflow.com/q/14926366/343721), preferably with the link to authoritative reference. – Jan Turoň Dec 08 '15 at 18:13

1 Answers1

0

Looks like in the future (as of 2015) css smooth-scroll will solve this:

The scrolling box is scrolled in a smooth fashion using a user-agent-defined timing function over a user-agent-defined period of time. User agents should follow platform convensions, if any.

User agents may ignore this property. (???)

The note about ignoring might be the reason why browsers mostly ignore this, but Chrome work's on it, so I expect Opera to implement it later, too.

IE, FF and Safari in the latest version seem to be scrolling smoothly by default everywhere, so this problem can be solved by waiting.

Community
  • 1
  • 1
Jan Turoň
  • 31,451
  • 23
  • 125
  • 169