Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Łukasz Czuliński
Łukasz Czuliński
8,646 Points

Trying to resize header on window scroll and getting strange behavior.

As my title suggests, I'm having trouble animating my header on window scroll.

Everything works just fine after the page loads and I initially scroll down. The animation runs smooth and all at once.

When I scroll back up to the top, however, weird stuff happens. The removeClass() fires instantly, and then the animations happen at odd times. For example, with this animation $('#logo, header').animate({height: '120px'}, 500);, the header resizes maybe 5 seconds after I scroll to the top, and then the #logo a few seconds after that.

window.onscroll = function () {
    if ($(window).scrollTop() > 0) {
        $('header').addClass('header-shadow');
        $('#logo, header').animate({height: '80px'}, 500);
        $('#logo').animate({backgroundColor: 'white'}, 500);
    }
    else{
        $('header').removeClass('header-shadow');
        $('#logo, header').animate({height: '120px'}, 500);
        $('#logo').animate({backgroundColor: '#E0E066'}, 500);
    }
};

Any ideas why it's behaving this way?

2 Answers

As you scroll, the animations on the elements keep queuing up. Even though you can't see it (since the end result of the first animation is already visible), the animations keep firing up.

If you scroll back up, the queue gets filled further with additional animation events. The .scrollTop() == 0 animations only get fired when the queue is empty, that's what causes the delays.

The .addClass()/ .removeClass() methods are instantaneous, there's no queue, so they get executed immediately and you don't need to do anything to get them working.

As Andrew Shook suggested, the best way to do this is through CSS3 transitions, and just use JavaScript to add the classes.

If you really need to use JavaScript for this, you can use the jQuery .stop() method to stop current animations, like this:

$(function(){
    $(document).on("scroll", function () {
        if ($('body').scrollTop() > 0) {
            $('header').addClass('header-shadow');
            $('#logo').stop().animate({height: '80px'}, {queue: false, duration: 500}, function(){console.log("height logo done");}).animate({backgroundColor: '#ffffff'}, 500, function(){console.log("color logo done");});
            $("header").stop().animate({height: '80px'}, 500, function(){console.log("height header done");});
        }
        if ($('body').scrollTop() === 0) {
            console.log("banan");
            $('header').removeClass('header-shadow');
            $('#logo').stop().animate({height: '120px'}, {queue: false, duration: 500}).animate({backgroundColor: '#E0E066'}, 500);
            $("header").stop().animate({height: '120px'}, 500);
        }
    });

});

Oh, and if you want to see how the animations queue up, remove the .stop() calls from my code snippet and open the JavaScript console in your browser when the page loads. Then scroll down. You'll see how the completion callbacks for animations keep firing even when you've stopped scrolling.

Andrew Shook
Andrew Shook
31,709 Points

Dino, I should have noticed that it was continuously queuing the animation. Good catch.

Łukasz Czuliński
Łukasz Czuliński
8,646 Points

Thanks Dino. What a perfect explanation. That makes total sense.

JavaScript is not a necessity; I was just curious why it was behaving like that. As Andrew suggested, I have since used CSS animations which is so much better for this task,

Andrew Shook
Andrew Shook
31,709 Points

I know this does answer your question per se, but when I run into time like these when JS is acting weird I use css and css3 transitions. Just add and remove a class, like .big, a let css do the resizing.

Łukasz Czuliński
Łukasz Czuliński
8,646 Points

Nice one, thanks! That worked like a charm. I probably should have just done that from the start but I guess I like the self-punishment.

I'm still curious why all the animations were firing at weird times if anyone has an idea.

Andrew Shook
Andrew Shook
31,709 Points

JavaScript isn't really my strongest language so I might not be the best person to answer this question. My guess would be that it probably has something to do with the fact that JS is an asynchronous language and doesn't have to finish certain function calls before it starts a new one. Also I may have to do it checking your scroll top a zero. Having it set there may be causing an oscillation, since the margin for change is so small. Change your if conditional to scroll.top > 10 and see if that helps

Łukasz Czuliński
Łukasz Czuliński
8,646 Points

Yeah, I even tried setting the conditional to like 100 and the exact same issue.

The weirdest thing about the animation problems was that it seemed the delay between them was identical each time; something silly like 2 seconds for the header to resize, followed by 3 seconds and the logo resizing. I'll try to throw it up on JSFiddle or something and see if anyone knows what was going on.