CSS3硬件加速也有坑

常听人说:html

移动端要想动画性能流畅,应该使用3d硬件加速前端

最近深刻了解了一些浏览器内核的细节,感受这里面其实有坑啊。。。html5

事情要从最近看的《WebKit技术内幕》提及,第二章介绍了网页的结构,其中提到了Webkit硬件加速的方式,会把须要渲染的元素放到特定的『Composited Layer』中,在chrome的控制台能够这样开启:git

选择『Show composited layer borders』之后,就能看到有动画3d变换的元素会被一个黄色的边框圈起来,表示放到了一个新的『复合层(composited layer)』中渲染,大概长这个样子:github

蓝色的细线是浏览器渲染时候的『瓦片』,浏览器绘制页面的时候只会绘制可视区域必定范围内的瓦片,以节省性能开销,而黄色的边框框起来的,就表明了这个元素被放到特殊的复合层中渲染,跟主文档不在一个层中web

而后我以为这个视图挺有意思的,就拿来看了一下国内某项目,不看不知道,一看被吓尿:chrome

这个项目何时搞成全部元素都用3d加速了?!后端

仔细排查了这些被框出来的元素,彻底没有任何须要复合层渲染的迹象,我真是哔了狗了。。。我开始一个个删除元素,简化代码,很快就发现,原来罪魁祸首在这里:浏览器

头部的那个轮播动画元素的存在竟然会致使下面全部相对和绝对定位的元素都被放到复合层中。。。markdown

查了一些 资料

层建立标准

什么状况下能使元素得到本身的层?虽然 Chrome 的启发式方法(heuristic)随着时间在不断发展进步,可是从目前来讲,知足如下任意状况便会建立层:

  • 3D 或透视变换(perspective transform) CSS 属性
  • 使用加速视频解码的 元素
  • 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
  • 混合插件(如 Flash)
  • 对本身的 opacity 作 CSS 动画或使用一个动画 webkit 变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在本身的层里)
  • 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)

主要是最后一条,我以为它的中文翻译不是很准确,原文实际上是:

Element has a sibling with a lower z-index which has a compositing layer (in other words the it’s rendered on top of a composited layer)

这句话的意思是,若是有一个元素,它的兄弟元素在复合层中渲染,而这个兄弟元素的z-index比较小,那么这个元素(不论是不是应用了硬件加速样式)也会被放到复合层中。

最可怕的是,浏览器有可能给复合层以后的全部相对或绝对定位的元素都建立一个复合层来渲染,因而就有了上面那个项目截图的那种效果。以前一直奇怪为何这个页面滚动很卡,明明没有多少DOM,如今看来问题就在这里了!

因而乎我写了一个页面,让你们看看这东西到底有多大威力:

fouber.github.io/test/layer/

我在上面这个页面中放置了一个h1标题,应用了translate3d动画,使得它被放到composited layer中渲染,而后在这个元素后面建立了2000个list,每一个list中都有一个图片,一个标题和一个日期显示,其中图片和日期显示是绝对定位,父容器li是相对定位,而后,各位能够按照前述的说明打开chrome的『show composited layer borders』选项看看这个页面的内容复合层分布:

就是这个鸟样子,很难想象,这样的页面滚动起来会卡成什么样。我用的是mac机器,快速拖动滚动条chrome已经很是吃力了,而后我写了一个简单的滚动条移动操做:

setInterval(‘document.body.scrollTop++’, 0);

而后用timeline抓一下页面性能:

一次『Composite Layers』的计算竟然要 96.206 ms !!这仍是在个人mac系统上哦,手机上真的会卡出翔。

我在页面上放置了一个开关『为动画元素设置z-index』,这个checkbox点击以后,会用js给那个动画的h1元素加 position:relative 和 z-index: 1 ,这种作法的原理是人为提高动画元素的z-index,让浏览器知道这个元素的层排序,就不会很傻逼的把其余z-index比它高的元素也弄到复合层中了,看看这个效果:

仅仅给动画元素设置一个高一些的z-index,就能解决这种无厘头增长复合层的问题,略无语。。。搞定以后,再用滚动条移动函数抓一下页面性能:

彻底恢复正常了有木有!

你们能够用支持『硬件加速』的『安卓』手机浏览器测试上述页面,给动画元素加z-index先后的性能差距很是明显。

不过也不是全部浏览器都有这个问题,我在mac上的Safari、firefox都没有明显差别,安卓手机上的QQ浏览器好像也正常,猎豹、UC、欧朋、webview等浏览器差距明显,更多测试就靠你们来发现吧。

最后总结一下:

使用3D硬件加速提高动画性能时,最好给元素增长一个z-index属性,人为干扰复合层的排序,能够有效减小chrome建立没必要要的复合层,提高渲染性能,移动端优化效果尤其明显。

你们能够如今就排查一下这类问题,尤为是用了轮播、动画loading的页面,出现这问题很常见。另外推荐在追查性能问题的时候打开『show composited layer borders』选项,若是页面有不少黄色的框确定是不对的。

最后,再次推荐一下《Webkit技术内幕》这本书。浏览器内核之于前端工程师,就如同操做系统之于后端工程师,毕竟是咱们程序运行的宿主环境,多了解一些,不少问题容易想通。

若是有人让你推荐前端技术书,请让他看这个列表 ->《 经典前端技术书籍 1 赞 1 收藏 评论
相关文章
相关标签/搜索