浏览器的渲染过程、回流、重绘

本文详细介绍了浏览器的渲染过程,包括构建DOM树、CSS树及生成Render树。同时,重点讨论了重绘和回流的概念,以及如何通过优化技巧减少它们带来的性能影响,如使用transform代替top,优化CSS选择器等。最后,提出离线处理DOM、减少DOM操作等策略以提升页面性能。

一、浏览器的渲染过程

1.根据HTML生成DOM树

浏览器在接收到服务器发来的HTML文件是字节形式的,首先要将字节形式的HTML组建成字符串,然后将字符串
转换成token,再将token组装成node节点,最后用node节点组成Dom。

所以DOM(Document Object Model) 文档对象模型可以分解成。

D:document 由元素节点组成的文档 层级是文档包含节点节点包含元素。

O: object 将Dom转化成Dom对象。

M:model 是dom的主要骨架,将页面的标签按照层级从上到下加载每一个节点

2.根据Css生成Css树

按照Dom树的基本骨架添加样式,Css样式可以继承父节点的样式,如果自己定义了同样的属性就会将父类的覆盖掉
例如

<body style="font-size:16px;">
  		<div>
		     <p style="font-weight: bold;">
                    pStyle
               <span style="color:red">spanStyle</span>
             </p>
		</div>

  </body>

3.根据Dom树、Css树生成Render树

render树是以Dom树为骨架,以Css树为装饰搭建组合成的一个渲染树,然后结合渲染规则和布局进行渲染页面

这里要强调一下js代码需要注意的一点: 遇到js代码会先运行js代码,直到js代码块执行完再继续渲染页面,
因为js代码一般都是操作Dom元素的所以js一般放在页面的底部

二、浏览器的重绘与回流(重排)

1.重绘与回流

重绘:当元素属性发生改变且不影响布局时(背景颜色、透明度、字体样式等),产生重绘相当于不刷新页面,动态更新内容。

回流(重排):当元素属性发生改变且影响布局时(宽度、高度、内外边距等),产生回流,相当于 刷新页面。

重绘一般发生的比较频繁,因为页面很小的一个改动也会引起重绘,值得注意的是重绘消耗的性能要比回流(重排)要小,发生重绘不一定发生回流,但是发生回流一定会发生重绘

2.如何减少重绘与回流

①.使用 transform 替代 top

在2d或3d场景移动元素的时候会用到 transform 和top top是延时三秒后执行移动 所以transform性能也会比top好一些

②.使用 opacity:0、visibility:hidden 替换 display: none

opacity:0和visibility:hidden都是将元素隐藏只会引起重绘   display: none也是隐藏但是相当于将该部分删除 会造成回流(重排),
如图是三种属性对页面以及子元素的影响。

③.不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局

table是用来展示数据的组件,不能用来布局,如果使用了table布局其中的元素长度发生变化或者行高发生变化都会造成table
单元格大小尺寸的变化这时就会发生回流,数据是多变的会很频繁的发生回流进而很大的消耗了浏览器的性能

④.动画实现的速度的选择、动画速度越快、回流次数越多、也可以选择使用requestAnimationFrame

动画实现的速度与显示器刷新的频率是决定动画渲染的流畅度的,如果动画渲染过快,显示器跟不上动画渲染的速度就会造成重绘或者回流,
requestAnimationFrame是实现动画常用的方法,效果与setTimeOut、setInterval类似但是有本质上的不同

1、requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随
浏览器的刷新频率,一般来说,这个频率为每秒60帧。

2、在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。

⑤.CSS 选择符从右往左匹配查找,避免节点层级过多
例如:设置样式 .div-content .div-style .span{font-size:10px;}


Css的匹配规则就是从右往左

方案一:从左向右的匹配规则

从.div-content开始遍历子节点.div-style和子节点div,当遍历右侧的div分支时,遍历到a标签发现没有满足条件的,
就回溯到ul继续下一个分支的遍历,直到便利完ul下所有的分支,如果右侧的分支很多,则这样的遍历和回溯就会耗费很多性能

