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

发布于 2024-12-06 21:13:53 字数 584 浏览 1 评论 0原文

是否可以重新启动用作背景图像的 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 动画后都不会再次播放。添加/删除类闪烁仅在第一次有效。

Is it possible to restart an animated GIF used as background-image?

Consider this HTML:

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

And this style:

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

I would like the blink.gif animation to play every time I add the class blink to #eyes, not just the first time.

I expected this to work:

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

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

The problem is that both Firefox and WebKit browser do not play a background-image GIF animation again once it has played once. Adding/removing the class blink only works the first time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

上课铃就是安魂曲 2024-12-13 21:13:53

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

在我的示例中,我添加和删除了

onclick

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

实际演示

You can get the animated gif to replay by reloading it. This isn't ideal for bandwidth, especially if your image is large, but it will force a restart of the animation.

In my example I'm adding and removing it onclick of <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"});
    }
})

Demo of it in action.

征棹 2024-12-13 21:13:53

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

I've found you can also add a ?+Math.random() to the end of the picture src and it'll reload the .gif.

流心雨 2024-12-13 21:13:53

有一种替代方法可以避免每次都重新加载 GIF 并浪费带宽。

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

更新:浏览器缓存在缓存背景图像数据 URI 方面变得越来越智能,导致动画无法重新开始。我发现我现在必须向数据 url 添加一个缓存破坏随机字符串(根据 DataURI Scheme< /a>,应该被认为是一个可选属性。在 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 进行了修复。)

There is an alternative that does not reload the GIF every time and waste bandwidth.

It involves storing the GIF as Base64 in memory (circumventing browser cache), and uses the FileReader API (which seems to be supported in all modern browsers). Note that loading images this way is subject to cross-origin policy (unlike the image reload solutions.)

Update: Browser caching is getting smarter about caching background image data URI's, causing the animation not to start over. I found I had to add a cache-busting random string to the data url now (which according to the DataURI Scheme, should be considered an optional attribute. Tested in Chrome & IE Edge.)

See it in action: http://jsfiddle.net/jcward/nknLrtzL/10/

Here's how it works. This function loads the image as a Base64-encoded string.

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();
}

Then, any time you want to restart the GIF animation, change the background-image property to none, then the base64 string (in some browsers, you need to re-add the child to trigger the update without a 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())+")"});

Thanks to this answer for the toDataURL function (with fix for IE11.)

在你怀里撒娇 2024-12-13 21:13:53

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

  • 确定元素的背景图像 URL(来自 css background-image
  • 触发该图像的重新启动,而无需从网络重新加载它
  • 在所有位置重新启动它(无需单独触摸每个位置)
  • 确保重新启动动画后重新绘制目标而没有伪影

在我的解决方案中,我创建了辅助图像,这些图像添加到主体中,但以某种方式隐藏,以便它们仍然存在渲染者浏览器但不会使用 position:absolute; 与页面进行视觉交互左:-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>

I combined several parts of the solution to make one whole solution that solves (hopefully) all problems:

  • Determine the background-image URL of an element (from css background-image)
  • Trigger a restart for that image WITHOUT reloading it from the web
  • Restarting it in all places (without touching each individually)
  • Making sure the target is repainted without artifacts after restarting the animation

In my solution i create helper images that are added to the body but hidden in a way so they are still rendered by the browser but won't interact with the page visually using position: absolute; left: -5000px;.

A reference to our helper images is cached in resetHelperImages so we can reuse them for the same image in subsequent calls.

I am using jQuery for my example, but it could be adapted to work without jQuery, too.

Tested in: Chrome (Version 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>

挥剑断情 2024-12-13 21:13:53

您是否考虑过使用同一个图像两次(称为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');
   }
}

Have you considered using the same image twice called blink.gif and blink2.gif, adding two classes for them and toggling between classes?

<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');
   }
}
临走之时 2024-12-13 21:13:53

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

——妮可

Just because I still need this every now and then I figured the pure JS function I use might be helpful for someone else. This is a pure JS way of restarting an animated gif, without reloading it. You can call this from a link and/or document load event.

<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>

On some browsers you only need to reset the img.src to itself and it works fine. On IE you need to clear it before resetting it. This resetGif() picks the image name from the image id. This is handy in case you ever change the actual image link for a given id because you do not have to remember to change the resetGiF() calls.

--Nico

原野 2024-12-13 21:13:53

由于某种原因,这是可行的:

// 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: hide 隐藏它。这不需要通过网络多次下载图像。

我只在 Firefox 和 Chrome 中测试过。不确定其他浏览器是否如此。

For some reason this works:

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

This requires an actual image DOM element to be appended to the page, but you can hide it with visibility: hidden. This doesn't require the image to be downloaded over the network multiple times.

I only tested this in Firefox and Chrome. Not sure about other browsers.

凉城已无爱 2024-12-13 21:13:53

关于这个答案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%);

为了解决此限制,我修改了查找背景图像 url 的行,如下所示:

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

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

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

Regarding this answer posted by Frederic Leitenberger, I found it to work wonderfully.

However, it breaks down if your background-image has multiple, layered parts, like this:

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

To get around this limitation, I modified the line that finds the background image url, like so:

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

This uses a regular expression to extract just the URL portion of the background-image.

I would have added this as a comment to the linked answer, but I'm a noob without reputation, so was blocked from doing so. Those with adequate rep may want to add the line to the actual answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文