Пересмотрено по состоянию на август 2018 г. - теперь более элегантно, с ускорением и замедлением.
Протестировано в Mozilla и Safari сейчас.
Я разработал этот сценарий, используя объект «requestAnimFrame (callback)» для плавной прокрутки без библиотеки, он отлично работает с Safari, но не с Firefox, не могу понять почему.
Обратный вызов вызывается косвенно - функцией-оберткой для передачи дополнительных аргументов (помимо метки времени).
/*
* smoothScroll to a supplied target using "requestAnimationFrame"
*/
var starttime, // start of animation
runtime, // animation duration
distance, // distance of the target in reference to the viewport top
docpos, // distance document top to viewport top
delta, // distance left to scroll till target reached
step, // travelled distance
correct=10, // correct y destination position
t=900, // absolute duration
v,
a=0.001;
//wrapper function, necessary for passing arguments with requestAnimationFrame to the real callback function -> smoothScroll
function wrapsmoothScrl(callback, id, target){
return function(timestamp){
callback(id, target, timestamp);
};
}
function smoothScroll(id, target, timestamp){
$(id).addEventListener("click", function(event){event.preventDefault();});
if (!starttime) starttime=timestamp;
if (!distance) distance=$(target).getBoundingClientRect().top;
if (!docpos) docpos=window.pageYOffset;
v=Math.abs(distance)/t;
runtime=timestamp-starttime;
step=runtime<(t/2)?(v+a*runtime)*runtime:((v+a*t/2)-a*(runtime-t/2))*runtime;
step=distance>0?step:step*(-1);
document.documentElement.scrollTop=docpos+step; // for mozilla
document.body.scrollTop=docpos+step; // for safari (and others?)
delta=$(target).getBoundingClientRect().top;
if (distance>0 && delta>correct || distance<0 && delta<correct){
var animReq1=window.requestAnimationFrame(wrapsmoothScrl(smoothScroll, id, target));
} else {window.cancelAnimationFrame(animReq1); starttime=null; distance=null; docpos=null;}
}