在前端开发中,网页的性能优化是一个至关重要的话题。其中,回流(重排)和重绘是影响网页性能的两个关键概念。了解它们的原理、触发因素以及如何优化,对于提高网页的响应速度和用户体验至关重要。本文将结合代码示例和详细解释,深入探讨回流和重绘的相关知识。
布局难点与列式布局
块级格式化上下文(BFC)
在 HTML 中,根元素是最外层的第一个 BFC 元素。BFC 即块级格式化上下文,它规定了块级元素从上到下排列,行内元素从左到右排列,形成了文档流的基本规则。一些属性如 float
、overflow: hidden
和 flex
可以创建 BFC。
列式布局与 table 标签
table
标签可以用于列式布局,通过 tr
(行)和 td
(列)来构建表格结构。然而,使用 table
进行布局并不推荐,主要原因有以下几点:
- 触发大量回流和重绘:
table
中局部的改变会触发整个table
的回流重排,就像“火烧赤壁”一样,一个小的变动可能会影响整个布局。 - 语义不符:
table
标签主要用于展示数据表,使用它进行布局不符合其语义,不利于代码的维护和理解。 - 不够灵活:
table
的布局相对固定,不够灵活,难以满足复杂的页面设计需求。
回流(重排)Reflow
定义
当 RenderTree 中部分或全部元素的尺寸、结构或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程叫做回流,也称为重排。
回流简单示例:
当我们点击按钮将宽度修改了,就是改变了元素的布局,这样就是触发了回流,而且触发了回流就一定也会触发重绘。
触发回流的方式
- 页面首次渲染:严格意义上来说,这不是典型的回流,但它是从无到有的渲染过程,是最耗时的操作。据统计,网页每慢 0.1 秒,可能会少 1000 万的收入,因此页面首次渲染的性能优化至关重要。
- 浏览器窗口大小改变:当用户调整浏览器窗口大小时,页面中的元素需要重新计算布局,以适应新的窗口尺寸,从而触发回流。
- 元素尺寸或位置改变:例如,通过 CSS 改变元素的宽度、高度、边距等属性,或者使用 JavaScript 移动元素的位置。不过,
transition
、transform
和opacity
在新图层中的变化除外,它们不会触发回流。 - 元素内容变化:当使用
appendChild
或removeChild
方法添加或删除元素时,会导致页面结构发生变化,从而触发回流。 - display 属性改变:将元素的
display
属性从none
改为block
或反之,会使元素在文档流中显示或隐藏,触发回流。 - 字体大小变化:改变元素的字体大小会影响元素的尺寸,从而触发回流。
- 激活 CSS 伪类:例如,当鼠标悬停在元素上激活
:hover
伪类时,浏览器需要重新计算元素的样式,可能会触发回流。 - 查询某些属性或调用某些方法:例如,调用
img.getBoundingClientRect()
方法会触发回流,因为浏览器需要获取元素的精确位置和尺寸信息。
代码示例中的回流优化
使用 display: none
可以避免元素参与回流和重绘,这是一种常见的性能优化方案。
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>table 布局,不推荐</title>
<style>
.box{
width: 100px;
height: 100px;
background-color: red;
margin: 10px;
}
.vis_hid{
visibility: hidden;
}
.dis_none{
display: none;
}
</style>
</head>
<body>
<div class="container">
<div class="box vis_hid">123</div>
<div class="box dis_none">456</div>
</div>
</body>
</html>
在这个示例中,class
为 dis_none
的元素使用了 display: none
,该元素不会参与回流和重绘,从而提高了页面的性能。
重绘 Repaint
定义
当页面元素的样式改变,但不影响其在文档流中的位置时,浏览器会进行重绘操作。例如,改变元素的颜色、背景颜色、可见性等属性。
重绘简单示例:
代码示例中的重绘
在上述代码示例中,class
为 vis_hid
的元素使用了 visibility: hidden
,该元素会被隐藏,但仍然占据文档流中的位置,只会触发重绘,而不会触发回流。
页面渲染流程
输入 URL 到页面渲染的过程
- 下载 HTML:浏览器根据输入的 URL 下载 HTML 文件,首先获取字节数据,然后将其解码为 UTF - 8 编码的 HTML 字符,接着解析 HTML 的开关标签和属性,构建节点对象,最终构建 DOM 树。
- 下载 CSS:如果 HTML 中包含
link
标签引用的 CSS 文件,浏览器会下载 CSS 文件。下载过程包括获取字节码,根据Content - Type
确定文件类型为text/css
,解码为 UTF - 8 编码的 CSS 文本,进行词法分析得到token
,构建 CSS 规则节点,最终形成 CSSOM 树。 - 构建 RenderTree:将 DOM 树和 CSSOM 树合并,形成 RenderTree,它只包含需要显示的元素及其样式信息。
- Layout 树:进行布局计算,确定元素在文档流中的位置和大小,形成 Layout 树。
- 图层处理:根据元素的
z - index
、position: fixed
、transition + transform / opacity
等属性,将元素分配到不同的图层中。例如,使用translate(50%,50%,50%)
可以利用 GPU 加速,提高渲染性能。 - 图层合并:将各个图层合并,最终由浏览器的渲染引擎在绘制平面上进行像素点绘制,完成页面的渲染。
总结
回流和重绘是影响网页性能的重要因素,在前端开发中,我们应该尽量减少回流和重绘的次数,以提高网页的响应速度和用户体验。通过合理使用 CSS 属性、优化 DOM 操作以及了解页面渲染流程,我们可以更好地进行性能优化。希望本文能帮助你深入理解回流和重绘的相关知识,并在实际开发中应用这些优化策略。