方案二:从右向左的匹配规则

先找到所有的最右侧节点span,然后逐次向上寻找.div-style节点和.div-content节点,直到找到根元素html

⑥.将频繁重绘或者回流的节点设置为图层,图层能够阻止该节点的渲染行为影响别的节点。比如对于 video 标签来说,浏览器会自动将该节点变为图层.

⑦.减少对Dom的操作尽量进行一次性操作,减少回流,例如Vue的虚拟Dom或者将需要修改的节点克隆在修改之后替换到真正的Dom

⑧.将需要操作的Dom进行离线处理,即给需要离线的元素设置属性display:none,离线后对离线Dom进行操作,操作完之后将disply属性设置成可见,这样就可以只进行一次重绘与回流。

### 浏览器渲染机制中的回流 #### 排(Reflow)与(Repaint)的概念及其区别 在浏览器渲染过程中,**排**(也称为回流)是指当 DOM 树或 CSSOM 树发生变化时,浏览器需要新计算元素的位置和几何信息,并更新布局的过程。这一过程通常较为昂贵,因为它涉及到大量计算,包括元素的大小、位置以及父子节点之间的关系等[^1]。 ****则是指在不改变元素布局的情况下,仅更新元素的视觉样式,例如颜色、背景色、透明度等。由于不需要新计算布局信息,因此的开销远小于排[^2]。 两者的主要区别在于: - **排会触发**:当发生排时,元素的布局变化会导致其视觉部分也需要制。 - **不会触发排**:如果只是改变了元素的颜色等外观属性,而没有影响其布局,则只需进行。 #### 触发条件 以下是一些常见的触发排和的操作: - **触发排**的操作包括但不限于: - 添加或删除可见的 DOM 元素 - 修改元素的尺寸(如宽度、高度) - 修改元素的位置(如 `top`、`left`) - 改变窗口大小 - 获取某些会引起布局刷新的属性,如 `offsetWidth`、`offsetHeight` 等[^1] ```javascript const element = document.getElementById('box'); element.style.width = '200px'; // 修改尺寸,触发排 console.log(element.offsetWidth); // 获取 offsetWidth,可能触发同步排 ``` - **触发**的操作通常涉及样式的变化,但不涉及布局调整,例如: - 修改颜色 - 修改背景色 - 修改边框颜色或阴影 - 修改透明度(opacity) ```css .box { background-color: red; transition: background-color 0.3s ease; } ``` ```javascript document.getElementById('box').style.backgroundColor = 'blue'; // 触发 ``` #### 性能优化策略 为了提高页面性能,减少不必要的排和是关键。以下是一些有效的优化手段: - **批量修改 DOM 和样式**:避免多次对 DOM 进行单独操作,可以先将多个修改合并后一次性执行,从而减少排次数[^4]。 ```javascript const element = document.getElementById('box'); element.classList.add('new-style'); // 使用 class 替代 style 操作 ``` - **使用 CSS 动画替代 JS 动画**:对于动画效果,推荐使用 `transform`、`opacity` 等 CSS 属性,这些属性不会引起排,且支持硬件加速,性能更优[^3]。 ```css .animate { transform: translateX(100px); opacity: 0.5; transition: all 0.3s ease; } ``` - **避免在循环中频繁访问布局属性**:在循环体内读取 `offsetWidth`、`clientHeight` 等属性会强制浏览器同步执行排,影响性能[^1]。 ```javascript // 不推荐 for (let i = 0; i < elements.length; i++) { console.log(elements[i].offsetWidth); } // 推荐 const widths = []; for (let i = 0; i < elements.length; i++) { widths.push(elements[i].offsetWidth); } console.log(widths); ``` - **复杂动画使用绝对定位**:将动画元素设置为 `position: absolute` 或 `fixed`,使其脱离文档流,避免影响其他元素的布局。 ```css #animation { position: absolute; top: 0; left: 0; } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值