从浏览器渲染层面解析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),不定时推送文章:

从浏览器渲染层面解析css3动效优化原理的更多相关文章
- 前端必须收藏的CSS3动效库!!!
现在的网站和App的设计中越来越重视用户体验,而优秀的动效则能使你的应用更具交互性,从而吸引更多用户的使用. 如果你对CSS3中定义动效还不熟练,或希望采用更加简单直接的方式在你的应用中引入动效的话, ...
- 【总结】前端必须收藏的CSS3动效库!!!
现在的网站和App的设计中越来越重视用户体验,而优秀的动效则能使你的应用更具交互性,从而吸引更多用户的使用. 如果你对CSS3中定义动效还不熟练,或希望采用更加简单直接的方式在你的应用中引入动效的话, ...
- 浅谈浏览器解析 URL+DNS 域名解析+TCP 三次握手与四次挥手+浏览器渲染页面
(1)浏览器解析 URL 为了能让我们的知识层面看起来更有深度,我们应该考虑下面两个问题了: 从浏览器输入 URL 到渲染成功的过程中,究竟发生了什么? 浏览器渲染过程中,发生了什么,是不是也有重绘与 ...
- 【Web动画】CSS3 3D 行星运转 && 浏览器渲染原理
承接上一篇:[CSS3进阶]酷炫的3D旋转透视 . 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家. CSS3 3D 行星运转 demo 页面请戳:Demo.(建议使用Chrome打开 ...
- css3常用动效以及总结
(迁移自旧博客2017 08 06) CSS3 文本效果: box-shadow:盒子阴影,可以给卡片添加提高美化效果.可广泛应用于内容展示页面. <div class="card&q ...
- 动效解析工厂:Mask 动画
转载自:http://www.cocoachina.com/ios/20160214/15250.html 前言:很多动效都是多种动画的组合,有时候你可能只是需要其中某个动画,但面对庞杂的代码库或是教 ...
- 浏览器渲染详细过程:重绘、重排和 composite 只是冰山一角
https://juejin.im/entry/590801780ce46300617c89b8 渲染 这张很经典的图许多人都看过,其中的概念大家应该都很熟悉,也就是这么几个步骤:js修改dom结构或 ...
- Web动效研究与实践
随着CSS3和HTML5的发展,越来越多狂拽炫酷叼炸天的动效在网页设计上遍地开花,根据最新的浏览器市场份额报告,IE6的份额已经降到了5.21%,这简直是一个喜大普奔的消息,做动效可以完全不care低 ...
- webkit浏览器渲染影响因素分析
前言:浏览器的渲染对性能影响非常大,特别是在移动端页面,在宏观上,我们可以参考雅虎那20几条军规来操作,但在微观渲染层面,实际还没有一套相对成型的理论做为依据. 本文只是抛砖引玉,带大家进入微观的优化 ...
随机推荐
- 【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
问题描述 在.Net Core 5.0 项目中,添加 Microsoft.Extensions.Logging.AzureAppServices 和 Microsoft.Extensions.Logg ...
- NOIP 模拟 $21\; \rm Median$
题解 \(by\;zj\varphi\) 对于这个序列,可以近似得把它看成随机的,而对于随机数列,每个数的分布都是均匀的,所以中位数的变化可以看作是常数 那么可以维护一个指向中位数的指针,同时维护有多 ...
- C#序列化和反序列化 之 dynamic 动态Json的反序列化
序列化和反序列化的常识不再赘述,如果不清楚这个,可以 参考一下其他人写的文章https://www.cnblogs.com/maitian-lf/p/3670570.html 总结的说, 序列化 是把 ...
- spring学习日志三
一.回顾 1.1 依赖注入的方式. set方法来注入 <property name="属性名" /> 构造方法来注入<construtor-arg index=& ...
- dubbo(一)
1. Introduction 参考链接:https://www.baeldung.com/dubbo Dubbo is an open-source RPC and microservice fra ...
- Servlet学习之复习
Servlet的注册与运行(Servlet程序通常需要存储在<web应用程序目录>\WEB-INF\classes\目录中) 1.注册Servlet:在web.xml文件中,一个<s ...
- MAC下Jetbrains编译器无法打开问题解决
这段时间不知道怎么回事,每次打开Rider必定闪退,毫无头绪,只好暂时放弃使用Rider,试用了一段时间Visual Studio. 可惜...虽然大学时候觉得VS天下第一,但是用惯了JB的编译器,再 ...
- 跨域@RequestBody@RequestParam 和JSON.stringify
- 百闻不如一试——公式图片转Latex代码
写博客时,数学公式的编辑比较占用时间,在上一篇中详细介绍了如何在Markdown中编辑数学符号与公式. https://www.cnblogs.com/bytesfly/p/markdown-form ...
- pip install 报错 TypeError: 'module' object is not callable
$ pip install filetype Traceback (most recent call last): File "/usr/local/bin/pip2", line ...