Fabrício Matté Fabrício Matté - 2 years ago 220
Javascript Question

Proper way to reset a GIF animation with display:none on Chrome

Title is self-explanatory, but I'll provide a step-by-step view on the matter. Hopefully I'm not the first one to have noticed this (apparently) bug on Webkit/Chrome.

I want to reset a GIF animation. All of the examples I've seen so far either simply set the

of the image to itself or set it to an empty string followed by the original

Take a look at this JSFiddle for reference. The GIF resets perfectly fine on IE, Firefox and Chrome.

The issue which I have is when the image has
on Google Chrome only.

Check this JSFiddle. The GIF resets fine on IE and Firefox before being displayed in the page, but Chrome simply refuses to reset its animation!

What I've tried so far:

  • Setting the
    to itself as in Fiddle, doesn't work in Chrome.

  • Setting the
    to an empty string and restoring it to the default, doesn't work either.

  • Putting an wrapper around the image, emptying the container through
    and putting the image back inside of it, doesn't work either.

  • Changing the
    of the image through
    right before setting the
    doesn't work either.

The only workaround which I've found so far is keeping the image with its default
and manipulating it through
ing and
ing the opacity, height and visibility when necessary to simulate a

The main reason (context) of this question is that I wanted to reset an ajax loader GIF right before fading it in the page.

So my question is, is there a proper way to reset a GIF image's animation (which avoids Chrome's
"bug") or is it actually a bug?

(ps. You may change the GIF in the fiddles for a more appropriate/longer animation gif for testing)

Kal Kal
Answer Source

Chrome deals with style changes differently than other browsers.

In Chrome, when you call .show() with no argument, the element is not actually shown immediately right where you call it. Instead, Chrome queues the application of the new style for execution after evaluating the current chunk of JavaScript; whereas other browsers would apply the new style change immediately. .attr(), however, does not get queued. So you are effectively trying to set the src when the element is still not visible according to Chrome, and Chrome won't do anything about it when the original src and new src are the same.

Instead, what you need to do is to make sure jQuery sets the src after display:block is applied. You can make use of setTimeout to achieve this effect:

var src = 'http://i.imgur.com/JfkmXjG.gif';
    var $img = $('img');
            var timeout = 0; // no delay
            setTimeout(function() {
                $img.attr('src', src);
            }, timeout);

This ensures that src is set after display:block has been applied to the element.

The reason this works is because setTimeout queues the function for execution later (however long later is), so the function is no longer considered to be part of the current "chunk" of JavaScript, and it provides a gap for Chrome to render and apply the display:block first, thus making the element visible before its src attribute is set.

Demo: http://jsfiddle.net/F8Q44/19/

Thanks to shoky in #jquery of freenode IRC for providing a simpler answer.

Alternatively, you can force a redraw to flush the batched style changes. This can be done, for example, by accessing the element's offsetHeight property:

$('img').show().each(function() {
}).prop('src', 'image src');

Demo: http://jsfiddle.net/F8Q44/266/

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download