优化基于 SVG 的精灵表,以便在(移动)浏览器中实现 CSS3 硬件 GPU 加速



在过去的一周里,我一直在帮助一位朋友在浏览器中尝试基于 SVG 的精灵表。我们希望提出一个理想的工作流程,以便在浏览器中准备、发布和运行高质量的动画图形。因此,理想情况下,拥有适用于小型智能手机屏幕、平板电脑、视网膜显示器和桌面浏览器的单一动画数据源。

从理论上讲,(基于矢量的(SVG 应该是理想的选择,但由于 SVG 通常不经常使用 - 我们决定对其进行测试。这个想法不是使用 SMIL SVG(所以没有基于 SVG 的动画(,而是创建一个动画精灵表(就像您通常使用光栅数据 PNG/JPG 一样(,但使用纯矢量(即.SVG(执行此操作。它有点大,但如果它能做到这一点 - 它甚至可以与更优化的东西一起工作。

此外,逐帧矢量动画可以为我们的工作流程做很多事情 - 它将允许我们使用Flash编辑器制作动画,然后将它们导出到SVG精灵表。

无论如何,结果出奇地好,但在某些方面也失败了(请注意,出于测试目的,我们只适用于基于 Webkit 的浏览器,即 Safari、Chrome、iOS 上的移动 Safari 和 Android ICS(。

CSS中,很容易为这样的精灵表触发硬件加速(至少在具有关键帧和步骤的现代浏览器中( - 您只需这样做:

background-image: url(my.svg);
-webkit-animation: walk 1s steps(12, end) infinite; 

要调用此处所示的基于关键帧的动画,请执行以下操作:

@-webkit-keyframes walk {
    from { -webkit-transform: translate3d(0, 0, 0); }
    to { -webkit-transform: translate3d(-100%, 0, 0); }          
}

使用translate3d应该让GPU启动,整个事情应该在iOS移动Safari和Android ICS浏览器中进行硬件加速。

令人惊讶的是,考虑到它是一种蛮力技术和相当大的矢量动画(测试为 600x600px(——整个事情都在飞。但它并不完美 - 它在起飞前在 Safari 中闪烁。在ICS浏览器中,它一直在闪烁,所以它并不真正可用。

因此,我们尝试了常用的技巧来消除闪烁,例如:

-webkit-transform: translateZ(0);    
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;

但这没有用。因此,我们尝试在内存中动态栅格化SVG,并使用-webkit-transform:scale3d(1,1,0(将其用作纹理,但这对以太坊没有帮助。

最后,我们只是将 SVG 替换为相同大小的渲染 PNG/JPG 精灵表,认为复杂的向量对浏览器来说太多了 - 但你猜怎么着?这是同样的问题 - 所以它根本不是 SVG 渲染 - 这是一个浏览器绘图问题。进一步证明这一点的是,如果我们将动画速度减慢到 1FPS - 闪烁仍然存在。

图像对于 GPU 来说太大了吗?我们是否已达到您在浏览器中轻松绘制/制作动画的性能限制(尤其是移动设备(?

我真的很感激关于如何摆脱闪烁的想法/技巧(特别是因为它的性能如此之快(。它只是一种有前途的技术 - 适应不同屏幕尺寸的高性能浏览器动画 - HTML5圣杯;)

通过一些优化,例如

<svg preserveAspectRatio="xMinYMax slice" viewBox="0 0 600 50">
还有一些CSS

魔术,我们能够让SVG完美地适应它的容器,并从单个CSS类改变它的大小。它真的会创造奇迹——但唉,闪烁。

无论如何 - 请在此处阅读更多相关信息,您也可以尝试一下

很酷的主意。

如何更改帧的 zindex,以便将图像分层在一起? 这可能会解决闪烁问题,因为在重绘期间,最后一帧仍然可见。 因此,您只需继续增加最新帧的 zindex 值。 当然,这是有限制的,您需要再次重置 zindex,但它可能会对减少闪烁产生重大影响。

我这里没有ICS可以检查一下,但是在iPhone 6上的iOS 5和Galaxy Nexus上的Jelly Bean 4.1.1上,动画看起来非常流畅,除了当我缩放时,此时我得到了一些闪烁的帧,然后它再次稳定下来。

这让我想起了一个类似的问题,我渲染到一个大画布上并在屏幕上转换它(在任何给定时间,大部分画布都在屏幕外(。

我当时的黑盒分析表明,这是一些优化,浏览器不会费心渲染屏幕外的内容,而是等到它变得可见,这完全违背了拥有大图像和硬件加速它的目的。

我的"解决方案"是-webkit-transform:将整个图像缩小到足够小,以确保它都适合屏幕(因此浏览器别无选择,只能渲染整个图像(,让它渲染,然后将其放大到我想要的大小。

(顺便说一句:为了向用户隐藏这种黑客行为,我最初尝试设置不透明度:0,以便预渲染不可见,但这似乎与屏幕外渲染具有相同的效果 - 它被优化了。最后,我将不透明度设置得非常低,并用几乎不透明的"加载"消息覆盖它,这意味着背景渲染肉眼不可见,但浏览器没有绝对可见/不可见的优化。不确定这是否矫枉过正,但它似乎适用于我的设置。

我很想知道类似的技术是否适合您。

最新更新