Перезапустить анимированный GIF в качестве фона-изображение

можно ли перезапустить анимированный GIF, используемый как background-image?

рассмотрим этот HTML:

<div id="face">
    <div id="eyes"></eyes>
</div>

и этого стиля:

#eyes.blink {
    background-image:url('blink.gif');
}

Я бы blink.gif анимация для воспроизведения каждый раз, когда я добавляю класс blink to #eyes, а не только в первый раз.

Я ожидал, что это сработает:

function startBlink() {
    $('#eyes').addClass('blink');
}

function stopBlink() {
    $('#eyes').removeClass('blink');
}

проблема в том, что Firefox и браузер WebKit не воспроизводят анимацию GIF-изображений после того, как она была воспроизведена один раз. Добавление / удаление класса blink работает только в первый раз.

8 ответов


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

в моем примере я добавляю и удаляю его onclick of <div id="animated">:

$('#animated').click(function() {

    /* Reference to the clicked element and toggle the .go class */
    var $div = $(this);
    $div.toggleClass('go');

    /* Start the animated gif */
    if ($div.hasClass('go')) {

        /* Create an <img> element and give it the animated gif as a src.  To 
           force a reload we add a date parameter to the URL */
        var img = document.createElement('img');
        img.src = "http://yoursite.com/animated.gif?p" + new Date().getTime();

        /* Once the image has loaded, set it as the background-image */
        $(img).load(function(){
            $div.css({backgroundImage: "url("+img.src+")"});
        });

    /* Remove the background-image */        
    } else {
       $div.css({backgroundImage: "none"});
    }
})

демо в действии.


Я нашел вы также можете добавить ?+Math.random() до конца изображения src, и он перезагрузит .файл gif.


Я объединил несколько частей решения, чтобы сделать одно целое решение, которое решает (надеюсь) все проблемы:

  • определите URL фонового изображения элемента (из css background-image)
  • запустите перезапуск для этого изображения без перезагрузки его из интернета
  • перезапуск его во всех местах (не касаясь каждого отдельно)
  • убедитесь, что цель перекрашена без артефактов после перезапуска анимация

в моем решении я создаю вспомогательные изображения, которые добавляются в тело, но скрыты таким образом, чтобы они по-прежнему визуализируются браузером, но не будут взаимодействовать со страницей визуально с помощью position: absolute; left: -5000px;.

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

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

протестировано в: Chrome (Версия 43.0.2357.130 m)

var resetHelperImages = {};

