Подтвердить что ты не робот

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

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

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

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

И этот стиль:

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

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

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

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

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

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

4b9b3361

Ответ 1

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

В моем примере я добавляю и удаляю его onclick из <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"});
    }
})

Демо-версия в действии.

Ответ 2

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

Ответ 3

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

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

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

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

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

Протестировано в: Chrome (версия 43.0.2357.130 м)

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>

Ответ 4

Рассматривали ли вы использование одного и того же изображения, дважды называемого 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');
   }
}

Ответ 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

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

// 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';

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

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

Ответ 7

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

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

Смотрите в действии: http://jsfiddle.net/jcward/nknLrtzL/2/

Вот как это работает. Эта функция загружает изображение в виде кодированной в 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
$div.css({backgroundImage: "url("+img_base64+")"});

В некоторых случаях для запуска

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

Ответ 8

Что касается этого ответа, опубликованного Фредериком Лейтенбергером, я нашел, что он работает чудесно.

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

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-адреса фонового изображения.

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