Правильный способ reset анимации GIF с отображением: none в Chrome

Заголовок не требует пояснений, но я предоставлю пошаговое представление по этому вопросу. Надеюсь, я не первый, кто заметил эту (по-видимому) ошибку в Webkit/Chrome.

Я хочу reset анимацию GIF. Все примеры, которые я видел до сих пор, либо просто устанавливают src изображения самому себе, либо снова устанавливают его в пустую строку, за которой следует оригинал src.

Взгляните на этот JSFiddle для справки. GIF сбрасывает отлично в IE, Firefox и Chrome.

Проблема, которая у меня есть, заключается в том, что изображение display:none только в Google Chrome.

Отметьте JSFiddle. GIF сбрасывает штраф на IE и Firefox перед отображением на странице, но Chrome просто отказывается от reset его анимации!

Что я пробовал до сих пор:

  • Установка src для себя, как в Fiddle, не работает в Chrome.
  • Установка src в пустую строку и восстановление ее по умолчанию также не работает.
  • Помещение обертки вокруг изображения, опуская контейнер через .html('') и помещая изображение обратно внутрь, тоже не работает.
  • Изменение display изображения с помощью .show() или .fadeIn() перед установкой src тоже не работает.

Обходной путь только, который я нашел до сих пор, заключается в том, чтобы сохранить изображение по умолчанию display и манипулировать им с помощью .animate() ing и .css() с непрозрачностью, высотой и видимостью, когда необходимо для моделирования поведения display:none.

Основная причина (контекст) этого вопроса заключается в том, что я хотел reset ajax loader GIF прямо перед тем, как затухать его на странице.

Итак, мой вопрос в том, есть ли подходящий способ для reset анимации изображения GIF (что позволяет избежать ошибки Chrome display:none) или это на самом деле ошибка?

(ps. Вы можете изменить GIF в скриптах для более подходящего/более длинного анимационного gif для тестирования)

Ответы

Ответ 1

Chrome использует изменения стиля по-другому, чем другие браузеры.

В Chrome, когда вы вызываете .show() без аргумента, элемент фактически не отображается сразу же там, где вы его вызываете. Вместо этого Chrome ставит в очередь приложение нового стиля для выполнения после оценки текущего фрагмента JavaScript; тогда как другие браузеры немедленно применили бы новое изменение стиля. .attr(), однако, не попадает в очередь. Поэтому вы эффективно пытаетесь установить src, когда элемент по-прежнему не отображается в соответствии с Chrome, и Chrome ничего не сделает, когда исходные src и new src совпадают.

Вместо этого вам нужно убедиться, что jQuery устанавливает src после применения display: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 устанавливается после того, как display:block был применен к элементу.

Причина, по которой это работает, заключается в том, что setTimeout ставит очередь на выполнение функции позже (как бы долго она не была позже), поэтому функция больше не считается частью текущего "куска" JavaScript, и это обеспечивает разрыв для Chrome визуализировать и применять сначала display:block, тем самым делая элемент видимым до того, как будет установлен его атрибут src.

Демо: http://jsfiddle.net/F8Q44/19/

Благодаря shoky в #jquery freenode IRC для обеспечения более простого ответа.


В качестве альтернативы вы можете принудительно перерисовать, чтобы очистить измененные изменения стиля. Это можно сделать, например, путем доступа к элементу offsetHeight property:

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

Демо: http://jsfiddle.net/F8Q44/266/

Ответ 2

Самый надежный способ "reset" GIF - добавить случайную строку запроса. Однако это означает, что GIF будет перезагружен каждый раз, поэтому убедитесь, что это небольшой файл.

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

Ответ 3

Это решение предварительно загружает 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

Это работало для меня в Chrome, оно запускается каждый раз перед тем, как я исчезаю на изображении и очищает, а затем заправляет src, и моя анимация теперь начинается с самого начала каждый раз.

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

Ответ 5

Просто потому, что я все еще нуждаюсь в этом, время от времени я решил, что чистая функция JS, которую я использую, может быть полезна для кого-то другого. Это чистый JS-способ перезапуска анимированного gif, не перезагружая его. Вы можете вызвать это из события загрузки ссылки и/или документа.

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

В некоторых браузерах вам нужно только reset img.src для себя, и он отлично работает. В IE вам необходимо очистить его перед его сбросом. Этот resetGif() выбирает имя изображения из идентификатора изображения. Это удобно, если вы когда-либо меняете фактическую ссылку на изображение для данного идентификатора, потому что вам не нужно помнить об изменении вызовов resetGiF().

