web-dev-qa-db-fra.com

Méthode appropriée pour réinitialiser une animation GIF avec affichage: aucune sur Chrome

Le titre est explicite, mais je vais vous fournir une vue détaillée de la question. Espérons que je ne suis pas le premier à avoir remarqué ce bogue (apparemment) sur Webkit/Chrome.

Je veux réinitialiser une animation GIF. Tous les exemples que j'ai vus jusqu'à présent, définissaient simplement la src de l'image sur elle-même ou la définissaient à une chaîne vide suivie de la src d'origine à nouveau.

Jetez un oeil à ceci JSFiddle pour référence. Le GIF se réinitialise parfaitement sur IE, Firefox et Chrome.

Le problème que j'ai est lorsque l'image a display:none sur Google Chrome uniquement.

Vérifiez ceci JSFiddle. Le GIF se réinitialise correctement sur IE et Firefox avant de s'afficher dans la page, mais Chrome refuse simplement de réinitialiser son animation!

Ce que j'ai essayé jusqu'à présent:

  • Définir la src sur lui-même, comme dans Fiddle, ne fonctionne pas dans Chrome.
  • Définir src sur une chaîne vide et la restaurer à la valeur par défaut ne fonctionne pas non plus.
  • Placer un emballage autour de l'image, vider le conteneur par .html('') et remettre l'image à l'intérieur ne fonctionne pas non plus.
  • Changer la display de l'image par .show() ou .fadeIn() juste avant de définir la src ne fonctionne pas non plus.

La solution de contournement only que j’ai trouvée jusqu’à présent consiste à conserver l’image avec sa valeur par défaut display et à la manipuler via .animate()ing et .css()ing l’opacité, la hauteur et la visibilité lorsque cela est nécessaire pour simuler un comportement display:none.

La raison principale (contexte) de cette question est que je voulais réinitialiser un fichier GIF de chargeur Ajax juste avant de le perdre dans la page.

Ma question est donc la suivante: existe-t-il un moyen approprié de réinitialiser l'animation d'une image GIF (qui évite le bogue display:none de Chrome) ou s'agit-il en fait d'un bogue?

