web-dev-qa-db-ja.com

display:none on ChromeでGIFアニメーションをリセットする適切な方法

タイトルは一目瞭然ですが、この問題について順を追って説明します。 Webkit/Chromeでこの(明らかに)バグに気付いたのは私が初めてではないことを願っています。

GIFアニメーションをリセットしたい。これまでに見たすべての例は、単に画像のsrcをそれ自体に設定するか、空の文字列に元のsrcを続けて設定します。

参照のためにこれを見てくださいJSFiddle IE、Firefox、ChromeでGIFは完全にリセットされます。

私が抱えている問題は、画像にdisplay:none onGoogle Chrome only)がある場合です。

これを確認してくださいJSFiddle GIFは、ページに表示される前にIEおよびFirefoxで正常にリセットされますが、Chromeはアニメーションのリセットを拒否します!

これまでに試したこと:

  • Fiddleのようにsrcをそれ自体に設定しても、Chromeでは機能しません。
  • srcを空の文字列に設定し、デフォルトに戻すことも機能しません。
  • 画像の周囲にラッパーを配置し、.html('')を介してコンテナを空にし、その中に画像を戻すことも機能しません。
  • displayを設定する直前に.show()または.fadeIn()を介して画像のsrcを変更しても機能しません。

これまでに見つけたonlyの回避策は、デフォルトのdisplayで画像を保持し、.animate()ingで操作することです。 display:none動作をシミュレートするために必要な場合、不透明度、高さ、および可視性を.css()ingします。

この質問の主な理由(コンテキスト)は、ページでフェードする直前にajaxローダーGIFをリセットしたかったからです。

だから私の質問は、GIF画像のアニメーションをリセットする適切な方法はありますか(これはChromeのdisplay:none "バグ"を回避します)、それとも実際にはバグですか?

(ps。テスト用により適切な/より長いアニメーションGIFのためにフィドルのGIFを変更できます)

19

Chromeは、スタイルの変更を他のブラウザーとは異なる方法で処理します。

Chromeでは、引数なしで.show()を呼び出すと、要素は実際に呼び出した場所にすぐには表示されません。代わりに、Chromequeues実行のための新しいスタイルのアプリケーションafterJavaScriptの現在のチャンクを評価しますが、他のブラウザはすぐに新しいスタイルの変更を適用しますが、.attr()はキューに入れられません。したがって、srcを効果的に設定しようとしています。 Chromeに従って要素がまだ表示されておらず、元のsrcと新しいsrcが同じ場合、Chromeは何もしません。

代わりに、jQueryでsrcafterdisplay:blockが適用されていることを確認する必要があります。 setTimeoutを使用して、この効果を実現できます。

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();
        }
    );
});

これにより、srcが設定されていることが保証されますafterdisplay:blockが要素に適用されました。

これが機能する理由は、setTimeoutが実行のために関数をキューに入れるためですlater(ただし、長さlateris)であるため、関数はJavaScriptの現在の「チャンク」の一部とは見なされなくなり、display:blockを最初にレンダリングして適用するためのChrome src属性が設定される前に要素を表示します。

デモ: http://jsfiddle.net/F8Q44/19/

Freenode IRCの#jqueryのshokyに、より簡単な答えを提供してくれてありがとう。


または、再描画を強制して、スタイルのバッチ変更をフラッシュすることができます。これは、たとえば、要素のoffsetHeightプロパティにアクセスすることで実行できます。

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

デモ: http://jsfiddle.net/F8Q44/266/

30
Kal

GIFを「リセット」する最も信頼できる方法は、ランダムなクエリ文字列を追加することです。ただし、これはGIFが毎回再ダウンロードされることを意味するため、小さなファイルであることを確認してください。

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

これは solution gifをプリロードし、それをdomから取り出してからsrcに戻します(したがって、別のダウンロードを回避します)

属性を削除するためにjqueryを使用してテストしたところ、正常に機能します。

例:

<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

私は今でもこれを必要とするからといって、使用している純粋なJS関数が他の誰かに役立つかもしれないと考えました。これは、アニメーションgifをリロードせずに再起動する純粋なJSの方法です。これは、リンクおよび/またはドキュメントの読み込みイベントから呼び出すことができます。

<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>

一部のブラウザでは、img.srcを自分自身にリセットするだけでよく機能します。 On IEリセットする前にクリアする必要があります。このresetGif()はイメージIDからイメージ名を選択します。これは、特定のIDの実際のイメージリンクを変更する場合に便利ですresetGiF()呼び出しを変更することを覚えておく必要はありません。

