雷锋网按:本文作者 被单,原载于 凹凸实验室,雷锋网(公众号:雷锋网)获授权转载。
众所周知,网页不仅应该被快速加载,同时还应该流畅运行,比如快速响应的交互,如丝般顺滑的动画……
一. GPU 加速能做什么?
首先我们要了解什么是 16ms 优化
-
大多数设备的刷新频率是 60 次/秒,(1000/60 = 16.6ms)也就说是浏览器对每一帧画面的渲染工作要在 16ms 内完成,超出这个时间,页面的渲染就会出现卡顿现象,影响用户体验。
-
浏览器在一帧里面,会依次执行以下这些动作。减少或者避免 layout,paint 可以让页面不卡顿,动画效果更加流畅。
1. JavaScript:JavaScript 实现动画效果,DOM 元素操作等。
2. Style(计算样式):确定每个 DOM 元素应该应用什么 CSS 规则。
3. Layout(布局):计算每个 DOM 元素在最终屏幕上显示的大小和位置。由于 web 页面的元素布局是相对的,所以其中任意一个元素的位置发生变化,都会联动的引起其他元素发生变化,这个过程叫 reflow。
4. Paint(绘制):在多个层上绘制 DOM 元素的的文字、颜色、图像、边框和阴影等。
5. Composite(渲染层合并):按照合理的顺序合并图层然后显示到屏幕上。
利用 GPU 加速优先使用渲染层合并属性,避免 layout,paint。
从上图可以看出,可以通过改变元素的 transform 实现移动,伸缩变换而非改变物体的 left,top,width,height 避免 layout,paint。让动画效果更加流畅。
优化
二. GPU 是什么,如何用 Chrome devtools 进行分析 debug?
浏览器渲染一个页面大致是按照下面这个步骤执行。
1. 获取 DOM 并将其分割为多个层(RenderLayer)
2. 将每个层栅格化,并独立的绘制进位图中
3. 将这些位图作为纹理上传至 GPU
4. 复合多个层来生成最终的屏幕图像(终极 layer )。
Chrome 开启查看 renderlayer
按上面的步骤之后,即可看到
1. 黄色边框:有动画 3d 变换的元素,表示放到了一个新的复合层(composited layer)中渲染
2. 蓝色的栅格:这些分块可以看作是比层更低一级的单位,这些区域就是 RenderLayer
打开一个页面,如果该页面的黄色边框很多,那么肯定要查看一下原因了
Chrome 查看 layer
-
打开 timeline 进行录制,选中 timeline 的某一帧,然后选择下面的 layer ,可以左右拖动该模块出现 3d。
我们可以看到一个页面实际是像下面一样组成的
-
从上图不难理解,虽然我们最终在浏览器上看到的只是一个复印版,即最终只有一个层。类似于PhotoShop软件中的“图层”概念,最后合并所有可视图层,输出一张图片到屏幕上。但实际上一些dom会因为一些规则被提升成独立的层(开启 GPU 加速),一旦被独立出来之后,便不会再影响其他dom的布局,因为它改变之后,只是“贴上”了页面。
根据这个优点,我们可以把页面中一些布局经常变换的dom(动画)提升到独立的层。那么,浏览器在之后的 16ms 中,只需进行下面的几个步骤。
三. 如何开启 GPU 加速?
目前下面这些因素都会引起Chrome创建合成层:
1. 3D 或透视变换(perspective,transform) CSS 属性
2. 使用加速视频解码的video元素
3. 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 canvas 元素
4. 混合插件(如 Flash)
5. 对自己的 opacity 做 CSS 动画或使用一个动画 webkit 变换的元素
6. 拥有加速 CSS 过滤器的元素
7. 元素A有一个 z-index 比自己小的元素B,且元素B是一个合成层(换句话说就是该元素在复合层上面渲染),则元素A会提升为合成层。
上面7点都非常容易理解,在日常开发中,最容易出现问题的是第7点
四. GPU 加速隐藏的坑–隐式合成
-
元素A有一个 z-index 比自己小的元素B,且元素B是一个合成层(换句话说就是该元素在复合层上面渲染)
拿实际项目举个栗子,我们按照上面的步骤开启 layer borders
尚未给上图右手添加高层级的 z-index 时,整个页面在移动端打开后闪退。而添加了 z-index 之后,页面正常显示,不闪退了。
仔细看上面的 gif ,仅仅改变了 z-index ,就会改变大批数量的层(黄色边框)
为什么 z-index 力量这么大?
我们来看一个栗子,B 在做动画,理所当然把B提到单独的合成层。减少重绘。
按照上图,我们遇到一个逻辑问题,元素B应该在单独的合成层上,并且屏幕的最终图像应该在 GPU 上组成。但是A元素在B元素的顶部,我们没有指定提升A元素自身层级的东西。那么浏览器会做什么?它将强制为元素A创建一个新的合成图层。
这样,A和B都被提升到单独的复合层。
因此,使用 GPU 加速提升动画性能时,最好给当前动画元素增加一个高一点的 z-index 属性,人为干扰复合层的排序,可以有效减少 Chrome 创建不必要的复合层,提升渲染性能。
注意:GPU 不仅需要发送渲染层图像到 GPU ,而且还需存储它们,以便稍后在动画中重用。别盲目创建渲染层,一定要分析其实际性能表现。因为创建渲染层是有代价的,每创建一个新的渲染层,就意味着新的内存分配和更复杂的层的管理。对于使用移动设备的用户来说是很坑的。移动设备没有台式机那么多的内存。过多的 GPU 加速会引起页面卡顿甚至闪退。
找到 layers,点击当前层,在右边查看占用的 memory(内存)
总结
整篇文章介绍了下面几个部分
● GPU 加速能做什么
● GPU 是什么,如何用 Chrome devtools 进行分析 debug?
● 如何开启 GPU 加速?
● GPU 加速隐藏的坑–隐式合成
参考:
http://www.jianshu.com/p/a32b890c29b1
雷锋网相关阅读:
黄仁勋亲自撰文怼上 TPU:P40速度比你快 2 倍,带宽是你的 10 倍
雷锋网版权文章,未经授权禁止转载。详情见。
原创文章,作者:kepupublish,如若转载,请注明出处:https://blog.ytso.com/80484.html