10

I'm trying to create this behavior: when user scrolls a mousewheel (or presses ) the webpage is scrolled down by the height of the window.

I've ended up with following code:

var newScrollTop,
    oldScrollTop = $(window).scrollTop(),
    preventScroll = false;
$(window).scroll(function() {
    if (!preventScroll) {
        preventScroll = true;
        newScrollTop = $(this).scrollTop();
        if (newScrollTop > oldScrollTop) {
            $(this).scrollTop( oldScrollTop + $(window).height() );
        }
        else {
            $(this).scrollTop( oldScrollTop - $(window).height() );
        }
        oldScrollTop = newScrollTop;
        preventScroll = false;
    }
});

But this doesn't work as I expect it: on scroll event page is scrolled to the very edge (bottom or top). What am I missing?

Pavlo
  • 43,301
  • 14
  • 77
  • 113

2 Answers2

4

The issue is you're using scrollTop() which trigger a scroll event inside the window scroll event itself.

So basically, with the code you've written you run into an infinite loop because as soon as the first scroll event is triggered another one is triggered by scrollTop() while your preventScroll variable is still not set to false and so on.

To make your code work you would have to set your preventScroll variable to false inside the setTimeout function like so :

var newScrollTop,
    oldScrollTop = $(window).scrollTop(),
    preventScroll = false;

$(window).scroll(function() {
    if (!preventScroll) {
        preventScroll = true;
        newScrollTop = $(this).scrollTop();
        if (newScrollTop > oldScrollTop) {
            $(this).scrollTop( oldScrollTop + $(window).height() );
        }
        else {
            $(this).scrollTop( oldScrollTop - $(window).height() );
        }
        oldScrollTop = newScrollTop;

        setTimeout(function(){ preventScroll = false; }, 0);
    }
});

We add some "delay" before we set preventScroll to false. This way when you call scrollTop() preventScroll variable will still be set to true !

Here's a working fiddle : http://jsfiddle.net/J6Fcm/ (I modified a little bit your code to let the scrolling steps work as expected)

2

There is no easy way of overriding the default browser scroll functionality. Here's one way of doing what you want, but it requires Brandon Aaron's jquery-mousewheel plugin to manage the mouse scrollwheel:

$(function() {
    // Ugly hack to disable browser scrolling (downside: hides scrollbar!!!)
    $('html').css('overflow', 'hidden');

    // Get viewport height by which to scroll (up or down)
    var viewportHeight = $(window).height();

    // Recache viewport height on browser resize
    $(window).on('resize', function() {
        viewportHeight = $(window).height();
    });

    // Scroll on mousewheel
    $('html').on('mousewheel', function(event, delta, deltaX, deltaY) {
        // scroll down
        if (deltaY < 0)
            window.scrollBy(0, viewportHeight);
        // scroll up
        else
            window.scrollBy(0, -viewportHeight);
    });

    // Disable document keypress event
    // which would scroll the content even with "overlow: hidden"
    $(document).on('keypress', function(){
        return false;
    });

    // Scroll on arrow up/down keys
    $(document).on('keydown', function(event){
        // arrow down key
        if (event.which == 40)
            window.scrollBy(0, viewportHeight);
        // arrow up key
        if (event.which == 38)
            window.scrollBy(0, -viewportHeight);
    });
});

Here's a fiddle to demo the code. It all works very well except there is one ugly drawback to my solution. The $('html').css('overflow', 'hidden'); is removing the browser scrollbar.

Bogdan
  • 43,166
  • 12
  • 128
  • 129
  • I already have scrollbars hidden and disabling `keypress` seems to be unnecessary. The other part work like a charm. Many thanks. – Pavlo Oct 07 '12 at 15:17
  • 1
    Glad I could be of help. I've noticed a small bug with my solution, more exactly if you resize the browser the viewportHeight is no longer valid as it was cached on DOMReady. I've updated the code to manage that. – Bogdan Oct 07 '12 at 16:05