使用 transform3D 造成网页闪动的底层原因剖析
Tag Archives: transform3d
关于使用transform3D等造成网页闪动的底层原因剖析(webkit tiled layer重绘)
WWDC2012大会上一共放出了4个和Safari on iOS相关的技术分享,分别是(链接为对应的静态pdf版keynote):
session 600:Debugging uiwebviews and websites on iOS
session 601:Optimizing web content in uiwebviews and websites on iOS
session 602:Delivering web content on high resolution displays
session 604:Advanced effects with html5 media technologies
今天抽空看了两个,600和601,其中600讲了iOS6带来的新的web inspector,功能的确强大,不光可以调试设备,还可以直接调试模拟器,甚至是app中的uiwebview,一看便知,并无甚复杂之处。
601中干货颇多,尤其是涉及到浏览器底层实现的webkit layer,吸引我反复看了几遍(这个只看静态keynote完全看不懂的)。webkit layer理论完美解释并解决了各种类似transform3D引起的网页闪动的问题。相信这个问题很多移动开发者都碰到过,却无从得知底层原因而不能从根本上解决和避免这一问题。下面以我个人的理解介绍一下视频中的要点:
dom结构很简单,但它实际上被渲染成了3个层(webkit layer):
为什么要分层呢?演讲者解释到(个人理解):webkit并不会真正在3d空间渲染页面。如果有z轴方向上的变动,通过将这些元素绘制到不同的层上,然后直接挪动层,可以更好地利用GPU的计算能力,避免繁重的绘制,提高效率。但并不是所有的元素都会分层,webkit的分层依据为:
即:
1、主页面(body)始终为一个tiled layer
2、与绘图直接相关的如canvas,video等元素
3、3D变换:translte3D,rotate3D,translazeZ等
4、其它增强内容的样式如:
filters,masks,reflections,opacitys,transitions,animations
5、其它一些特例如(iOS5以上):
position:fixed,-webkit-overflow-scroll:touch
6、所有覆盖在现有层上的元素都会形成一个新层
分层虽然提高了绘制效率,但它会消耗大量内存(与元素绘制面积线性相关),如下图:
当单个layer的内存消耗超过一定程度时,其会被处理为tiled layer,即将层再细分为“瓦块”。例如一个较长的页面,在向下滚动时,我们可以观察到页面内容的闪动。因为此时webkit为了控制内存,会只绘制当前可视的那个“瓦块”,滚动加载时,需要从内存中交换数据,重新绘制新的内容“瓦块”,导致了这样一个闪动。
但是如何查看这样一些细节呢?前端开发者如何获知layer的实时情况呢?事实上,safari并没有提供这样的inspect能力。此时需要借助uiwebview控件:
使用这样一个参数,即会给层标记上不同颜色的border。其中尤其需要注意的即为tiled layer,它是影响性能的关键。
页面上有两个滑动图廊的实例:
其实现略有差异:上面那个是使用了iOS5原生的-webkit-overflow-scroll:touch,下面的那个则是常见的touch事件结合translate3D。两者都很流畅,但都有致命的缺陷:
上面这个在页面放大和缩小时会有明显的闪动。而原因也一目了然–画廊外层容器border为橘黄色,即此layer尺寸过大,被处理成了一个tiled layer,放大缩小时需要交换内存重绘,导致了闪动。
下面这个则在松开手指即touchend事件发生时会闪动。而截图中也能看到,在拖动时,内部也出现了橘黄色的border,因为此时对画廊列表整体应用了translate3D,同样也变为一个尺寸超大的tiled layer,松开手时,画廊快速回位,导致了重绘闪动。
原因终于大白天下,那么如何解决呢?演讲者提供了一种参考方案:既然因为layer太大,则完全可以考虑将layer拆分为小的layer。例如,给每张图都加上translatez属性,使每张图都成为一个独立的小的layer,此时滑动或者缩放再也不会引发闪动。
最后,总结了一下webkit layer的优缺点
优点:
1、有选择地使用,可以使动画更平滑
2、如果硬件对webkit layer有优化,则用户交互会非常流畅
缺点:
1、滥用层会导致极大的内存消耗,并影响性能
2、尺寸过大的层会被处理为tiled layer,导致内容闪动
3、增加了GPU计算,消耗更多电力
以上全部为个人理解,欢迎交流指正!
这一部分的演讲者为Joseph Pecoraro,Safari on iOS的工程师。感谢他细致的讲解!