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

Posted

技术标签:

【中文标题】重新启动动画 GIF 作为背景图像【英文标题】:Restart animated GIF as background-image 【发布时间】:2011-11-25 23:59:28 【问题描述】:

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

考虑一下这个 html

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

还有这种风格:

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

我希望每次将 blink 类添加到 #eyes 时播放 blink.gif 动画,而不仅仅是第一次。

我希望这会起作用:

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


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

问题是 Firefox 和 WebKit 浏览器都不会在播放一次后再次播放背景图像 GIF 动画。添加/删除类 blink 仅在第一次时有效。

【问题讨论】:

@NoufalIbrahim 仅当它们被设置为循环时。 @Noufal Ibrahim — 他们可以做到,这取决于图片内设置的循环选项。 @Noufal 是的,但我不想要一个循环。我想在用户执行某个事件时重新启动动画。 在 2016 年,我已经能够通过在 Chrome 和 Safari 中重置源(或在两个图像之间切换)而不是 Firefox 或 Edge 来让它作为背景图像工作。它们仍然只会显示非循环动画的最后一帧。 【参考方案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');
   

【讨论】:

这将是两帧动画(“眨眼”)的方式。 Gif 动画可以通过点击键盘上的 Esc 按钮来取消。 真的需要不同的图像吗?我看不出 $('#eyes').removeClass('blink').addClass('blink'); 不起作用的原因 @Ivan — 大概 OP 希望通过闭上眼睑而不是消失来眨眼。 那么在这种情况下使用相同的图像会更好。如果没有预加载blink2.gif,那么背景会消失很长一段时间。如果我们使用相同的图像,那么只需删除和添加相同的类,这与删除和应用不同的类而不加载新图像所花费的时间相同。 我建议预加载blink2.gif,但它们应该是不同的名称,以确保浏览器不会认为没有样式更改,因此跳过动画【参考方案2】:

您可以通过重新加载动画 gif 来重播它。这对于带宽来说并不理想,尤其是在您的图像很大的情况下,但它会强制重新启动动画。

在我的示例中,我添加和删除了 onclick&lt;div id="animated"&gt;

$('#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 在行动中。

【讨论】:

为什么要在文件路径中添加随机数? 滞后 ? - 只需重置src 即可重新启动动画。 jsfiddle.net/Lqx2V @c69 强制它不使用浏览器缓存。没有这个 Webkit 就不会重新启动动画。 需要注意的是 $eyes.css('background-image', 'url(' + 'blink.gif?d=' + new Date().getTime() + ')' );足够的。无需使用辅助 img。 我只是在 URL 中添加了 '#' + Math.random(),它在使用缓存时重新启动了动画。使用 Chrome 38.0.2125.111 测试 '#' + Math.random() 使用 Chrome 42.0.2311.135 失败,但是 '?' + Math.random() 有效:-(【参考方案3】:

我发现您还可以在图片 src 的末尾添加 ?+Math.random(),它会重新加载 .gif。

【讨论】:

更好的是,您可以在 URL 中添加 '#' + Math.random(),然后大概浏览器不必重新加载它。我已经在 Chrome 中对此进行了测试,并且可以正常工作(从缓存中检索)。 @Abram,将 # 添加到 URL 而不是 ? 似乎不再起作用 FWIW【参考方案4】:

由于某种原因,这可行:

// 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 中测试过这个。不确定其他浏览器。

【讨论】:

【参考方案5】:

只是因为我仍然时不时需要这个,所以我认为我使用的纯 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() 调用。

--妮可

【讨论】:

【参考方案6】:

我将解决方案的几个部分组合成一个完整的解决方案,以解决(希望)所有问题:

确定元素的背景图片 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://***.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://***.com/a/21012986/1520422
      helper.src = bgImg;
    
  
  // force repaint - otherwise it has weird artefacts (in chrome at least)
  // code part from: http://***.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>

【讨论】:

@jnkb 是的,你是对的,它在 IE 中不起作用。也许所有浏览器的通用解决方案是下载并缓存图像的原始数据,然后从中创建一个data:-url 以重新启动动画。也许data:-url 缓存失效...这可能吗?【参考方案7】:

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

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

更新:浏览器缓存在缓存背景图像数据 URI 方面变得更加智能,导致动画无法重新开始。我发现我现在必须向数据 url 添加一个缓存破坏随机字符串(根据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字符串(在某些浏览器中,你需要重新添加child来触发更新而不需要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())+")");

感谢this answer 提供toDataURL 功能(已修复IE11。)

【讨论】:

这是最好的答案!【参考方案8】:

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

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

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 部分。

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

【讨论】:

我将您的改进添加到我的解决方案中。谢谢!

以上是关于重新启动动画 GIF 作为背景图像的主要内容,如果未能解决你的问题,请参考以下文章

重新启动 gif 动画而不重新加载文件

如何从头开始重新启动gif动画?框架

我希望我的关键帧动画在一段时间后重新启动

如何重新启动统一动画师?

.gif 图像作为源代码在 Windows kivy 程序中运行良好。通过 kivy Launcher 运行显示 gif 图像的背景

如何在xcode中使用图像文件作为启动图像而不将其名称更改为“Default.png”并将其重新导入到项目中?