-ニコ

2
nico

アニメーション化されたループなしの画像を含むボタンがあります。私はいくつかのjqueryで画像をリロードするだけで、これは私のために働いているようです。

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

ここに背景画像のハックがあります:

$(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

これはChromeで私にはうまくいくように見えました。画像をフェードインする直前に毎回実行され、srcをクリアしてから補充し、毎回アニメーションが最初から始まります。

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

上記のすべてのソリューションで問題が発生しました。最終的に機能したのは、srcを一時的に透明な1px gifに置き換えることでした:

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

数年が経ちましたが、多くの新しいオプションが用意されているため、これを再検討することにしました。

以前の回答 の問題は、GIFを再起動するたびに強制的にGIFを再ダウンロードすることです。これは小さなファイルには適していますが、可能であればオーバーヘッドを回避するのが最善です。

それを念頭に置いて、AJAXを使用してGIFを一度ダウンロードし、それを(FileReaderを介して)データURLに変換し、それをソースとして使用する新しいソリューションがあります。添付されたランダムなクエリ文字列。

このように、ブラウザはイメージを一度だけダウンロードし、それを適切にキャッシュすることさえでき、「リセット」はその事前にダウンロードされたリソースからプルします。

もちろん、唯一の問題は、使用する前に適切にロードされていることを確認する必要があることです。

デモ: http://adamhaskell.net/misc/numbers/numbers.html

関連コード:

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

この問題の完全な解決策を考え出しました。ここにあります: https://stackoverflow.com/a/31093916/1520422

私のソリューションは、ネットワークから画像データを再ロードせずにアニメーションを再起動します。

また、発生したいくつかのペイントアーティファクト(クロム)を修正するために、イメージを強制的に再ペイントします。

他の多くを検索した後、このスレッドに出会いました。 David Bellの投稿は、私が必要とする解決策に私を導いた。

私が経験したことを達成しようとする人にとって有用なイベントに、自分の経験を投稿すると思いました。これは、PhoneGapを介したiPhoneアプリになるHTML5/JavaScript/jQuery Webアプリ用です。 Chromeでテストします。

目標:

  1. ユーザーがボタンAをタップ/クリックすると、アニメーションGIFが表示されて再生されます。
  2. ユーザーがボタンBをタップ/クリックすると、gifが消えます。
  3. ユーザーがボタンAを再度タップ/クリックすると、ボタンBをタップ/クリックした後、アニメーションgifが再表示され、最初から再生されます。

問題:

  • ボタンAをタップ/クリックすると、既存のdivにgifを追加していました。それはうまくいくでしょう。
  • 次に、ボタンBをタップ/クリックすると、コンテナdivを非表示にしてから、gifのimg srcを空の文字列( '')に設定しました。繰り返しますが、問題はありません(つまり、問題はまだ明らかではありませんでした。)
  • その後、ボタンAのタップ/クリックで、ボタンBのタップ/クリック後、ソースとしてgifへのパスを再度追加していました。

    -これは機能しませんでした。 GIFは、ボタンAの後続のタップ/クリックで表示されます...しかし、ボタンAをさらにタップ/クリックすると、 gifがロードされ、最初からやり直すことになります。つまり、ボタンAを3回タップ/クリックしてからボタンBを3回タップ/クリックすると、gifが表示され、3回起動/停止/起動します...そして、アプリ全体が動き始めました。ボタンBがタップ/クリックされたときにsrcを空の文字列に設定したにもかかわらず、gifが複数回ロードされたと思います。

解決策:

David Bellの投稿を見て、答えにたどり着きました。

  1. コンテナdivとイメージ(ソースパスを含む)を保持するグローバル変数(myVarと呼びます)を定義しました。
  2. ボタンAのタップ/クリック機能で、そのコンテナdivをdom内の既存の親divに追加しました。
  3. その関数では、gifのsrcパスを保持する新しい変数を作成しました。

デビッドが示唆したように、私はこれを行いました(および追加):

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

次に、ボタンBの関数で、srcを空の文字列に設定し、gifを含むdivを削除しました。

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

これで、ボタンA、ボタンB、ボタンAなどを1日中タップ/クリックできます。 GIFは、ボタンAのタップ/クリックでロードおよび再生され、ボタンBのタップ/クリックで非表示になり、その後、問題なくボタンAの後続のタップで最初からロードおよび再生されます。

0
Banjo Drill