【问题标题】:Restart animated GIF as background-image重新启动动画 GIF 作为背景图像
【发布时间】: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 来让它作为背景图像工作。它们仍然只会显示非循环动画的最后一帧。

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


【解决方案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://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>

      【讨论】:

      • @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,但我是一个没有声誉的菜鸟,因此被阻止这样做。那些有足够代表的人可能希望在实际答案中添加该行。

      【讨论】:

      • 我将您的改进添加到我的解决方案中。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-28
      • 1970-01-01
      • 2011-03-12
      • 2021-01-31
      • 2010-10-23
      相关资源
      最近更新 更多