一、浏览器渲染流程
网页的生成过程,大致可以分成五步。
很快: 解析HTML【遇到标签加载图片】 —> 构建DOM树
很快: 加载样式 —> 解析样式【遇到背景图片链接不加载】 —> 构建样式规则树
很快: 把DOM树和样式规则树匹配构建渲染树【加载渲染树上的背景图片】
比较耗时:生成布局(layout),即将所有渲染树的所有节点进行平面合成
比较耗时:将布局绘制(paint)在屏幕上【开始渲染图片】
“生成布局”(flow)和”绘制”(paint)这两步,合称为”渲染”(render)。
图片加载与渲染规则:页面中不是所有的标签图片和样式表背景图片都会加载。设置了display:none属性的元素,图片不会渲染出来,但会加载。
二、重排和重绘
网页生成的时候,至少会渲染一次。用户访问的过程中,还会不断重新渲染。
三种情况,会导致网页重新渲染。
- 修改DOM
- 修改样式表
- 用户事件(比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)
重新渲染,就需要重新生成布局和重新绘制。前者叫做”重排”(reflow),后者叫做”重绘”(repaint)。
需要注意的是,“重绘”不一定需要”重排”,比如改变某个网页元素的颜色,就只会触发”重绘”,不会触发”重排”,因为布局没有改变。但是,“重排”必然导致”重绘”,比如改变一个网页元素的位置,就会同时触发”重排”和”重绘”,因为布局改变了。
*** 对动画性能影响最大的,就是重绘和重排。且重排的代价比重绘要大。重排的花销跟渲染树有多少节点需要重构有关。
假如在body最前面插入一个元素,会导致整个渲染树回流,但如果是指body后面插入一个元素,则不会影响前面的元素重排。
2.1、重排(Relayout/Reflow)
重排,是根据渲染树中每个渲染对象的信息,计算出各自渲染对象的几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置。
重排,标准文档叫做回流(Reflow),是因为浏览器渲染是基于“流式布局”的模型,流实际就是常说的文档流,当dom或者css几何属性发生改变的时候,文档流会受到波动联动的去更改。
【1】重排的影响范围:
由于浏览器渲染界面是基于流式布局模型(Flow Based Layout),也就是某一个DOM节点信息更改了,就会触发重排。只是这个DOM更改程度会决定周边DOM更改范围,即全局范围和局部范围
全局范围:就是从根节点html开始对整个渲染树进行重新布局,例如当我们改变了窗口尺寸或方向或者是修改了根元素的尺寸或者字体大小等;
局部范围:对渲染树的某部分或某一个渲染对象进行重新布局。
【2】会引起重排的操作:
页面首次渲染。
浏览器窗口大小发生改变——resize事件发生时。
元素尺寸或位置发生改变——定位、边距、填充、边框、宽度和高度。
元素内容变化(文字数量或图片大小等等)。
元素字体大小变化。
添加或者删除可见的DOM元素。
激活CSS伪类(例如::hover)。
设置style属性
查询某些属性或调用某些方法。
【3】常见引起重排属性和方法:
常见引起重排属性和方法 |
|||
width |
height |
padding |
margin |
display |
border-width |
border |
top |
position |
font-size |
float |
text-align |
overflow-y |
font-weight |
overflow |
left |
font-family |
line-height |
vertical-align |
right |
clear |
white-space |
bottom |
min-height |
clientWidth |
clientHeight |
clientTop |
clientLeft |
offsetWidth |
offsetHeight |
offsetTop |
offsetLeft |
scrollWidth |
scrollHeight |
scrollTop |
scrollLeft |
scrollIntoView() |
scrollTo() |
getComputedStyle() |
|
getBoundingClientRect() |
scrollIntoViewIfNeeded() |
2.2重绘(Repainting)
重绘,就是页面中元素样式的改变,并不影响它在文档流中的位置,例如更改了字体颜色,浏览器会将新样式赋予给元素并重新绘制的过程。
【1】常见的重绘属性:
常见的重绘属性 |
|||
color |
border-style |
visibility |
background |
text-decoration |
background-image |
background-position |
background-repeat |
outline-color |
outline |
outline-style |
border-radius |
outline-width |
box-shadow |
background-size |
三、提高性能的几个技巧
有一些技巧,可以降低浏览器重新渲染的频率和成本。
1、DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
2、尽可能限制reflow的影响范围。越小越好。
2.1、在body前加元素和body最后加元素影响范围是不同的
2.2、position属性为absolute或fixed的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。
3、避免设置大量的style属性,通过设置style属性改变结点样式,每一次设置都会触发一次reflow;最好是使用class属性或者csstext属性,一次性地改变样式。
4、尽量使用离线DOM,而不是真实的网面DOM,来改变元素样式。比如,操作Document Fragment对象,完成后再把这个对象加入DOM。再比如,使用 cloneNode() 方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。
5、只在必要的时候,才将元素的display属性为可见,因为不可见的元素不影响重排和重绘。【先将元素设为display: none(1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(1次重排和重绘)。用两次取代100次重新渲染。】另外,visibility : hidden的元素只对重绘有影响,不影响重排。
6、使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染。
7、结合will-change使用,兼容性查看: https://caniuse.com/will-change
7.1、它能取代通过3D transform的hack来强制将transforms转移到GPU上,我们可以使用一个专门的属性来通知浏览器关注特性的变化,以及相应的优化和分配内存
7.2、使用will-change:值: auto|scroll-position|contents|<custom-ident> ,可多个 逗号隔开。
-
- auto表示没有指定元素的哪些属性会变化,浏览器不会对任何的变化做出优化工作。
- scroll-position表示开发者希望改变滚动条的位置或者使之产生动画。
- contents表示开发者希望改变元素内容中的某些东西,或者使它们产生动画。
- <custom-ident>表示开发者希望改变指定的属性名或者使之产生动画。
7.3、**注意**: 不要在 will-change 中设置过多属性,也不要在过多元素中设置 will-chaneg 本身
8、不要使用table布局,因为table中某个元素旦触发了reflow,那么整个table的元素都会触发reflow。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。
四、优化动画
除了减少 Reflow 和 Repaints 之外,还要注意,
1、启用GPU 硬件加速。 https://zhuanlan.zhihu.com/p/58222612
可以触发 GPU的硬件加速的CSS属性:transform3D,opacity,filter。
但硬件加速也不是完美的,也不能过多使用。
2、避免高消耗属性:css shadow、background-attachment: fixed等
*** 本文仅是学习中的记录,有错误请指正。 ***
暂无评论内容