文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

抖音三面:硬件加速中的“层”和层叠上下文中的“层”,是一个东西吗?

2024-12-01 19:13

关注

页面渲染的流程

首先来复习一下一个老八股:页面渲染的流程, 简单来说,初次渲染时会经过以下几步:

在CSS属性改变时,重渲染会分为“回流”、“重绘”和“直接合成”三种情况,分别对应从“布局定位”/“图层绘制”/“合成显示”开始,再走一遍上面的流程。

元素的CSS具体发生什么改变,则决定属于上面哪种情况:

回流(又叫重排):元素位置、大小发生变化导致其他节点联动,需要重新计算布局;

重绘:修改了一些不影响布局的属性,比如颜色;

直接合成:合成层的transform、opacity修改,只需要将多个图层再次合并,而后生成位图,最终展示到屏幕上;

渲染中的层

上面提到了渲染过程中会发生“图层分层”。浏览器中的层分为两种:“渲染层”和“合成层(也叫复合层)”。很多文章中还会提到一个概念叫“图形层”,其实可以把它当作合成层看待。为了降低理解成本,本文全部使用“渲染层”和“合成层”这两个名词描述。

开发者工具中的Layers

先直观的感受一下“层”,打开浏览器开发者工具的layers:

可以看到AB元素都在最底下的图层中,元素C是单独的一层,元素D又是一层。

<style>
body{
margin:0;
padding:0;
}
.box {
width: 100px;
height: 100px;
background: rgba(240, 163, 163, 0.4);
border: 1px solid pink;
border-radius: 10px;
text-align: center;
}
#a {
}
#b {
position: absolute;
top:0;
left: 80;
z-index: 2;
}
#c {
position: absolute;
top:0;

left: 160;
z-index: 3;
transform: translateZ(0);
}
#d {
position: absolute;
top:0;

left: 240;
z-index: 4;
}
.description {
font-size: 10px;
}
style>

<div id="a" class="box">Adiv>
<div id="b" class="box">
B
<div class="description">z-index:2div>
div>
<div id="c" class="box">
C
<div class="description">z-index:3div>
<div class="description">transform: translateZ(0)div>
div>
<div id="d" class="box">
D
<div class="description">z-index:4div>
div>

之前说过,浏览器中的层分两种,渲染层和合成层,在这里看到的全部都是合成层。那么,怎样生成一个渲染层,又怎样才能形成一个合成层呢?

渲染层

渲染层的概念跟“层叠上下文”密切相关,之前也写过一篇文章,可以看这里。简单来说,拥有z-index属性的定位元素会生成一个层叠上下文,一个生成层叠上下文的元素就生成了一个渲染层。

还是沿用上面的例子,BCD三个元素都是拥有z-index属性的定位元素(绝对定位),所以他们三个都形成了一个渲染层,加上document根元素形成的,一共是四个渲染层。(再强调一下,在开发者工具中看不到渲染层。)

形成渲染层的条件也就是形成层叠上下文的条件,有这几种情况:

此外需要剪裁的元素也会形成一个渲染层,也就是overflow不是visible的元素。

合成层

在开发者工具中看到的不是渲染层,而是下面要讲的合成层,只有一些特殊的渲染层才会被提升为合成层,通常来说有这些情况:

可以看出,上面这些条件属于生成渲染层的“加强版”,也就是说形成合成层的条件要更苛刻。

还是用开头的例子,C元素就是命中条件1,使用了3D变换transform: translateZ(0),于是被提升到一个单独的合成层。

但是D元素没有命中上面任何一条规则,却也是一个单独的合成层。因为还有一种情况——隐式合成。

隐式合成

当出现一个合成层后,层级顺序高于它的堆叠元素就会发生隐式合成。

我们给C、D元素设置层级,z-index分别是3和4;又在C元素上使用3D变换,提升成了合成层。此时,层级高于它的D元素就发生了隐式合成,也变成了一个合成层。

隐式合成出现的根本原是,元素发生了堆叠,浏览器为了保证最后的展示效果,不得不把层级顺序更高的元素拎出来盖在已有合成层上面。

层爆炸与层压缩

这是我在项目中实际遇到的一个问题:一个页面在低端机器上滚动时非常卡顿,排查了很久,最后发现原因就在于隐式合成带来的层爆炸。

