Usage
First add this to your page.
scrollByAnimated = function(scrollY, duration){
var startTime = new Date().getTime();
var startY = window.scrollY;
var endY = startY + scrollY;
var currentY = startY;
var directionY = scrollY > 0 ? 'down' : 'up';
var animationComplete;
var count = 0;
var animationId;
if(duration === undefined){
duration = 250;//ms
}
//grab scroll events from the browser
var mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel" //FF doesn't recognize mousewheel as of FF3.x
//stop the current animation if its still going on an input from the user
var cancelAnimation = function () {
if(animationId!==undefined){
window.cancelAnimationFrame(animationId)
animationId=undefined;
}
}
if (document.attachEvent) {
//if IE (and Opera depending on user setting)
document.attachEvent("on"+mousewheelevt, cancelAnimation)
} else if (document.addEventListener) {
//WC3 browsers
document.addEventListener(mousewheelevt, cancelAnimation, false)
}
var step = function (a,b,c) {
var now = new Date().getTime();
var completeness = (now - startTime) / duration;
window.scrollTo(0, Math.round(startY + completeness * scrollY));
currentY = window.scrollY;
if(directionY === 'up') {
if (currentY === 0){
animationComplete = true;
}else{
animationComplete = currentY<=endY;
}
}
if(directionY === 'down') {
/*limitY is cross browser, we want the largest of these values*/
var limitY = Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight );
if(currentY + window.innerHeight === limitY){
animationComplete = true;
}else{
animationComplete = currentY>=endY;
}
}
if(animationComplete===true){
/*Stop animation*/
return;
}else{
/*repeat animation*/
if(count > 500){
return;
}else{
count++;
animationId = window.requestAnimationFrame(step);
}
}
};
/*start animation*/
step();
};
Then use it;
scrollByAnimated(100, 250);// change in scroll Y, duration in ms
Explanation
Here's a more robust version than your original code suggested you needed. Additional features include stop scrolling at the top and bottom of the page, uses requestAnimationFrame()
.
It also only supports scrolling up and down because thats all I need at this time. You'd be a cool, cool person if you added left and right to it.
It has only been tested in Chrome, so your milage may vary.
This code leverages requestAnimationFrame()
. First scrollByAnimated()
sets variables, then runs step()
which loops until the duration has been reached.
At each frame it calculates the animation's completeness
as a number from 0 to 1. This is the difference between the startTime
and now
, divided by duration
.
This completeness
value is then multiplied by the requested scrollY
. This gives us our amount to scroll for each frame. Then we add the startY
position to achieve a value that we can use window.scrollTo()
to set the frame's position, rather than increment the current position.