重新启动动画GIF作为背景图像

时间:2011-09-27 12:08:34

标签: jquery html css background-image animated-gif

是否可以重新启动用作background-image的动画GIF?

考虑这个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动画。添加/删除类闪烁仅适用于第一次。

8 个答案:

答案 0 :(得分:17)

你可以通过重新加载动画gif来重播。这对于带宽来说并不理想,特别是如果您的图像很大,但它会强制重新启动动画。

在我的示例中,我添加并删除onclick <div id="animated">的{​​{1}}:

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

Demo of it正在行动中。

答案 1 :(得分:7)

我发现你还可以在图片src的末尾添加?+Math.random(),然后重新加载.gif文件。

答案 2 :(得分:3)

我结合了解决方案的几个部分,制作了一个解决(希望)所有问题的整个解决方案:

  • 确定元素的背景图片网址(来自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>

答案 3 :(得分:1)

您是否考虑使用两次相同的图像,名为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');
   }
}

答案 4 :(得分:1)

仅仅因为我仍然需要这个时不时我想我使用的纯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重置为自身,它就可以正常工作。在IE上,您需要在重置之前清除它。此resetGif()从图像ID中选择图像名称。如果您更改了给定ID的实际图像链接,这很方便,因为您不必记住更改resetGiF()调用。

- 尼科

答案 5 :(得分:1)

有一种替代方案,每次都不会重新加载GIF并浪费带宽。

它涉及将GIF作为Base64存储在内存中(绕过浏览器缓存),并使用FileReader API(似乎是supported in all modern browsers)。请注意,以这种方式加载图像需遵循跨源策略(与图像重新加载解决方案不同。)

更新:浏览器缓存在缓存背景图片数据URI方面越来越智能,导致动画无法重新开始。我发现我必须立即在数据网址中添加缓存清除随机字符串(根据DataURI Scheme,应该将其视为可选属性。在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 protocol Subject { func register(observer: Observer) func remove(observer: Observer) func notifyObservers() } protocol Observer { func update(temperature: Double, humidity: Double, pressure: Double) } protocol DisplayElement { func display() } class WeatherData: Subject { var observers: [Observer] var temperature: Double! var humidity: Double! var pressure: Double! init() { observers = [] } func register(observer: Observer) { observers.append(observer) } func remove(observer: Observer) { } func notifyObservers() { for obs: Observer in observers { obs.update(temperature: temperature, humidity: humidity, pressure: pressure) } } } 函数(修复了IE11。)

答案 6 :(得分:0)

出于某种原因,这有效:

// 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 :(得分:0)

关于this answer发布的Frederic Leitenberger,我发现它工作得非常好。

但是,如果你的背景图片有多个分层的部分,它会崩溃,如下所示:

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%);

为了解决这个限制,我修改了找到背景图片网址的行,如下所示:

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

这使用正则表达式来仅提取背景图像的URL部分。

我会将此作为评论添加到linked answer,但我是一个没有声望的菜鸟,因此被禁止这样做。具有足够代表的人可能希望将该行添加到实际答案中。