每日一博 | 从浏览器渲染层面解析 CSS3 动效优化原理
引言
在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),不定时推送文章。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
联发科计划为 nanoMIPS 带来上游 GCC 编译器支持
联发科正致力于为 nanoMIPS 带来上游 GCC 编译器支持,不过官方并未透露其这样做的原因。Phoronix猜测称,或许与该公司的调制解调器的控制处理器中仍然依赖的指令集架构(ISA)有关。 MIPS Technologies 于 2018 年宣布了面向嵌入式设备的 nanoMIPS 架构,旨在降低功耗并实现更小的代码空间占用。但自 MIPS I7200 之后,与 nanoMIPS 相关的消息已经很久没有出现更新了。直至近日,联发科再次开始寻求要将该指令集架构并入上游 GCC。 事实上,MIPS 架构本身现在已经被上游放弃。MIPS Technologies 曾于今年年初表示将不再设计 MIPS 芯片,转而开发基于 RISC-V 架构的处理器。该公司此前也曾试图将 nanoMIPS 支持引入上游 GCC 编译器,但从未成功过;而是一直在依靠于他们的out-of-tree工具链。 这在某种程度上是之前将 nanoMIPS 支持引入上游的努力的延续。我们希望将我们的工具链发布转移到更接近于上游 GCC 的地方。作为其中的一部分,我们希望得到社区的反馈,目前 nanoMIPS 和 MI...
- 下一篇
MOS —— C++ 编写的轻量级跨平台游戏引擎
MOS 是一个轻量级的跨平台游戏引擎/库,用现代 C++ 编写,MOS 目前还处于实验阶段。 特征 最小化和文档化的代码库。 与 Blender 集成 3D mesh 渲染 聚光灯和定向照明 基于物理的材料模型 粒子渲染 文字渲染 后期处理效果 碰撞检测 3D 音频播放 资产管理 IO 管理 源代码 获取和使用项目的一种便捷方法是将其添加为git 子模块: git submodule add https://github.com/morganbengtsson/mos.git git submodule update --init --recursive 构建 该项目最好用作CMake的子项目: add_subdirectory(externals/mos) target_link_libraries(${PROJECT_NAME} PUBLIC mos) 依赖关系 MOS 依赖于以下项目: GLAD GLFW GLM JSON for Modern C++ OpenAL soft STB
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS8安装Docker,最新的服务器搭配容器使用
- 设置Eclipse缩进为4个空格,增强代码规范
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2全家桶,快速入门学习开发网站教程
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- MySQL8.0.19开启GTID主从同步CentOS8