- Нико

Ответ 6

вот мой взлом для фоновых изображений:

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

Ответ 7

У меня есть кнопка с анимационным изображением без петли. Я просто перезагружаю изображение с помощью некоторого jquery, и это, похоже, работает для меня.

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

Ответ 8

Я наткнулся на эту тему после поиска многих других. Сообщение Дэвида Белла привело меня к решению, в котором я нуждался.

Я думал, что отправлю свой опыт в том случае, если это может быть полезно для тех, кто пытается выполнить то, что мне нужно. Это для веб-приложения HTML5/JavaScript/jQuery, которое будет iPhone-приложение через PhoneGap. Тестирование в Chrome.

Цель:

  • Когда пользователь нажимает кнопку A, появляется анимированный gif и воспроизводится.
  • Когда пользователь нажимает/нажимает кнопку B, gif исчезает.
  • Когда пользователь снова нажимает кнопку A, после нажатия/нажатия кнопки B, анимированный gif должен появляться и воспроизводиться с самого начала.

Проблема:

  • При нажатии/нажатии кнопки A я добавлял gif к существующему div. Это будет хорошо.
  • Затем, нажав кнопку/кнопку B, я скрыл контейнер div, а затем установил img src gif в пустую строку (''). Опять же, никаких проблем (то есть проблема еще не проявилась).
  • Затем, при нажатии/нажатии кнопки A, после нажатия/нажатия кнопки B, я повторно добавлял путь к gif как src.

    - Это не сработало. gif будет отображаться при последующих нажатиях/щелчках кнопки A... однако, чем больше я нажал/нажал кнопку A, тем больше времени gif загрузится и начните сначала. То есть, если бы я пошел туда и обратно, нажав/нажав кнопку A, а затем кнопку B 3 раза, появится gif, а затем начните/остановитесь/начните 3 раза... и все мое приложение начнет крутить. Я думаю, что gif загружался несколько раз, хотя я установил src в пустую строку, когда нажата/нажата кнопка B.

Решение:

Посмотрев сообщение Дэвида Белла, я пришел к моему ответу.

  • Я определил глобальную переменную (позвольте ей myVar), которая содержала контейнер div и изображение (с исходным путем) внутри.
  • При нажатии кнопки/щелчка кнопки A я добавил этот контейнер div в существующий родительский div в dom.
  • В этой функции я создал новую переменную, которая содержит путь src для gif.

Как и Дэвид, я сделал это (плюс добавление):

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

THEN, в функции для кнопки B я установил src в пустую строку, а затем удалил div, содержащий gif:

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

Теперь я могу нажать кнопку A, затем кнопку B, затем кнопку A и т.д., весь день. Gif загружает и воспроизводит нажатие кнопки A, затем прячется нажатием кнопки B, затем загружает и воспроизводит с самого начала на последующих нажатиях кнопки A каждый раз без проблем.

Ответ 9

Я разработал полное решение этой проблемы. Его можно найти здесь: fooobar.com/questions/322698/...

Мое решение перезапускает анимацию БЕЗ повторной загрузки данных изображения из сети.

Он также заставляет изображение перерисовывать, чтобы исправить некоторые артефакты живописи, которые произошли (в хроме).

Ответ 10

У меня возникли проблемы со всеми вышеперечисленными решениями. Что, наконец, было заменено 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;
};

Ответ 11

Прошло несколько лет, и я решил пересмотреть это, так как у нас есть ряд новых возможностей в нашем распоряжении.

Проблема с моим предыдущим ответом заключается в том, что он заставляет повторно загружать GIF каждый раз, когда вы хотите снова запустить его. Хотя это прекрасно для небольших файлов, это все еще накладные расходы, которые лучше всего избегали, если это было возможно.

Имея это в виду, у меня появилось новое решение, которое использует AJAX для загрузки GIF один раз, а затем преобразует его в URL-адрес данных (через FileReader) и использует это как источник со случайной строкой запроса.

Таким образом, браузер только когда-либо загружает изображение один раз и может даже кэшировать его правильно, а "reset" извлекает из этого загруженного ресурса.

Единственный улов, конечно, состоит в том, что вы должны убедиться, что он правильно загружен, прежде чем вы сможете его использовать.

Демо: 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();
}