0

I want to write custom scroll to sections functionality.

When I load the page and scroll down, it should scroll down the height of the window, which is fine.

Then, if scrolling down again, I want to check if the page has scrolled more than window height (which should be, if scrolling down), but it seems to be stuck at where it's at after the first scroll.

So I can get from red to yellow, but not from yellow to green.

var winHeight = window.innerHeight;
$('div').each(function(){
        $(this).css('height', winHeight);
});

function scrollSections() {

        var windowHeight = window.innerHeight;
        var scrollTop = $(window).scrollTop();
        var pos = windowHeight;

        if (scrollTop > windowHeight) {
            pos = windowHeight * 2;
        }

        $('body, html').animate({scrollTop: pos}, 1000, function() {
        });
}

$( window ).on( "scroll", function() {

        scrollSections();

    });

Fiddle: https://jsfiddle.net/zts70yc1/

dzimi
  • 769
  • 3
  • 10
  • 20
  • Have you looked around? I think this or something very similar has been [answered before.](http://stackoverflow.com/questions/21450095/how-to-make-mouse-wheel-scroll-to-section-like-in-mediafire-com) – R. Arnone May 27 '16 at 18:20
  • 1
    Be aware that if you initiate a scroll animation in a scroll event handler you are multiplying the calls to that handler and stacking up animations. That can't be right. – trincot May 27 '16 at 20:30

1 Answers1

1

When you call $('body, html').animate({scrollTop: pos}, ...);, you are triggering scroll events, which will run your handler again, which will start an animation again, based on the current (not final) scroll position, and so on. This multiplies the number of scrolls that happen: this is not what you want.

Instead, before doing anything else in your event handler, check whether an animated scrolling is ongoing, and decide what to do then. For instance, you could just exit the handler in that case, so the animation can continue without interference:

if ($('body, html').is(':animated')) return; // exit when animation ongoing

Also, the formula for setting the target position could be improved, by comparing first the scroll position to the previous scroll position. If higher, then scroll one "page" down, else one "page" up. For that, you should keep pos as a global variable, and do as follows:

var pos = $(window).scrollTop();
function scrollSections() {
        if ($('body, html').is(':animated')) return;
        var windowHeight = window.innerHeight;
        var scrollTop = $(window).scrollTop();
        if (pos == scrollTop) return; // no change
        // depending on scroll direction, go page up, down
        pos += pos < scrollTop ? windowHeight : -windowHeight;
        // round to nearest page boundary
        pos = Math.round(pos / windowHeight) * windowHeight;
        $('body, html').animate({scrollTop: pos}, 1000, function() {
        });
}

These changes have been applied in this fiddle.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • @trincof I just noticed if I scroll harshly with the mouse or laptop touchpad, it kind of shakes up or even jumps two sections ahead, any way to remedy this? So basically if scroll has been detected or scrolling animation started no further scrolling should be detected until it finishes. – dzimi May 27 '16 at 22:55
  • The problem is that your scrolling and the animated scrolling are working in concurrence and cause these shakes. You could make the animation finish faster, or somehow detect the difference between a scroll event triggered by the animation and the one from the mouse/pad. See [here](http://stackoverflow.com/questions/31467098/distinguishing-between-the-user-scrolling-and-programmatically-scrolling-using-j) for ideas. If you detect a mouse/pad one, you should [`stop()`](https://api.jquery.com/stop/) the animation. You could ask a new question about this. – trincot May 27 '16 at 23:13
  • Thanks. Can you have a look here first? http://stackoverflow.com/questions/37497607/isanimated-doesnt-seem-to-be-working – dzimi May 28 '16 at 09:59