15

作为一个实验,我试图在不使用画布对象的情况下在 JavaScript 中复制 AS3 的 Sprite 功能。我认为使用绝对定位的 div 并操作它们的 css 属性是一件轻而易举的事,但是在 Chrome 中,动画会引入奇怪的伪影(似乎是因为重绘问题)。

我找不到我做错了什么?事实上,代码非常简单。以下是我尝试过的一些没有帮助的点:

  • 使用相对定位的 div(而不是绝对定位。)
  • 使用边距(与顶部和左侧属性相反。)
  • 将对象直接附加到正文(而不是附加到容器 div。)
  • 使用 setTimeout(相对于 requestAnimationFrame)

你可以在这里看到一个简化的小提琴:http: //jsfiddle.net/BVJYJ/2/

编辑:http: //jsfiddle.net/BVJYJ/4/

在这里,您可以在我的浏览器上看到工件:

Chrome 中的工件

这可能是我的设置中的一个错误(Windows 7 64 位,Chrome 21.0.1180.75)。没有其他浏览器表现出这种行为。如果有人可以评论我可能做错了什么,我将不胜感激。我更好奇这背后的原因,而不是顺便说一句的解决方法。也就是说,欢迎任何解释。:)

编辑:示例代码中有一个错误导致使用 setTimeout,即使我认为使用了 RAF。requestAnimationFrame 解决了基本转换的问题,但问题仍然存在于 CSS 转换,例如旋转。

Chrome 中带有旋转变换的工件。

4

3 回答 3

28

我的 liteAccordion 插件也有同样的问题。可以通过在您正在制作动画的元素上将背面可见性设置为隐藏来修复它,您可以在此处看到:http: //jsfiddle.net/ZPQBp/1/

于 2012-08-18T23:56:28.783 回答
3

一些研究表明,setTimeout由于各种原因,这可能会导致问题。你真的应该使用requestAnimationFrame

计时器不精确到毫秒。以下是一些常见的计时器分辨率1

  • Internet Explorer 8 及更早版本的计时器分辨率为 15.625 毫秒
  • Internet Explorer 9 及更高版本的计时器分辨率为 4 毫秒。火狐
  • Safari 的计时器分辨率约为 10 毫秒。
  • Chrome 的计时器分辨率为 4 毫秒。

版本 9 之前的 Internet Explorer 的计时器分辨率为 15.625 ms 1,因此 0 到 15 之间的任何值都可以是 0 或 15,但仅此而已。Internet Explorer 9 将计时器分辨率提高到 4 毫秒,但在动画方面仍然不是很具体。

Chrome 的计时器分辨率是 4 毫秒,而 Firefox 和 Safari 是 10 毫秒。因此,即使您将时间间隔设置为最佳显示,您仍然只能接近您想要的时间。

参考:http ://www.nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestanimationframe/

setTimeout没有考虑浏览器中发生的其他事情。该页面可能隐藏在选项卡后面,在不需要时占用您的 CPU,或者动画本身可能已从页面滚动,从而再次不需要更新调用。Chrome 确实在隐藏选项卡中将 setInterval 和 setTimeout 限制为 1fps,但这并不是所有浏览器都依赖的。

其次,setTimeout仅在需要时更新屏幕,而不是在计算机能够更新时。这意味着你糟糕的浏览器必须在重绘整个屏幕的同时重绘动画,如果你的动画帧速率与屏幕的重绘不同步,它可能会占用更多的处理能力。这意味着更高的 CPU 使用率和计算机的风扇启动,或耗尽移动设备上的电池。Nicolas Zakas 在一篇相关文章中出色地解释了计时器分辨率对动画的影响 。

参考:http ://creativejs.com/resources/requestanimationframe/

于 2012-08-12T19:16:24.610 回答
1

它与亚像素定位有关。如果您四舍五入到最近的像素,您将不会看到这些渲染错误:

thisRef.block.style.left = Math.round((x + (mouseX - ox - x) * .125)) + "px";
thisRef.block.style.top = Math.round((y + (mouseY - oy - y) * .125)) + "px";
于 2012-08-12T19:22:15.543 回答