从浏览器渲染层面解析css3动效优化原理
source link: https://my.oschina.net/o2team/blog/5268715
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
在h5开发中,我们经常会需要实现一些动效来让页面视觉效果更好,谈及动效便不可避免地会想到动效性能优化这个话题:
- 减少页面DOM操作,可以使用CSS实现的动效不多出一行js代码
- 使用绝对定位脱离让DOM脱离文档流,减少页面的重排(relayout)
- 使用CSS3 3D属性开启硬件加速
那么,CSS3与动效优化有什么关系呢,本文将从浏览器渲染层面讲述CSS3的动效优化原理
浏览器页面展示过程
首页,我们需要了解一下浏览器的页面展示过程:
- Javascript:主要负责业务交互逻辑。
- Style: 根据 CSS 选择器,对每个 DOM 元素匹配对应的 CSS 样式。
- Layout: 具体计算 DOM 元素显示在屏幕上的大小及位置。
- Paint: 实现一个 DOM 元素的可视效果(颜色、边框、阴影等),一般来说由多个渲染层完成。
- Composite: 当每个层绘制完成后,浏览器会将所有层按照合理顺序合并为一个图层,显示到屏幕。 本文我们将重点关注
Composite
过程。
浏览器渲染原理
在讨论 Composite
之前,我们还需要了解一下浏览器渲染原理
从该图中,我们可以发现:
DOM 元素
与Layout Object
存在一一对应的关系- 一般来说,拥有相同坐标空间的
Layout Object
属于同一个Paint Layer (渲染层)
,通过position、opacity、filter
等 CSS 属性可以创建新的 Paint Layer - 某些特殊的
Paint Layer
会被认为是Composite Layer (合成层/复合层)
,Composite Layer 拥有单独的Graphics Layer (图形层)
,而那些非 Composite Layer 的 Paint Layer,会与拥有 Graphics Layer 的父层共用一个
Graphics Layer
我们日常生活中所看到屏幕可视效果可以理解为:由多个位图通过 GPU
合成渲染到屏幕上,而位图的最小单位是像素。如下图:
那么位图是怎么获得的呢,Graphics Layer
便起到了关键作用,每个 Graphics Layer
都有一个 Graphics Context
, 位图是存储在共享内存中,Graphics Context
会负责将位图作为纹理
上传到GPU
中,再由GPU进行合成渲染。如下图:
CSS在浏览器渲染层面承担了怎样的角色
大多数人对于CSS3的第一印象,就是可以通过3D(如transform)属性来开启硬件加速,许多同学在重构某一个项目时,考虑到动画性能问题,都会倾向:
- 将2Dtransform改为3Dtransform 2.将 left ( top、bottom、right )的移动改为 3Dtransform
但开启硬件加速的底层原理
其实就在于将 Paint Layer 提升到了 Composite Layer
以下的几种方式都用相同的作用:
- 3D属性开启硬件加速(3d-transform)
- will-change: (opacity、transform、top、left、bottom、right)
- 使用fixed或sticky定位
- 对opacity、transform、filter应用了 animation(actived) or transition(actived),注意这里的 animation 及 transition 需要是处于
激活状态
才行
我们来写两段 demo
代码,带大家具体分析一下实际情况
demo1. 3D属性开启硬件加速(3d-transform)
.composited{
width: 200px;
height: 200px;
background: red;
transform: translateZ(0)
}
</style>
<div class="composited">
composited - 3dtransform
</div>
可以看到是因为使用的CSS 3D transform,创建了一个复合层
demo2. 对opacity、transform、filter应用 animation(actived) or transition(actived)
<style>
@keyframes move{
0%{
top: 0;
}
50%{
top: 600px;
}
100%{
top: 0;
}
}
@keyframes opacity{
0%{
opacity: 0;
}
50%{
opacity: 1;
}
100%{
opacity: 0;
}
}
#composited{
width: 200px;
height: 200px;
background: red;
position: absolute;
left: 0;
top: 0;
}
.both{
animation: move 2s infinite, opacity 2s infinite;
}
.move{
animation: move 2s infinite;
}
</style>
<div id="composited" class="both">
composited - animation
</div>
<script>
setTimeout(function(){
const dom = document.getElementById('composited')
dom.className = 'move'
},5000)
</script>
这里我们定义了两个keyframes(move、opacity)
,还有两个class(both、move)
,起初 #composited
的 className = 'both'
,5秒延时器后,className = 'move'
,我们来看看浏览器的实际变化。
起初:#composited 创建了一个复合层,并且运动时 fps 没有波动,性能很稳定
5秒后:复合层消失,运动时 fps 会发生抖动,性能开始变得不再稳定
如何查看复合层及fps
在浏览器的 Dev Tools
中选择 More tools
,并勾选 Rendering
中的 FPS meter
动画性能最优化
之前,我们提到了页面呈现出来所经历的渲染流水线,其实从性能方面考虑,最理想的渲染流水线是没有布局和绘制环节的
,为了实现上述效果,就需要只使用那些仅触发 Composite
的属性。
目前,只有两个属性是满足这个条件的:transforms
和 opacity
(仅部分浏览器支持)。
相关信息可查看:css Triggers
提升为合成层简单说来有以下几点好处:
- 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
- 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
- 对于 transform 和 opacity 效果,部分浏览器不会触发 Layout 和 Paint, 相关信息可查看:css Triggers
- 创建一个新的合成层并不是免费的,它得消耗额外的内存和管理资源。
- 纹理上传后会交由 GPU 处理,因此我们还需要考虑 CPU 和 GPU 之间的带宽问题、以及有多大内存供 GPU 处理这些纹理的问题
大多数人都很喜欢使用3D属性 translateZ(0) 来进行所谓的硬件加速,以提升性能。但我们还需要切实的去分析页面的实际性能表现,不断的改进测试,这样才是正确的性能优化途径。
欢迎关注凹凸实验室博客:aotu.io
或者关注凹凸实验室公众号(AOTULabs),不定时推送文章。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK