重绘(Repaint)和重排(Reflow)是浏览器渲染引擎中的两个重要概念。
重排是指浏览器重新计算文档中每个元素的几何属性(例如位置、大小),并计算出它们在渲染树中的位置,然后将它们重新绘制出来。这个过程是非常耗费性能的,因为它需要遍历整个文档,并重新计算每个元素的属性,然后更新渲染树和布局。常见的触发重排的操作包括改变元素的尺寸、位置、内容或样式等。
重绘是指在重排之后,浏览器需要将重新计算后的元素重新绘制到屏幕上,也就是重新绘制所有的像素。重绘的过程相对来说比较轻量,因为它不需要重新计算布局和几何属性,只需要更新像素值即可。
需要注意的是,重排和重绘是紧密相关的过程,重排必然会导致重绘,因为重新计算了元素的几何属性,所以渲染引擎必须重新绘制这些元素。
如何避免触发重排
虽然重排和重绘是紧密相关的过程,但是在某些情况下,仅会触发重绘而不会导致重排,比如:
修改了元素的背景颜色、文本颜色、边框颜色、透明度等与几何属性无关的样式属性。
修改了元素的 box-shadow、outline、visibility、text-decoration、transform、opacity 等属性。
修改了元素的背景图片、背景定位、背景大小等属性。
修改了某些和位置和尺寸无关的属性,例如:pointer-events、cursor、z-index 等。
这些属性的修改只会触发重绘,而不会导致重排。但是需要注意的是,修改样式属性的性能也会受到影响,所以我们还是要尽量避免频繁修改样式属性。
常见触发场景
触发repaint:
color的修改,如color=#ddd;
text-align的修改,如text-align=center;
a:hover也会造成重绘。
:hover引起的颜色等不导致页面回流的style变动。
触发reflow:
width/height/border/margin/padding的修改,如width=778px;
动画,:hover等伪类引起的元素表现改动,display=none等造成页面回流;
appendChild等DOM元素操作;
font类style的修改;
background的修改,注意着字面上可能以为是重绘,但是浏览器确实回流了,经过浏览器厂家的优化,部分background的修改只触发repaint,当然IE不用考虑;
scroll页面,这个不可避免;
resize页面,桌面版本的进行浏览器大小的缩放,移动端的话,还没玩过能拖动程序,resize程序窗口大小的多窗口操作系统。
读取元素的属性(这个无法理解,但是技术达人是这么说的,那就把它当做定理吧):读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE));
全部的非空元素
<area>:定义图像映射中的可点击区域。
<base>:定义文档中所有链接的默认地址或默认目标。
<br>:插入一个换行符。
<col>:定义表格列。
<embed>:定义嵌入的内容,比如多媒体。
<hr>:插入一条水平线。
<img>:插入图像。
<input>:定义输入控件,如文本框、单选框、复选框等。
<keygen>:定义用于表单的密钥对生成器字段。
<link>:定义文档与外部资源之间的关系。
<meta>:定义文档的元数据,比如描述、关键词、编码方式等。
<param>:定义包含在 <object> 和 <applet> 中的参数。
<source>:定义多媒体资源。
<track>:定义用于 HTML5 音频和视频的文本轨道。
<wbr>:定义一个可能的换行符。