Перезапустите анимированный GIF как фоновое изображение. - PullRequest
16 голосов
/ 27 сентября 2011

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

Рассмотрим этот HTML-код:

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

И этот стиль:

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

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

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

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

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

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

Ответы [ 8 ]

17 голосов
/ 06 октября 2011

Вы можете получить анимированный 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"});
    }
})

Демонстрация этого в действии.

7 голосов
/ 07 августа 2013

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

3 голосов
/ 28 июня 2015

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

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

В моем решении я создаю вспомогательные изображения, которые добавляются в тело, но скрываются таким образом, что они по-прежнему отображаются браузером, но визуально не взаимодействуют со страницей с помощью 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>
1 голос
/ 01 февраля 2017

Существует альтернатива, которая не перезагружает 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.)

1 голос
/ 24 февраля 2015

Просто потому, что время от времени мне все еще нужно это, я подумал, что чистая функция 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 () выбирает имя изображения из идентификатора изображения.Это удобно, если вы когда-нибудь измените фактическую ссылку на изображение для данного идентификатора, поскольку вам не нужно помнить об изменении вызовов resetGiF ().

- Nico

1 голос
/ 27 сентября 2011

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

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

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

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

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

0 голосов
/ 09 января 2014

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

// 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. Не уверен насчет других браузеров.

...