ChaBuku Bakke
ChaBuku Bakke

Reputation: 693

Why are my animations delayed in Firefox? How can I improve this scroll script?

I'm having troubles getting this code to execute in a timely manner in Firefox. It seems to work just fine in Chrome.

JSFiddle here: http://jsfiddle.net/EXDhb/

Real live example page I'm working with here: http://mindevo.com/tests/tacos.html

I'm not sure if I'm leaving something out. I kind of hacked this together from reading a bunch of page-scroll scripts other people have put together. Not sure if this is even the best way for me to do what I'm trying to accomplish (which is to darken the next area until it's somewhat revealed. (I used halfway for this).

Here's my javascript:

$(document).ready(function(){
 $(window).scroll(function(){
  $('.dark').each(function(i){

   var half_object = $(this).position().top + ($(this).outerHeight()/2);
   var bottom_window = $(window).scrollTop() + $(window).height();
   var bottom_object = $(this).position().top + $(this).outerHeight();

   if(bottom_window > half_object){
    $(this).animate({'opacity':'1'},200);
   }
   else if(bottom_object > $(window).scrollTop()) {
    $(this).animate({'opacity':'.5'},200);
   }
  });
 });
});

Is there a better way to do this? I tried adding/removing css classes but it invoked some crazy Chrome bug I was not pleased about.

Why does it work so slowly in Firefox?

Upvotes: 0

Views: 99

Answers (3)

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93601

Start by not having 6 separate jQuery $(this) operations and multiple $(window)! Use temp variables whenever you can to avoid requerying.

JSFIddle: http://jsfiddle.net/TrueBlueAussie/EXDhb/9/

$(document).ready(function () {
    // window never changes
    var $window = $(window);
    $window.scroll(function () {
        // Window height may have changed between scrolls
        var windowHeight = $window.height();
        var scrollTop = $window.scrollTop();
        $('.dark').each(function (i) {
            var $this = $(this);
            var top = $this.position().top;
            var outerH = $this.outerHeight();
            var half_object = top + (outerH / 2);
            var bottom_window = scrollTop + windowHeight;
            var bottom_object = top + outerH;

            console.log(half_object);

            if (bottom_window > half_object) {
                $this.stop().animate({
                    'opacity': '1'
                }, 200);
            } else if (bottom_object > scrollTop) {
                $this.stop().animate({
                    'opacity': '.5'
                }, 200);
            }
        });
    });
});

And so on until you do not do anything twice that has an overhead that you do not need to have.

Update: Stop previous animations

The pause was not caused by the speed of the code above, but by not stopping multiple animations. The problem is that scroll fires frequently, so without .stop() animations get queued up and fire one after the other. This made it look much slower that it actually was.

Further optimizations might involve only processing elements that are actually onscreen, but that is pretty pointless given the apparent speed now.

Upvotes: 2

Greg Burghardt
Greg Burghardt

Reputation: 18868

I realize there is already an accepted answer, but many times it is useful to do something only after the user has stopped scrolling, and not each time the "scroll" event fires. This event can can fire upwards of 50 times per second, leaving you with ~20ms to do what you need to do. This other StackOverflow question shows you how to do something only after scrolling has stopped. As @TrueBlueAussie mentioned in his answer, you would still want to stop any animations that were currently running.

Upvotes: 1

Igor
Igor

Reputation: 34011

You can cache your variables, which should help slightly:

$(document).ready(function(){
    var $window = $(window);

    $window.scroll( function(){
        $('.dark').each(function(i){
            var $this = $(this);
            var outerHeight = $this.outerHeight();
            var positionTop = $this.position().top;
            var half_object = positionTop + (outerHeight/2);
            var bottom_window = window.scrollTop() + window.height();
            var bottom_object = positionTop + outerHeight;

            if(bottom_window > half_object){
                $this.animate({'opacity':'1'}, 200);
            } else if(bottom_object > window.scrollTop()) {
                $this.animate({'opacity':'.5'}, 200);
            }
        });
    });
});

Upvotes: 1

Related Questions