如何开启GPU加速
RenderLayer(负责 DOM 子树),GraphicsLayer(负责 RenderLayer 的子树),其中 GraphicsLayer 层是作为纹理(texture)上传给 GPU 的。
方法:
- opacity
- transform
transform:translateZ(0); // 设置这个属性不影响动画
GPU与CPU?
- GPU
主要做图形处理,渲染顶点,图像变换,吞吐大,运算大,但是对数据流处理能力没有CPU好
- CPU
对复杂的数据流控制更好
了解页面卡顿的原因
- 16ms优化
大多数设备刷新频率60HZ(60次/s),每一次刷新耗时16.6ms(1000/60)
所以在浏览器的每一帧画面要在16ms内完成,这样看起来页面才不会卡顿
- 浏览器的每一帧做什么?
javascript -> style -> layout -> paint -> composite
js: 实现动画,DOM元素的操作
style: 计算DOM应该运用什么css规则
layout: 计算每个DOM的位置和大小,每个DOM位置变化都要reflow
paint: 在多个层上绘制DOM元素的文字,颜色,图像等
composite:渲染层合并,合并图层显示到屏幕上(layer终极)
GPU为什么能加速
关键: 避免layout paint这两个最耗时的步骤,
javascript -> style -> layout -> paint -> composite
javascript -> style -> composite
可以让每一帧画面在16ms内完成,所以看起来不卡顿
60帧最适合人眼交互,低于30fps一下的动画,让人感觉明显变得卡顿
- 关于不同类型的层
chrome中包含两个层:
渲染层(RenderLayer)
图层(GraphicsLayer,GPU加速触发创建)
怎么触发:
1 3D 或透视变换(perspective、transform) CSS 属性
2 使用加速视频解码的 元素
3 拥有 3D (WebGL) 上下文或加速的 2D 上下文的 元素
4 混合插件(如 Flash)
5 对自己的 opacity 做 CSS 动画或使用一个动画变换的元素
6 拥有加速 CSS 过滤器的元素
7 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
8 元素有一个 z-index 较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)
- 为什么能避免layout和paint?
开启GPU后,会将经常变换的DOM提升单独的图层(GraphicsLayer),就不会改变自己和周围的DOM布局
所以每一帧内,浏览器就不用不断的回流,重绘
只需要第一次布局元素,位图绘入元素,将位图同步到绘制器,加载到GPU内存,然后位图从GPU内存绘制到屏幕上
GPU加速这么好,那么都用GPU加速行不行?
不行,因为GPU不仅要发送渲染图层到GPU,还要存储他们,一边稍后动画中使用
由此,没创建一个新的渲染层,就要消耗内存和复杂的层管理,特别对于移动设备来说,过多的GPU加速会导致页面卡顿合闪退
GPU导致闪退坑
z-index导致创建意外的复合层
A:{
z-index: 10 //开启的GPU
}
B:{
z-index: 15 //没有开启GPU
}
由于B在A上面,所以B会被默认开启GPU,导致额外创建新的合成层,过多会导致手机页面闪退,卡顿
渲染一个网页需要两个线程完成
- 主线程
- compositor thread(绘制线程)
未开启GPU加速
#### 开启GPU加速
- GPU擅长
- 绘制位图到屏幕上
- 可不断的绘制相同的位图
- 将同一位图进行位移、旋转、缩放 (就是动画)
优化案列
- 优化前
@keyframes animation {
0% {
top: 10px;
}
50% {
top: 30px;
}
}
- 优化后
通过开启GPU加速,避免layout,paint,让动画更流畅
@keyframes animation {
0% {
transform: translateY(10px);
}
50% {
transform: translateY(30px);
}
}