(ps. Vous pouvez changer le GIF dans les violons pour un gif d'animation plus approprié/plus long pour le test)

16
Fabrício Matté

Chrome traite les changements de style différemment des autres navigateurs.

Dans Chrome, lorsque vous appelez .show() sans argument, l'élément n'est pas affiché immédiatement à l'endroit où vous l'appelez. À la place, Chrome met en file d'attente l'application du nouveau style pour exécution après évaluer le bloc actuel de JavaScript; alors que d'autres navigateurs appliqueraient le nouveau changement de style immédiatement. .attr(), cependant, ne se met pas en file d'attente. Donc, vous essayez effectivement de définir la src lorsque l'élément n'est toujours pas visible selon Chrome et que Chrome ne fera rien à ce sujet lorsque l'original src et le nouveau src sont les mêmes.

Au lieu de cela, vous devez vous assurer que jQuery définit la src après l'application de display:block. Vous pouvez utiliser setTimeout pour obtenir cet effet:

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

Cela garantit que src est défini après que display:block a été appliqué à l'élément.

Cela fonctionne parce que setTimeout met en file d'attente la fonction à exécuter plus tard (quelle que soit la durée plus tard est), donc la fonction n'est plus considérée comme faisant partie du "bloc" actuel de JavaScript et fournit un espace pour que Chrome rende et applique le display:block en premier, rendant ainsi l'élément visible avant que son attribut src ne soit défini.

Démo: http://jsfiddle.net/F8Q44/19/

Merci à Shoky de #jquery of freenode IRC pour sa réponse plus simple.


Vous pouvez également forcer un rafraîchissement pour vider les modifications de style par lots. Cela peut être fait, par exemple, en accédant à la propriété offsetHeight de l'élément:

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

Démo: http://jsfiddle.net/F8Q44/266/

28
Kal

Le moyen le plus fiable de "réinitialiser" un fichier GIF consiste à ajouter une chaîne de requête aléatoire. Cependant, cela signifie que le fichier GIF sera à chaque fois téléchargé à nouveau. Assurez-vous donc qu'il s'agit d'un petit fichier.

// reset a gif:
img.src = img.src.replace(/\?.*$/,"")+"?x="+Math.random();
27

Cette solution précharge le gif et le sort du dom puis revient dans le src (évitant ainsi un autre téléchargement)

Je viens de le tester en utilisant jQuery pour supprimer l'attribut et cela fonctionne très bien. 

Exemple: 

<html>
<head>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>

<script>

$(function() {

    $('.reset').click(resetGif);

    function resetGif() 
    {
        $('.img1').removeAttr('src', '');
    }
});

</script>

</head>

<body>
    <img class="img1" src="1.gif" />
    <a href="#" class="reset">reset gif</a>
</body>
</html>
4
teebot

Juste parce que j'en ai toujours besoin de temps en temps, j'ai pensé que la fonction JS que j'utilise pourrait être utile à quelqu'un d'autre. C’est une façon JS pure de redémarrer un gif animé, sans le recharger. Vous pouvez appeler cela à partir d'un événement de lien et/ou de chargement de document.

<img id="img3" src="../_Images/animated.gif">

<a onClick="resetGif('img3')">reset gif3</a>

<script type="text/javascript">

// reset an animated gif to start at first image without reloading it from server.
// Note: if you have the same image on the page more than ones, they all reset.
function resetGif(id) {
    var img = document.getElementById(id);
    var imageUrl = img.src;
    img.src = "";
    img.src = imageUrl;
};

</script>

Sur certains navigateurs, il vous suffit de réinitialiser le fichier img.src pour qu'il fonctionne correctement. Sur IE, vous devez l’effacer avant de le réinitialiser. Ce resetGif () sélectionne le nom de l'image à partir de l'id de l'image. C'est pratique si vous modifiez jamais le lien d'image réel pour un identifiant donné, car vous n'avez pas à vous souvenir de modifier les appels resetGiF ().

--Nico

2
nico

J'ai un bouton avec une image animée sans boucle dedans. Je viens de recharger l’image avec quelques images et cela semble fonctionner pour moi.

var asdf = $(".settings-button img").attr("src");
$(".settings-button img").attr("src", "").attr("src", asdf);
1
Pratyush

voici mon hack pour les images de fond:

$(document).on('mouseenter', '.logo', function() {
  window.logo = (window.logocount || 0) + 1;
  var img = new Image();
  var url = "/img/mylogimagename.gif?v=" + window.logocount;
var that = this;
  $(img).load(function(){

     $(that ).css('background-image','url(' + url + ')');
  });
  img.src = url;
});
1
ayal gelles

Cela semblait fonctionner pour moi dans Chrome: il s'exécute à chaque fois juste avant que je ne passe en fondu dans l'image, efface puis recharge le src et mon animation commence maintenant à chaque début.

var imgsrc = $('#my_image').attr('src');
$('#my_image').attr('src', '');
$('#my_image').attr('src', imgsrc);
1
David Bell

J'ai rencontré des problèmes avec toutes les solutions ci-dessus. Ce qui a finalement fonctionné a été de remplacer temporairement le src par un gif transparent de 1 px

var transparent1PxGif = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
var reloadGif = function(img) {
    var src = img.src;
    img.src = transparent1PxGif;
    img.offsetHeight; // triggers browser redraw
    img.src = src;
};
0
Daniel Howard

Cela fait plusieurs années et j'ai décidé de revenir sur cette question depuis que nous avons plusieurs nouvelles options à notre disposition.

Le problème avec ma réponse précédente est que cela force un nouveau téléchargement du fichier GIF à chaque fois que vous souhaitez le redémarrer. Même si cela convient pour les petits fichiers, cela reste une surcharge qu'il vaut mieux éviter si possible.

Dans cet esprit, j'ai une nouvelle solution qui utilise AJAX pour télécharger le GIF une fois, puis le convertit en une URL de données (via un FileReader) et l'utilise comme source avec une chaîne de requête aléatoire attachée. .

De cette façon, le navigateur ne télécharge l'image qu'une seule fois et peut même la mettre en cache correctement. La "réinitialisation" est alors extraite de cette ressource pré-téléchargée.

Le seul problème, bien sûr, est que vous devez vous assurer qu'il est correctement chargé avant de pouvoir l'utiliser.

Démo: http://adamhaskell.net/misc/numbers/numbers.html

Code pertinent:

var url = "something.gif"; // fallback until the FileReader is done
function setup() {
    var xhr = new XMLHttpRequest();
    xhr.open("GET",url,true);
    xhr.responseType = "blob";
    xhr.onreadystatechange = function() {
        if( this.readyState == 4) {
            var fr = new FileReader();
            fr.onload = function() {
                url = this.result; // overwrite URL with the data one
            };
            fr.readAsDataURL(this.response);
        }
    };
    xhr.send();
}
function getGIF() {
    return url+"?x="+Math.random();
}
0

J'ai élaboré une solution complète pour ce problème. Vous pouvez le trouver ici: https://stackoverflow.com/a/31093916/1520422

Ma solution relance l'animation SANS recharger les données d'image du réseau.

Il oblige également l'image à repeindre pour corriger certains artefacts de peinture apparus (en chrome).

0

Je suis tombé sur ce fil après avoir cherché beaucoup d'autres. Le message de David Bell m'a amené à la solution dont j'avais besoin.

Je pensais poster mon expérience au cas où cela pourrait être utile à quiconque essaie d'accomplir ce que j'étais après. Ceci est pour une application Web HTML5/JavaScript/jQuery qui sera une application iPhone via PhoneGap. Test en Chrome.

Le but:  

  1. Lorsque l'utilisateur appuie/clique sur le bouton A, un gif animé apparaît et est lu.
  2. Lorsque l'utilisateur appuie/clique sur le bouton B, gif disparaît.
  3. Lorsque l'utilisateur appuie/clique à nouveau sur le bouton A, après avoir appuyé sur/cliqué sur le bouton B, le gif animé doit réapparaître et être lu à partir du début.

Le problème:

  • Sur tap/click du bouton A, j'ai ajouté le gif à un div existant. Cela jouerait bien.
  • Puis, en tapotant/cliquant sur le bouton B, je cachais le conteneur div, puis je définissais img src du gif sur une chaîne vide (''). Encore une fois, pas de problème (c'est-à-dire, le problème n'était pas encore évident.)
  • Puis, appuyez sur/cliquez sur le bouton A, puis appuyez sur/cliquez sur le bouton B, je rajoutais le chemin d'accès au gif en tant que src.

    - Cela n'a pas fonctionné. Le gif apparaîtra lors des taps/clics ultérieurs du bouton A ... Cependant, plus je tapotai/cliquais sur le bouton A, plus le gif se chargerait et recommencerait. C'est-à-dire que si j'allais et venais, tapotant/cliquant sur le bouton A, puis sur le bouton B 3 fois, le gif apparaîtrait, puis démarrer/arrêter/démarrer 3 fois ... et toute mon application a commencé à bouger. Je suppose que le gif a été chargé plusieurs fois, même si j'avais défini la chaîne src sur une chaîne vide lorsque le bouton B était appuyé/cliqué.

La solution:

Après avoir regardé le message de David Bell, je suis arrivé à ma réponse.

  1. J'ai défini une variable globale (appelons-la myVar) qui contenait le conteneur div et l'image (avec le chemin source) à l'intérieur.
  2. Sur la fonction Taper/cliquer du bouton A, j'ai ajouté ce conteneur div à un div parent existant dans le dom.
  3. Dans cette fonction, j'ai créé une nouvelle variable qui contient le chemin src du gif.

Comme David l’a suggéré, j’ai fait ceci (plus une annexe):

$('#mainParent').append(myVar);
var imgsrc = $('#my_image').attr('src');
$('#my_image').attr('src', '');
$('#my_image').attr('src', imgsrc);

ALORS, dans la fonction du bouton B, j'ai défini le src sur une chaîne vide, puis supprimé le div contenant le gif:

$('#my_image').attr('src', '');
$('#mainParent').find('#my_image').remove();

Maintenant, je peux appuyer/cliquer sur le bouton A, puis sur le bouton B, puis sur le bouton A, etc., toute la journée. Le gif se charge et joue du tap/clic du bouton A, puis se masque au tap/du clic du bouton B, puis se charge et se lit depuis le début lors des taps suivants du bouton A à chaque fois, sans problème.

0
Banjo Drill