隐式合成产生了很多预期外的合成层——页面中所有 z-index 高于它的节点全部被提升,这些合成层都是相当消耗内存和GPU的。所以带给我们的启示是给合成层一个大的z-index值,避免出现隐式合成。

还好浏览器逐渐进行了优化,也就是层压缩机制——多个渲染层同一个合成层重叠时,会自动将他们压缩到一起,避免“层爆炸”带来的损耗。

硬件加速

上面讲了这么多,在实际开发中有什么用呢?或者说,浏览器为什么要分层呢?答案是硬件加速。听起来很厉害,其实不过是给HTML元素加上某些CSS属性,比如3D变换,将其提升成一个合成层,独立渲染。

之所以叫硬件加速,就是因为合成层会交给GPU(显卡)去处理,在硬件层面上开外挂,比在主线程(CPU)上效率更高。

就像在ipad上画画一样,画手都是在不同的图层绘制线稿、上色,这样才方便后期修改,不至于牵一发而动全身。提升成合成层的元素发生回流、重绘都只影响这一层,渲染效率得到提升。

来看一个例子,使用animation改变B元素的宽度,通过开发者工具Layers中的“paint count”的可以看到页面绘制次数会一直在增加,能直观感受到页面发生了“重绘”。

可以注意到,重绘是发生在整个图层#document上的,也就是整个页面都要重绘。

<style>
.box {
width: 100px;
height: 100px;
background: rgba(240, 163, 163, 0.4);
border: 1px solid pink;
border-radius: 10px;
text-align: center;
}
#a {
}
#b {
position: absolute;
top: 50;
left: 50;
z-index: 2;
animation: width-change 5s infinite;
}
@keyframes width-change {
0% {
width: 80px;
}
100% {
width: 120px;
}
}

.description {
font-size: 10px;
}
style>

<div id="a" class="box">Adiv>
<div id="b" class="box">
B
<div class="description">animation:width-changediv>
div>

给B元素加上will-change:transform开启硬件加速,让他提升成一个合成层。

会发现重绘只发生在这个图层上,#document图层的绘制次数不会一直增加了。

<style>
.box {
width: 100px;
height: 100px;
background: rgba(240, 163, 163, 0.4);
border: 1px solid pink;
border-radius: 10px;
text-align: center;
}
#a {
}
#b {
position: absolute;
top: 50;
left: 50;
z-index: 2;
animation: width-change 5s infinite;
will-change: transform;
}
@keyframes width-change {
0% {
width: 80px;
}
100% {
width: 120px;
}
}

.description {
font-size: 10px;
}
style>

<div id="a" class="box">Adiv>
<div id="b" class="box">
B
<div class="description">animation:width-changediv>
div>

这就是硬件加速的意义:我们在讲到性能优化时,经常会说减少回流、重绘,如果能直接避免当然是最好,但如果实在没法避免,可以使用硬件加速,让这个元素单独回流、重绘,减少绘制的面积。

有得必有失,开启硬件加速后的合成层会交给GPU处理,当图层过多时,将会占用大量内存,尤其在移动端会造成卡顿,让优化适得其反。正确使用硬件加速就是在渲染效率和性能损耗之间找到一个平衡点,让页面渲染迅速不白屏,又流畅丝滑。

优化渲染性能

上面讲到了,利用硬件加速,可以把需要重排/重绘的元素单独拎出来,减少绘制的面积,除此之外,提升渲染性能还有这几个常见的方法:

结语

回到开头的几个问题,答案不难在文中找到:

硬件加速并不是前端专有的东西,它是一个很宽泛的计算机概念——把软件的工作交给特定的硬件,更高效的完成某项任务。对于前端来说,就是使用特定的CSS属性,把元素提升成合成层,交给GPU处理;

合成层中的“层”可以被认为是真正物理上的层,浏览器把它独立出来,单独拿给GPU处理,而层叠上下文的“层”则是指渲染层,更像是一个概念上的层,一个合成层可以包含多个渲染层;

层爆炸指的是大量元素意料之外被提升成合成层,即隐式合成;层压缩是浏览器对隐式合成的优化,chrome在94版本中做到比较完善了;

使用transform、opacity取代传统属性来实现一些动画,并把他们提升到一个单独的合成层,能跳过布局计算和重新绘制,直接合成,能避免不必要的回流、重绘。

来源:前端私教年年内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