说说你对重绘和重排的理解,以及如何优化?

1、重排 / 回流 / 布局:Layout / Reflow

原理: 

重排是指对元素的几何属性进行计算。当几何属性发生了改变,例如元素的位置、大小发生改变,或者切换显示隐藏时候。需要重新构建,对节点信息重新计算从而触发重排操作。

因为浏览器渲染页面是基于流式布局的,对某一个DOM节点信息进行修改时,就需要对该DOM结构进行重新计算。该DOM结构的修改会决定周边DOM结构的更改范围,主要分为全局范围和局部范围。

全局范围就是从页面的根节点html标签开始,对整个渲染树进行重新计算。例如,当我们改变窗口的尺寸或者修改了根元素的字体大小时。

局部范围只会对渲染树的某部分进行重新计算。例如要改变页面中某个div的宽度,只需要重新计算渲染树中与该div相关的部分即可。

每个页面至少需要一次回流,就是在页面第一次加载的时候。

引起重排的操作:任何页面布局和几何属性的改变都会触发重排

① 页面首次渲染                                ② DOM 的显示与隐藏(添加或删除DOM)
③ 元素相对于文档的定位改变          ④ 改变元素的大小(width、height、pading、margin
⑤ 添加行内 style 样式                      ⑥ 浏览器窗口大小发生改变时

⑦ 填充内容的改变,比如文本的改变或图片大小改变而引起的计算值宽度和高度的改变

⑧ 元素内容、字体发生改变

 在获取以下一些常见的属性和函数时,会引发重排的操作:

· width:宽度。
· height:高度。
· margin:外边距。
· padding:内边距。
· display:元素显示方式。
· border:边框。
· position:元素定位方式。
· overflow:元素溢出处理方式。
· clientWidth:元素可视区宽度。
· clientHeight:元素可视区高度。
· clientLeft:元素边框宽度。
· clientTop:元素边框高度。
· offsetWidth:元素水平方向占据的宽度。
· offsetHeight:元素水平方向占据的高度。
· offsetLeft:元素左外边框至父元素左内边框的距离。
· offsetTop:元素上外边框至父元素上内边框的距离。
· scrollWidth:元素内容占据的宽度。
· scrollHeight:元素内容占据的高度。
· scrollLeft:元素横向滚动的距离。
· scrollTop:元素纵向滚动的距离。
· scrollIntoView():元素滚动至可视区的函数。
· scrollTo():元素滚动至指定坐标的函数。
· getComputedStyle():获取元素的CSS样式的函数。
· getBoundingClientRect():获取元素相对于视窗的位置集合的函数。
· scrollIntoViewIfNeeded():元素滚动至浏览器窗口可视区的函数。(非标准特性,谨慎使用)
 优化方向:

浏览器中最耗时的部分就是reflow,所以围绕这一部分就是考虑如何减少reflow的次数

2、重绘: Painting / Repaint

原理: 

即根据计算好的信息绘制整个页面。 重绘相对来说就简单点了,比如颜色、背景图片、阴影、透明度发生改变。只要不影响元素本身相对于浏览器文档的位置只会触发重绘。

重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。

引起重绘的操作:改变元素外观属性

color,background-color,font-size

在修改某些常见的属性时,会引发重绘的操作:

· color:颜色。
· border-style:边框样式。
· visibility:元素是否可见。
· background:元素背景样式,包括背景色、背景图、背景图尺寸、背景图位置等。
· text-decoration:文本装饰,包括文本加下画线、上划线、贯穿线等。
· outline:元素的外轮廓的样式,在边框外的位置。
· border-radius:边框圆角。
· box-shadow:元素的阴影。

3、重排和重绘的关系

理论上,每一次的DOM更改或者CSS几何属性更改,比如 width,height,position 定位等,都会引起一次浏览器的重排/重绘过程。也就是浏览器会重新计算元素的几何属性,并重新构造渲染树,这个过程叫做重排。完成重排后,要将重新构建的渲染树渲染到屏幕上,这个过程就是“重绘”。而如果是CSS的非几何属性更改,则只会引起重绘过程。 

所以,重排必定会引发重绘,但重绘不一定会引发重排。

页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow 和 repain。

4、优化 

① 浏览器自己的优化:

浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。

② 我们要注意的优化:

我们要减少重绘和重排就是要减少对渲染树的操作,例如:

(1)将多次样式修改合并成一次

(2)将需要多次重排的元素,position属性设为 absolute 或 fixed

使元素脱离了文档流,它的变化不会影响到其他元素;

(3)复杂元素处理先设置display:none,处理完再显示

由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发2次重排;

(4)缓存频繁操作的属性;

(5)减少使用table布局

如果table中任何一个元素触发了重排的操作,那么整个table都会触发重排的操作,尤其是当一个table内容比较庞大时,更加不推荐使用table布局。

如果不得已使用了table,可以设置table-layout:auto或者是table-layout:fixed。这样可以让table一行一行地渲染,这种做法也是为了限制重排的影响范围。

(6)使用事件委托绑定事件处理程序

在对多个同级元素做事件绑定时,推荐使用事件委托机制进行处理。使用事件委托可以在很大程度上减少事件处理程序的数量,从而提高性能。

 (7)利用 DocumentFragment 操作DOM节点

DocumentFragment 是一个没有父级节点的最小文档对象,它可以用于存储已经排好版或者尚未确定格式的HTML片段。

DocumentFragment 最核心的知识点在于它不是真实DOM树的一部分,它的变化不会引起DOM树重新渲染的操作,也就不会引起浏览器重排和重绘的操作,从而带来性能上的提升。

因为DocumentFragment 具有的特性,在需要频繁进行DOM新增或者删除的操作中,它将变得非常有用。

一般的操作方法分为以下两步:

① 将需要变更的DOM元素放置在一个新建的DocumentFragment中,因为DocumentFragment不存在于真实的DOM树中,所以这一步操作不会带来任何性能影响。

② 将DocumentFragment添加至真正的文档树中,这一步操作处理的不是DocumentFragment自身,而是DocumentFragment的全部子节点。对DocumentFragment的操作来说,只会产生一次浏览器重排和重绘的操作,相比于频繁操作真实DOM元素的方法,会有很大的性能提升。

(8)减少DOM操作

(9)元素适当地定义高度或最小高度,否则元素的动态内容载入时,会出现页面元素的晃动或位置,造成回流(比如图片要定义宽高,避免页面塌陷,同时减少回流 

具体示例:JavaScript 浏览器的重排和重绘 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值