TAGS :Viewed: 18 - Published at: a few seconds ago

[ JQuery long delay on .scrollTop() calculation ]

I wrote this little bit of code to calculation the distance to the top of the page. Depending if the distance is 0 or not it make a an image disappear/appear and moves the secondary have on up/down.

$(window).scroll(function(){
    if ($(this).scrollTop() > 0) {
        $('#headerImg').animate({height:'0px'}, 500);
        $('#wrapperSCNav').animate({top:'185px'}, 500);
    } else {
        $('#headerImg').animate({height:'290px'}, 500);
        $('#wrapperSCNav').animate({top:'475px'}, 500);
    }
});

Which kinda works, I'm pretty sure the problem is that code is calculating scrollTop() so many times that it takes it's self seconds to realize that its back at 0.

Answer 1


You should consider throttling the scrolling function, such that it fires after a set interval rather that many dozen times a second. I have always recommended using Ben Alman's plugin.

The modification to your code will be quite minimal - in the code below, I have chosen to throttle the scroll event such that it fires every 250ms (or 4 times per second). You can of course adjust this value.

$(window).scroll($.throttle(250, function(){ // Use $.throttle() before calling function
    if ($(this).scrollTop() > 0) {
        $('#headerImg').animate({height:'0px'}, 500);
        $('#wrapperSCNav').animate({top:'185px'}, 500);
    } else {
        $('#headerImg').animate({height:'290px'}, 500);
        $('#wrapperSCNav').animate({top:'475px'}, 500);
    }
})); // Extra closing parenthesis from $.throttle()

On a side note, it is also probably a good idea to forcibly clear the animation queue and jump to end state before you fire each animation using .stop(true,true):

$(window).scroll($.throttle(250, function(){ // Use $.throttle() before calling function
    if ($(this).scrollTop() > 0) {
        $('#headerImg').stop(true,true).animate({height:'0px'}, 500);
        $('#wrapperSCNav').stop(true,true).animate({top:'185px'}, 500);
    } else {
        $('#headerImg').stop(true,true).animate({height:'290px'}, 500);
        $('#wrapperSCNav').stop(true,true).animate({top:'475px'}, 500);
    }
})); // Extra closing parenthesis from $.throttle()

Answer 2


Maybe something like this will help:

This will only apply the changes after the user has stopped scrolling.

var timer;
$(window).scroll(function(){
    clearTimeout(timer);
    timer = setTimeout( refresh , 150 );
});
var refresh = function () { 
    if ($(window).scrollTop() > 0) {
        $('#headerImg').animate({height:'0px'}, 500);
        $('#wrapperSCNav').animate({top:'185px'}, 500);
    } else {
        $('#headerImg').animate({height:'290px'}, 500);
        $('#wrapperSCNav').animate({top:'475px'}, 500);
    }        
};

Update

Or if you would like it only to change when scrolling but only when needed:

$(window).scroll(function(){
    if ($(this).scrollTop() > 0 && $('#headerImg').height() != 0) {
        $('#headerImg').animate({height:'0px'}, 500);
        $('#wrapperSCNav').animate({top:'185px'}, 500);
    } else if($('#headerImg').height() == 0) {
        $('#headerImg').animate({height:'290px'}, 500);
        $('#wrapperSCNav').animate({top:'475px'}, 500);
    }
});

Answer 3


jsFiddle Demo

$(window).scroll(function(){
 if ($(this).scrollTop() > 0) {
    $('#headerImg').stop().animate({height:'0px'}, 500);
    $('#wrapperSCNav').stop().animate({top:'185px'}, 500);
 } else {
    $('#headerImg').stop().animate({height:'290px'}, 500);
    $('#wrapperSCNav').stop().animate({top:'475px'}, 500);
 }
});

$.fx is filling up

Every time there is a call to animate, an event with a timeout is pushed into the fx queue of the jQuery object for the given selector. When an animation is tied to scrolling, what will occur is that this fx queue fills up quickly with these animation callbacks. Scrolling to the bottom and then back, and repeating will cause the animation to have undesired results (most of the time) because it causes everything to wait for every animation to complete before doing the next step.

use stop to prevent it

The common fix for this is to call jQuery's stop on the jQuery object before using animate. This essentially pops the previous callbacks from the fx queue allowing the current animation to run instantly.