I am trying to make a function which everytime a user scrolls "into" some container div, the web smoothly scrolls to that div (I don't know if I am being clear, you can undertand it better looking at my JSFiddle)
It works fine when the user scrolls slowly or using arrow keys, but if the user makes an abrupt scroll then the animated scrolling is not smooth at all. It also sometimes makes a jump on the opposite direction in the middle of the animation.
I am uncertain if this is a cause of momentum scrolling or the increase in scroll speed when user spins the scrollwheel very fast. Or maybe some other reason I didn't think of.
Here is the minimal code to reproduce the bug (same as in JSFiddle)
HTML:
<body>
<div style="background-color:red;" class="autoscroll">
<p style="line-height:3;color:white;">
Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem
</p>
</div>
<div style="background-color:blue;" class="autoscroll">
<p style="line-height:3;color:white;">
Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>
</p>
</div>
<div style="background-color:green;" class="autoscroll">
<p style="line-height:3;color:white;">
Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem
</p>
</div>
<div style="background-color:brown;" class="autoscroll">
<p style="line-height:3;color:white;">
Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>Ipsum Lorem<br><br>
</p>
</div>
</body>
CSS:
.autoscroll{
min-height:100%;
}
html, body, p{
margin:0;
padding:0;
}
JS:
$(function() {
var scrollFlag = true;
window.setTimeout(function(){
$(window).on('wheel keydown scroll',function(event){
var validate_scroll = false;
var scroll_direction = '';
if(event.type=="wheel"){
if(event.originalEvent.deltaY < 0){
scroll_direction = 'up';
validate_scroll = true;
}
if(event.originalEvent.deltaY > 0){
scroll_direction = 'down';
validate_scroll = true;
}
}else{ //keydown
if(event.which == 38){ //UP
scroll_direction = 'up';
validate_scroll = true;
}
if(event.which == 40){ //DOWN
scroll_direction = 'down';
validate_scroll = true;
}
}
if(validate_scroll && scrollFlag){
var windowHeight = $(window).height();
var st = $(window).scrollTop();
var st2 = windowHeight + st;
if (scroll_direction == 'down'){
//downscroll
$('.autoscroll').each(function(){
var ost = $(this).offset().top;
if (ost < st2 && st < ost && scrollFlag){
console.log('smooth scrolling down');
disableScroll();
scrollFlag = false;
$('window,html,body').stop(true);
$('html,body').animate({
scrollTop: ost
}, 1200, "linear", function(){
enableScroll();
scrollFlag = true;
});
}
});
}else if (scroll_direction == 'up'){
//upscroll
$('.autoscroll').each(function(){
var ost = $(this).offset().top;
var ost2 = ost + $(this).outerHeight(true);
if (ost2 < st2 && st < ost2 && scrollFlag){
console.log('smooth scrolling up');
disableScroll();
scrollFlag = false;
$('window,html,body').stop(true);
$('html,body').animate({
scrollTop: ost2 - windowHeight
}, 1200, "linear", function(){
enableScroll();
scrollFlag = true;
});
}
});
}
}//if validate_scroll && scrollFlag
});
}, 1000)
});
I also have two other functions, disableScroll
and enableScroll
. These I did not included in my JSFiddle because the bug reproduces anyway, it was just an attempt to fix it but I am lost whether I should keep or delete these functions. I would also appreciate an advice on this
var keys = {37: 1, 38: 1, 39: 1, 40: 1};
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
function preventDefaultForScrollKeys(e) {
if (keys[e.keyCode]) {
preventDefault(e);
return false;
}
}
function disableScroll() {
console.log('disabling scroll')
if (window.addEventListener) // older FF
window.addEventListener('DOMMouseScroll', preventDefault, false);
window.onwheel = preventDefault; // modern standard
window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE
window.ontouchmove = preventDefault; // mobile
document.onkeydown = preventDefaultForScrollKeys;
}
function enableScroll() {
console.log('enabling scroll')
if (window.removeEventListener)
window.removeEventListener('DOMMouseScroll', preventDefault, false);
window.onmousewheel = document.onmousewheel = null;
window.onwheel = null;
window.ontouchmove = null;
document.onkeydown = null;
}
I have made several research on this matter but I was not able to fix it. Any help is very much appreciated. Thank you.