触发回流的API完整清单
Part 1: 强制立即回流(读取操作)
1. 元素尺寸和偏移(Element Dimensions & Offset)
| API |
返回值 |
说明 |
触发回流 |
element.offsetWidth |
Number |
元素布局宽度(包括边框+滚动条) |
✅ 立即 |
element.offsetHeight |
Number |
元素布局高度(包括边框+滚动条) |
✅ 立即 |
element.offsetLeft |
Number |
元素相对于offsetParent的左偏移 |
✅ 立即 |
element.offsetTop |
Number |
元素相对于offsetParent的顶部偏移 |
✅ 立即 |
element.offsetParent |
Element |
最近的定位父元素 |
✅ 立即 |
2. 客户区尺寸(Client Dimensions)
| API |
返回值 |
说明 |
触发回流 |
element.clientWidth |
Number |
可见宽度(不含边框和滚动条) |
✅ 立即 |
element.clientHeight |
Number |
可见高度(不含边框和滚动条) |
✅ 立即 |
element.clientLeft |
Number |
左边框宽度 |
✅ 立即 |
element.clientTop |
Number |
上边框宽度 |
✅ 立即 |
3. 滚动相关(Scroll Properties)
| API |
返回值 |
说明 |
触发回流 |
element.scrollWidth |
Number |
内容总宽度(包括溢出部分) |
✅ 立即 |
element.scrollHeight |
Number |
内容总高度(包括溢出部分) |
✅ 立即 |
element.scrollLeft |
Number |
水平滚动距离(读取) |
✅ 立即 |
element.scrollTop |
Number |
垂直滚动距离(读取) |
✅ 立即 |
4. 矩形和位置(Rectangles & Position)
| API |
返回值 |
说明 |
触发回流 |
element.getBoundingClientRect() |
DOMRect |
元素相对视口的位置和尺寸 |
✅ 立即 |
element.getClientRects() |
DOMRectList |
所有CSS盒子的矩形集合 |
✅ 立即 |
range.getBoundingClientRect() |
DOMRect |
Range对象的边界矩形 |
✅ 立即 |
range.getClientRects() |
DOMRectList |
Range对象的矩形列表 |
✅ 立即 |
5. 计算样式(Computed Style)
| API |
返回值 |
说明 |
触发回流 |
window.getComputedStyle(el) |
CSSStyleDeclaration |
元素的计算后样式 |
✅ 立即 |
window.getComputedStyle(el).width |
String |
计算后的宽度值 |
✅ 立即 |
window.getComputedStyle(el)[property] |
String |
任何计算后的属性值 |
✅ 立即 |
6. 窗口和视口(Window & Viewport)
| API |
返回值 |
说明 |
触发回流 |
window.innerWidth |
Number |
视口宽度(包括滚动条) |
✅ 立即 |
window.innerHeight |
Number |
视口高度(包括滚动条) |
✅ 立即 |
window.outerWidth |
Number |
浏览器窗口外部宽度 |
✅ 立即 |
window.outerHeight |
Number |
浏览器窗口外部高度 |
✅ 立即 |
window.scrollX |
Number |
文档水平滚动距离 |
✅ 立即 |
window.scrollY |
Number |
文档垂直滚动距离 |
✅ 立即 |
window.pageXOffset |
Number |
同scrollX(兼容性) |
✅ 立即 |
window.pageYOffset |
Number |
同scrollY(兼容性) |
✅ 立即 |
7. 文档滚动(Document Scroll)
| API |
返回值 |
说明 |
触发回流 |
document.scrollingElement.scrollTop |
Number |
文档滚动位置 |
✅ 立即 |
document.scrollingElement.scrollLeft |
Number |
文档水平滚动位置 |
✅ 立即 |
document.documentElement.scrollTop |
Number |
根元素滚动位置 |
✅ 立即 |
document.body.scrollTop |
Number |
body滚动位置(已废弃) |
✅ 立即 |
8. 焦点和交互(Focus & Interaction)
| API |
返回值 |
说明 |
触发回流 |
element.focus() |
void |
设置焦点(可能触发滚动) |
✅ 立即 |
element.blur() |
void |
移除焦点 |
⚠️ 可能 |
element.select() |
void |
选择文本(input/textarea) |
✅ 立即 |
9. 鼠标事件属性(Mouse Event Properties)
| API |
返回值 |
说明 |
触发回流 |
event.offsetX |
Number |
鼠标相对于目标元素的X坐标 |
✅ 立即 |
event.offsetY |
Number |
鼠标相对于目标元素的Y坐标 |
✅ 立即 |
event.layerX |
Number |
鼠标相对于定位层的X坐标 |
✅ 立即 |
event.layerY |
Number |
鼠标相对于定位层的Y坐标 |
✅ 立即 |
10. DOM查询和匹配(DOM Query)
| API |
返回值 |
说明 |
触发回流 |
document.elementFromPoint(x, y) |
Element |
获取指定坐标的元素 |
✅ 立即 |
document.elementsFromPoint(x, y) |
Array |
获取指定坐标的所有元素 |
✅ 立即 |
element.matches(selector) |
Boolean |
检查元素是否匹配选择器 |
⚠️ 可能 |
11. Range和Selection(范围和选区)
| API |
返回值 |
说明 |
触发回流 |
selection.getRangeAt(index) |
Range |
获取选区的Range对象 |
⚠️ 可能 |
range.getBoundingClientRect() |
DOMRect |
Range的边界矩形 |
✅ 立即 |
range.getClientRects() |
DOMRectList |
Range的矩形列表 |
✅ 立即 |
12. SVG相关(SVG Specific)
| API |
返回值 |
说明 |
触发回流 |
svgElement.getBBox() |
SVGRect |
SVG元素的边界框 |
✅ 立即 |
svgElement.getCTM() |
SVGMatrix |
当前变换矩阵 |
✅ 立即 |
svgElement.getScreenCTM() |
SVGMatrix |
屏幕变换矩阵 |
✅ 立即 |
Part 2: 标记需要回流(写入操作)
1. 盒模型属性(Box Model)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.width |
String |
宽度 |
✅ 标记 |
element.style.height |
String |
高度 |
✅ 标记 |
element.style.minWidth |
String |
最小宽度 |
✅ 标记 |
element.style.minHeight |
String |
最小高度 |
✅ 标记 |
element.style.maxWidth |
String |
最大宽度 |
✅ 标记 |
element.style.maxHeight |
String |
最大高度 |
✅ 标记 |
2. 外边距(Margin)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.margin |
String |
外边距(简写) |
✅ 标记 |
element.style.marginTop |
String |
上外边距 |
✅ 标记 |
element.style.marginRight |
String |
右外边距 |
✅ 标记 |
element.style.marginBottom |
String |
下外边距 |
✅ 标记 |
element.style.marginLeft |
String |
左外边距 |
✅ 标记 |
3. 内边距(Padding)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.padding |
String |
内边距(简写) |
✅ 标记 |
element.style.paddingTop |
String |
上内边距 |
✅ 标记 |
element.style.paddingRight |
String |
右内边距 |
✅ 标记 |
element.style.paddingBottom |
String |
下内边距 |
✅ 标记 |
element.style.paddingLeft |
String |
左内边距 |
✅ 标记 |
4. 边框(Border)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.border |
String |
边框(简写) |
✅ 标记 |
element.style.borderWidth |
String |
边框宽度 |
✅ 标记 |
element.style.borderTopWidth |
String |
上边框宽度 |
✅ 标记 |
element.style.borderRightWidth |
String |
右边框宽度 |
✅ 标记 |
element.style.borderBottomWidth |
String |
下边框宽度 |
✅ 标记 |
element.style.borderLeftWidth |
String |
左边框宽度 |
✅ 标记 |
5. 定位(Position)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.position |
String |
定位方式(static/relative/absolute/fixed/sticky) |
✅ 标记 |
element.style.top |
String |
顶部偏移 |
✅ 标记 |
element.style.right |
String |
右侧偏移 |
✅ 标记 |
element.style.bottom |
String |
底部偏移 |
✅ 标记 |
element.style.left |
String |
左侧偏移 |
✅ 标记 |
6. 显示和布局(Display & Layout)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.display |
String |
显示方式(none/block/inline/flex等) |
✅ 标记 |
element.style.float |
String |
浮动(left/right/none) |
✅ 标记 |
element.style.clear |
String |
清除浮动 |
✅ 标记 |
element.style.verticalAlign |
String |
垂直对齐 |
✅ 标记 |
7. Flexbox属性
| 属性 |
类型 |
说明 |
触发回流 |
element.style.flexDirection |
String |
flex方向 |
✅ 标记 |
element.style.flexWrap |
String |
flex换行 |
✅ 标记 |
element.style.flexGrow |
String |
flex增长 |
✅ 标记 |
element.style.flexShrink |
String |
flex收缩 |
✅ 标记 |
element.style.flexBasis |
String |
flex基准 |
✅ 标记 |
element.style.justifyContent |
String |
主轴对齐 |
✅ 标记 |
element.style.alignItems |
String |
交叉轴对齐 |
✅ 标记 |
element.style.alignSelf |
String |
单个项对齐 |
✅ 标记 |
8. Grid属性
| 属性 |
类型 |
说明 |
触发回流 |
element.style.gridTemplateColumns |
String |
Grid列模板 |
✅ 标记 |
element.style.gridTemplateRows |
String |
Grid行模板 |
✅ 标记 |
element.style.gridTemplateAreas |
String |
Grid区域模板 |
✅ 标记 |
element.style.gridColumn |
String |
Grid列位置 |
✅ 标记 |
element.style.gridRow |
String |
Grid行位置 |
✅ 标记 |
element.style.gap |
String |
Grid/Flex间距 |
✅ 标记 |
element.style.columnGap |
String |
列间距 |
✅ 标记 |
element.style.rowGap |
String |
行间距 |
✅ 标记 |
9. 文本和字体(Text & Font)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.fontSize |
String |
字体大小 |
✅ 标记 |
element.style.fontFamily |
String |
字体族 |
✅ 标记 |
element.style.fontWeight |
String |
字体粗细 |
✅ 标记 |
element.style.lineHeight |
String |
行高 |
✅ 标记 |
element.style.letterSpacing |
String |
字间距 |
✅ 标记 |
element.style.wordSpacing |
String |
词间距 |
✅ 标记 |
element.style.textAlign |
String |
文本对齐 |
✅ 标记 |
element.style.textIndent |
String |
文本缩进 |
✅ 标记 |
element.style.whiteSpace |
String |
空白处理 |
✅ 标记 |
element.style.wordWrap |
String |
自动换行 |
✅ 标记 |
10. 溢出和滚动(Overflow & Scroll)
| 属性 |
类型 |
说明 |
触发回流 |
element.style.overflow |
String |
溢出处理(visible/hidden/scroll/auto) |
✅ 标记 |
element.style.overflowX |
String |
水平溢出 |
✅ 标记 |
element.style.overflowY |
String |
垂直溢出 |
✅ 标记 |
element.scrollTop = value |
Number |
设置垂直滚动位置 |
✅ 标记 |
element.scrollLeft = value |
Number |
设置水平滚动位置 |
✅ 标记 |
11. DOM操作
| 操作 |
类型 |
说明 |
触发回流 |
element.appendChild(child) |
Element |
添加子元素 |
✅ 标记 |
element.insertBefore(new, ref) |
Element |
插入元素 |
✅ 标记 |
element.removeChild(child) |
Element |
移除子元素 |
✅ 标记 |
element.remove() |
void |
移除元素自身 |
✅ 标记 |
element.replaceChild(new, old) |
Element |
替换子元素 |
✅ 标记 |
element.innerHTML = html |
String |
设置HTML内容 |
✅ 标记 |
element.textContent = text |
String |
设置文本内容 |
✅ 标记 |
element.innerText = text |
String |
设置可见文本 |
✅ 标记 |
12. 类和属性操作
| 操作 |
类型 |
说明 |
触发回流 |
element.className = 'class' |
String |
设置类名 |
⚠️ 可能 |
element.classList.add('class') |
void |
添加类 |
⚠️ 可能 |
element.classList.remove('class') |
void |
移除类 |
⚠️ 可能 |
element.classList.toggle('class') |
Boolean |
切换类 |
⚠️ 可能 |
element.setAttribute('style', css) |
void |
设置style属性 |
⚠️ 可能 |
13. 表格相关
| 属性 |
类型 |
说明 |
触发回流 |
element.style.borderCollapse |
String |
边框合并 |
✅ 标记 |
element.style.borderSpacing |
String |
边框间距 |
✅ 标记 |
element.style.tableLayout |
String |
表格布局算法 |
✅ 标记 |
14. 列表相关
| 属性 |
类型 |
说明 |
触发回流 |
element.style.listStyle |
String |
列表样式 |
✅ 标记 |
element.style.listStylePosition |
String |
列表标记位置 |
✅ 标记 |
15. 其他布局属性
| 属性 |
类型 |
说明 |
触发回流 |
element.style.boxSizing |
String |
盒模型(content-box/border-box) |
✅ 标记 |
element.style.columns |
String |
多列布局 |
✅ 标记 |
element.style.columnCount |
String |
列数 |
✅ 标记 |
element.style.columnWidth |
String |
列宽 |
✅ 标记 |
element.style.columnGap |
String |
列间距 |
✅ 标记 |
element.style.aspectRatio |
String |
宽高比 |
✅ 标记 |
Part 3: 不触发回流(只触发重绘或合成)
只触发重绘的属性
| 属性 |
类型 |
说明 |
触发 |
element.style.color |
String |
文字颜色 |
🎨 重绘 |
element.style.backgroundColor |
String |
背景颜色 |
🎨 重绘 |
element.style.backgroundImage |
String |
背景图片 |
🎨 重绘 |
element.style.borderColor |
String |
边框颜色 |
🎨 重绘 |
element.style.borderStyle |
String |
边框样式 |
🎨 重绘 |
element.style.boxShadow |
String |
阴影 |
🎨 重绘 |
element.style.outline |
String |
轮廓 |
🎨 重绘 |
element.style.visibility |
String |
可见性(visible/hidden) |
🎨 重绘 |
只触发合成的属性(GPU加速)
| 属性 |
类型 |
说明 |
触发 |
element.style.transform |
String |
2D/3D变换 |
🚀 合成 |
element.style.opacity |
String |
不透明度 |
🚀 合成 |
element.style.filter |
String |
滤镜(需要独立层) |
🚀 合成 |
element.style.willChange |
String |
性能提示 |
🚀 合成 |
对比总结
| 操作类型 |
触发时机 |
能否批量优化 |
性能影响 |
示例 |
| 读取布局 |
立即强制触发 |
❌ 很难 |
🔴 高 |
element.offsetWidth |
| 写入布局 |
标记延迟触发 |
✅ 可以 |
🟡 中 |
element.style.width = '100px' |
| 写入颜色 |
标记延迟触发 |
✅ 可以 |
🟢 低 |
element.style.color = 'red' |
| Transform |
标记延迟触发 |
✅ 可以 |
🟢 极低 |
element.style.transform = 'translateX(10px)' |
性能优化策略
1. 避免强制同步布局
// ❌ 错误:写入后立即读取
element.style.width = '100px'
const width = element.offsetWidth // 强制同步布局
// ✅ 正确:读写分离
const width = element.offsetWidth // 先读
element.style.width = '100px' // 后写
2. 批量操作
// ❌ 错误:逐个修改
for (let i = 0; i < elements.length; i++) {
elements[i].style.width = '100px'
}
// ✅ 正确:使用CSS类
const style = document.createElement('style')
style.textContent = '.new-width { width: 100px; }'
document.head.appendChild(style)
elements.forEach(el => el.classList.add('new-width'))
// 🚀 最佳:使用CSS变量
document.documentElement.style.setProperty('--item-width', '100px')
// CSS: .item { width: var(--item-width); }
3. 使用Transform代替位置属性
// ❌ 慢:触发回流
element.style.left = '100px'
element.style.top = '100px'
// ✅ 快:不触发回流
element.style.transform = 'translate(100px, 100px)'
4. 缓存布局信息
// ❌ 错误:重复读取
for (let i = 0; i < 100; i++) {
console.log(element.offsetWidth) // 触发100次
}
// ✅ 正确:缓存值
const width = element.offsetWidth // 只触发1次
for (let i = 0; i < 100; i++) {
console.log(width)
}
5. 使用requestAnimationFrame分帧
// ❌ 错误:一次性处理大量元素
for (let i = 0; i < 10000; i++) {
elements[i].style.width = '100px'
}
// ✅ 正确:分帧处理
let index = 0
function processBatch() {
const end = Math.min(index + 500, elements.length)
for (let i = index; i < end; i++) {
elements[i].style.width = '100px'
}
index = end
if (index < elements.length) {
requestAnimationFrame(processBatch)
}
}
processBatch()
快速参考卡片
触发回流的操作
| 类别 |
数量 |
示例 |
| 读取布局(立即) |
~52个 |
offsetWidth,
getBoundingClientRect() |
| 写入盒模型(标记) |
~6个 |
width,
height,
min-width |
| 写入边距(标记) |
~10个 |
margin,
padding,
border-width |
| 写入定位(标记) |
~5个 |
position,
top,
left |
| 写入显示(标记) |
~4个 |
display,
float,
clear |
| 写入Flex(标记) |
~8个 |
flex-direction,
justify-content |
| 写入Grid(标记) |
~8个 |
grid-template-columns,
gap |
| 写入文本(标记) |
~10个 |
font-size,
line-height |
| DOM操作(标记) |
~8个 |
appendChild,
innerHTML |
| 总计 |
~111个 |
读52 + 写59 |
不触发回流的操作
| 类别 |
数量 |
示例 |
| 颜色(重绘) |
~8个 |
color,
background-color |
| Transform(合成) |
~4个 |
transform,
opacity |
| 总计 |
~12个 |
只重绘或合成 |
触发回流工作机制
浏览器靠「监听触发源 + 维护渲染队列 + 脏检查」机制感知布局变化,核心是精准捕捉 “影响几何属性 / 结构” 的操作,具体流程如下:
监听触发事件:浏览器内置监听逻辑,一旦检测到前文提到的触发源(如修改 width、增删 DOM、窗口 resize),就标记该元素为 “布局脏元素”。维护渲染队列:不会立即回流,而是将所有 “脏元素” 加入队列,等待浏览器空闲时批量处理(避免频繁计算)。强制刷新触发:若代码读取 offsetWidth 等布局属性,浏览器会立即清空队列、执行回流,确保读取到最新布局数据。