how -爱代码爱编程
目录
一、重绘和回流
1. 定义
- 重绘(Repaint):指的是当元素样式的改变不影响其在文档流中的位置时,浏览器会重新绘制这个元素,使其呈现新的样式,但不影响布局。
- 回流(Reflow):指的是当元素的尺寸、位置或某些属性发生改变时,浏览器需要重新计算元素的
几何属性
并重新布局,然后再进行绘制,这个过程称为回流。
2. 产生原因
- 重绘产生原因:当元素的样式属性(如颜色、背景等)发生改变,但不影响元素在文档流中的位置时,浏览器会触发重绘。
- 回流产生原因:当元素的几何属性发生变化时,例如尺寸、位置、边距等改变,或者添加、删除、隐藏元素时,浏览器会触发回流。
3. 区别
- 重绘不影响布局,只是重新绘制元素样式,性能开销较小。
- 回流会触发重绘,但反之不一定,因为回流会导致布局的变化,可能会影响其他元素的位置和尺寸,性能开销较大。
二、优化回流频繁导致的性能开销
从重绘和回流的定义来看,回流是性能开销比较大的场景,而且对于会频繁触发回流的页面,性能问题更明显,导致降低渲染速度,从而出现卡顿。
2.1 常见导致回流的场景
包括但不限于:
- 修改元素的几何属性:
- 改变元素的尺寸(宽度、高度)
- 改变元素的位置(top、left、right、bottom)
- 修改元素的边框大小(border)
- 改变元素的内边距(padding)
- 修改元素的外边距(margin)
- 调整元素的布局属性(display、float、position)
- 添加、删除、隐藏元素:
- 添加新的元素到文档中
- 从文档中移除元素
- 修改元素的可见性(visibility、display: none)
- 修改字体属性:
- 改变文字的大小(font-size)
- 修改字体的样式(font-weight、font-style)
- 调整文字的对齐方式(text-align、vertical-align)
- 获取某些布局信息:
- 获取元素的尺寸、位置等属性(offsetWidth、offsetHeight、getBoundingClientRect())
- 计算元素的样式(clientWidth、clientHeight、scrollWidth、scrollHeight)
- 修改表格相关属性:
- 添加或删除表格的行、列
- 修改表格的宽度、高度
- 修改 Flexbox 和 Grid 布局属性:
- 改变 Flexbox 的 flex 属性
- 调整 Grid 的列数、行数等属性
- 页面的初始渲染:
- 当页面首次加载时,浏览器需要对页面进行初始化渲染,这个过程也会触发回流。
- 浏览器窗口尺寸变化:
- 浏览器窗口大小改变时,会触发所有元素的回流,因为页面的布局需要根据新的窗口大小重新计算。
在前端开发中,应该尽量避免频繁触发这些导致回流的场景,以提高页面的性能和用户体验。
2.2 为什么获取某些布局信息也会导致回流
- 获取元素的尺寸、位置等属性(offsetWidth、offsetHeight、getBoundingClientRect())
- 计算元素的样式(clientWidth、clientHeight、scrollWidth、scrollHeight)
这些获取布局信息的操作会导致回流的主要原因是因为浏览器需要计算元素的几何属性,而这些属性的计算需要考虑到整个文档流的布局。因此,当你获取这些属性时,浏览器会强制进行重新布局以确保返回的值是最新的。
具体来说:
- offsetWidth 和 offsetHeight:返回元素相对于包含块的宽度和高度,包含了元素的边框和内边距,但不包括外边距和滚动条。
强调,不包括外边距和滚动条。
- clientWidth 和 clientHeight:返回元素内部可视区域的宽度和高度,不包括边框、外边距、滚动条。
强调,相比 offsetHeight,clientHeight 不包括边框。
- scrollWidth 和 scrollHeight:返回元素的内容区域的宽度和高度,包括被隐藏的部分,但不包括边框、内边距和外边距。
- getBoundingClientRect():返回一个 DOMRect 对象,包含元素的位置、尺寸等信息。
当你调用这些属性时,浏览器需要根据当前文档流的布局重新计算元素的相关属性,如果文档流中的其他元素发生了变化,就会导致回流。因此,在性能要求较高的情况下,应该尽量减少对这些属性的频繁访问,或者在一次操作中一次性获取需要的多个属性,以减少回流的次数。
这里额外介绍一下关于 offsetHeight、clientHeight、scrollHeight 的区别:
下面是一个简单的示例:
<div id="container