重新启动动画 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
的 <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 在行动中。
【讨论】:
为什么要在文件路径中添加随机数? 滞后 ? - 只需重置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(来自 cssbackground-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 图像作为源代码在 Windows kivy 程序中运行良好。通过 kivy Launcher 运行显示 gif 图像的背景