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);
}
})();