📌 前言
在前端性能优化领域,“回流(Reflow)”和“重绘(Repaint)”这两个词绝对绕不过去。
如果再加上 table 布局的老坑,这些点几乎是前端面试必问。
「table 为什么不推荐做布局?」
「浏览器是怎么从 URL 渲染出页面的?」
「什么是回流?什么是重绘?各自如何触发?」
搞懂这些,页面更丝滑,面试不掉链子!
🏗️ 一个最简单的 table 列式布局示例
来看个很多新手都写过的 table 多列布局👇
<table>
<tr>
<td class="sidebar">左侧边栏</td>
<td class="main">主体内容</td>
<td class="sidebar">右侧边栏</td>
</tr>
</table>
table {
width: 100%;
border-collapse: collapse;
}
td {
border: 1px solid #ccc;
padding: 10px;
}
.sidebar {
width: 20%;
background: #f0f0f0;
}
.main {
width: 60%;
background: #e0e0e0;
}
看着能跑,但问题多多。
❌ 为什么 table 不推荐做页面布局?
1️⃣ 语义化问题
table 本质是为展示表格数据而生,
用来做页面结构,既不符合语义化,也对 SEO 和可访问性(A11Y)不友好。
2️⃣ 灵活性太差
相对于 flex、grid、float,
table 在响应式布局、顺序调换、列数变化上完全没优势,维护起来也别扭。
3️⃣ 性能坑:回流开销大
table 的单元格相互依赖,任何一个单元格大小改变,都可能影响整行甚至整张表格布局。
当表格内容复杂或动态增删时,局部变化会触发大范围回流(Reflow) ,严重拖慢页面性能。
⚙️ 浏览器是怎么渲染页面的?
搞懂回流和重绘,先要弄明白浏览器从 URL 到页面渲染的整个流程👇
✅ 1. 输入 URL,下载资源
- 浏览器解析域名、建立连接,下载 HTML 字节流。
✅ 2. 解析 HTML
- 按 UTF-8 编码解析成字符。
- 词法、语法分析,生成 DOM 节点对象。
- 最终构建成 DOM 树(Document Object Model)。
✅ 3. 下载 & 解析 CSS
- HTML 中遇到
<link>、<style>等,发起 CSS 请求。 - 下载字节流,解析成 CSS 文本,词法分析生成规则,最终构建 CSSOM 树(CSS Object Model)。
✅ 4. 生成 Render Tree
- 浏览器将 DOM 树和 CSSOM 树结合,生成 Render Tree。
- Render Tree 只包含可见节点(
display: none的节点不会出现)。
✅ 5. Layout(回流 Reflow)
- 浏览器根据 Render Tree 计算每个元素的盒模型、位置和尺寸,生成 布局树(Layout Tree) 。
- 这个过程就是回流:只要元素的几何信息改变,就要重新 Layout。
✅ 6. 分层(Layer Tree)
-
特定属性会触发单独成层,比如:
position: fixed(弹窗)z-index(堆叠上下文)transform/opacity/will-change(GPU 加速)animation/transition
-
独立图层有助于后续合成和动画性能。
✅ 7. Painting(重绘 Repaint)
- 每个图层被栅格化(Rasterize),绘制成位图。
- 改变颜色、背景等样式而不改变几何信息,只触发重绘。
✅ 8. Compositing(合成)
- 所有图层叠加合成,输出到 GPU,显示在屏幕上。
🧩 一图看懂浏览器渲染流程
下面是对应的渲染流程思维导图,方便你快速记忆👇
输入 URL
│
├─► 下载 HTML
│ ├─ 字节流 → 字符(UTF-8)
│ ├─ 解析标签、属性
│ └─ 构建 DOM 树
│
├─► 下载 CSS
│ ├─ 字节流 → CSS 文本
│ ├─ Tokenize、Parse
│ └─ 构建 CSSOM 树
│
├─► DOM + CSSOM → Render Tree
│ ├─ 过滤掉 display: none
│ └─ 渲染可见节点
│
├─► Layout(回流 Reflow)
│ ├─ 计算盒模型
│ ├─ 确定位置、大小
│ └─ 生成 Layout Tree
│
├─► 分层(Layer Tree)
│ ├─ position: fixed
│ ├─ z-index
│ ├─ transform / opacity
│ ├─ animation / will-change
│ └─ GPU 加速单独成层
│
├─► Painting(重绘 Repaint)
│ ├─ 栅格化 Rasterize
│ └─ 绘制成像素 Bitmap
│
└─► Compositing(合成)
├─ 所有图层叠加
└─ 输出到 GPU 显示屏幕
🔍 回流(Reflow)和重绘(Repaint)到底有什么区别?
📌 回流(Reflow)
-
元素尺寸、位置、盒模型变化时,浏览器会重新计算布局,这个过程叫回流。
-
典型触发操作:
- 添加/删除 DOM 节点(
appendChild、removeChild) - 切换
display: none - 改变
width、height、margin - 查询
offsetHeight、getBoundingClientRect()等布局信息 - 浏览器窗口尺寸变化
- 添加/删除 DOM 节点(
🎨 重绘(Repaint)
-
样式发生变化但不影响几何信息时,只需要重新涂色,触发重绘即可。
-
典型:
- 改变
color、background-color visibility: hidden(元素仍占位,只隐藏)
- 改变
⚡ table 布局为什么放大回流代价?
table 的表格单元格是互相关联的:
某个单元格高度变了,整行都要重新计算,甚至整个表都可能重新布局。
对于大型表格来说,局部变化等于牵一发而动全身,高频的回流很容易拖垮页面。
🛠️ 性能优化实战要点
✅ 用 flex / grid 替代 table 做列式布局
✅ 动画尽量用 transform 和 opacity,触发独立图层,避免回流
✅ visibility: hidden 不会触发回流,display: none 会,按需选择
✅ 批量操作 DOM,用 DocumentFragment 减少回流次数
✅ 避免频繁读取布局信息(多次触发同步回流)
📌 面试必问点汇总
- 渲染流程能画出来吗?
- 回流 vs 重绘的区别?如何触发?
- 为什么 table 布局性能差?
- 有哪些实际优化手段?
记住这套思维导图,面试官追问的时候,你有底气说得明明白白!
✅ 小结
table不适合做页面布局,既不灵活,性能也差。- 回流比重绘更消耗性能,要尽量避免不必要的回流。
- 浏览器渲染链路必须吃透,很多性能优化方案本质就是围绕减少回流重绘做文章。
觉得有帮助,点个 👍 收藏一下,别再被回流重绘难住了!