function restartAnimation(elem) {
  elem = $(elem);
  for (var i = 0; i < elem.length; i++) {
    var element = elem[i];
    // code part from: http://stackoverflow.com/a/14013171/1520422
    var style = element.currentStyle || window.getComputedStyle(element, false);
    // var bgImg = style.backgroundImage.slice(4, -1).replace(/"/g, '');
    var bgImg = style.backgroundImage.match(/url\(([^\)]+)\)/)[1].replace(/"/g, '');
    // edit: Suggestion from user71738 to handle background-images with additional settings

    var helper = resetHelperImages[bgImg]; // we cache our image instances
    if (!helper) {
      helper = $('<img>')
        .attr('src', bgImg)
        .css({
          position: 'absolute',
          left: '-5000px'
        }) // make it invisible, but still force the browser to render / load it
        .appendTo('body')[0];
      resetHelperImages[bgImg] = helper;
      setTimeout(function() {
        helper.src = bgImg;
      }, 10);
      // the first call does not seem to work immediately (like the rest, when called later)
      // i tried different delays: 0 & 1 don't work. With 10 or 100 it was ok.
      // But maybe it depends on the image download time.
    } else {
      // code part from: http://stackoverflow.com/a/21012986/1520422
      helper.src = bgImg;
    }
  }
  // force repaint - otherwise it has weird artefacts (in chrome at least)
  // code part from: http://stackoverflow.com/a/29946331/1520422
  elem.css("opacity", .99);
  setTimeout(function() {
    elem.css("opacity", 1);
  }, 20);
}
.myBgImageClass {
  background-image: url('http://i410.photobucket.com/albums/pp184/OllieMarchant/Countup.gif');
  width: 100px;
  height: 150px;
  background-size: 100%;
  background-repeat: no-repeat;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="myBgImageClass"></div>
<button onclick="restartAnimation($('.myBgImageClass'))">restart</button>

вы рассматривали использование одного и того же изображения, дважды называемого blink.gif и blink2.gif, добавляя для них два класса и переключаясь между классами?

<div id="face">
    <div id="eyes"></eyes>
</div>

.blink {
    background-image:url('blink.gif');
}

.blink2 {
    background-image:url('blink2.gif');
}

function MakeBlink()
{
   if ($('#eyes').hasClass('blink'))
   {
      $('#eyes').removeClass('blink').addClass('blink2');
   } else
   {
     $('#eyes').removeClass('blink2').addClass('blink');
   }
}

просто потому, что мне все еще нужно это время от времени, я подумал, что чистая функция 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>

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

--Нико


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

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

обновление: кэширование браузера становится умнее о кэшировании фона URI данных изображения, в результате чего анимация не запускается. Я обнаружил, что теперь мне нужно добавить случайную строку кэширования в url-адрес данных (который согласно Схема DataURI, следует считать необязательным атрибутом. Протестировано в Chrome & IE Edge.)

увидеть его в действии:http://jsfiddle.net/jcward/nknLrtzL/10/

вот как это работает. Эта функция загружает изображения в base64-кодировке.

function toDataUrl(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    var reader = new FileReader();
    reader.onloadend = function() {
      callback(reader.result);
    }
    reader.readAsDataURL(xhr.response);
  };
  xhr.open('GET', url);
  xhr.responseType = 'blob'; // IE11, set responseType must come after .open()
  xhr.send();
}

тогда, в любое время, когда вы хотите чтобы перезапустить GIF-анимацию, измените background-image свойство none, затем строка base64 (в некоторых браузерах вам нужно повторно добавить ребенка, чтобы запустить обновление без setTimeout):

$div.css({backgroundImage: "none"});
$div.parent().add($div); // Some browsers need this to restart the anim
// Slip in a cache busting random number to the data URI attributes
$div.css({backgroundImage: "url("+img_base64.replace("image/gif","image/gif;rnd="+Math.random())+")"});

спасибо ответ на toDataURL функция (с исправлением для IE11.)


по какой-то причине это работает:

// Append the image to the page
var i = new Image();
i.src = 'some.gif';
document.body.appendChild(i);

// Now execute this line and the gif will restart
// (anywhere it appears on the page, including CSS backgrounds)
i.src = 'some.gif';

для этого требуется добавить на страницу фактический элемент image DOM, но вы можете скрыть его с помощью visibility: hidden. Это не требуется, чтобы изображение было загружено по сети несколько раз.

Я тестировал это только в Firefox и Chrome. Не уверен в других браузерах.


о ответ сообщение от Фредерик Лайтенбергер, Я нашел, что это работает чудесно.

однако он ломается, если ваше фоновое изображение имеет несколько слоистых частей, например:

background-image: url(https://upload.wikimedia.org/wikipedia/commons/5/53/Google_%22G%22_Logo.svg),
    radial-gradient(ellipse at center,
        rgba(255,255,255,1) 0%,
        rgba(255,255,255,1) 50%,
        rgba(255,255,255,0) 80%);

чтобы обойти это ограничение, я изменил строку, которая находит url фонового изображения, например:

var bgImg = style.backgroundImage.match(/url\(([^\)]+)\)/)[1].replace(/"/g, '');

это использует регулярное выражение для извлечения только части URL фонового изображения.

Я бы добавил Это в качестве комментария к связан ответа, но я нуб без репутации, поэтому был заблокирован от этого. Те адекваты рэп может понадобиться добавить строку для ответа.