重绘(Repaint)和重排(Reflow)是浏览器渲染过程中的两个重要概念,它们对性能的影响不同。

浏览器渲染流程

HTML → DOM Tree
CSS  → CSSOM Tree
     ↓
  Render Tree → Layout(重排) → Paint(重绘) → Composite(合成)

重排(Reflow/Layout)

定义

重排是指浏览器重新计算元素的几何属性(位置、大小)的过程。

触发重排的属性

/* 盒模型相关 */
width, height, padding, margin, border
 
/* 定位相关 */
position, top, left, right, bottom
 
/* 浮动和清除 */
float, clear
 
/* 显示类型 */
display
 
/* 字体相关 */
font-size, font-family, font-weight
 
/* 文本相关 */
line-height, text-align, vertical-align, white-space
 
/* 溢出相关 */
overflow, overflow-x, overflow-y

触发重排的操作

// 获取布局信息
element.offsetWidth
element.offsetHeight
element.offsetTop
element.offsetLeft
element.clientWidth
element.clientHeight
element.scrollWidth
element.scrollHeight
element.scrollTop
element.scrollLeft
 
// 获取计算样式
window.getComputedStyle(element)
element.getBoundingClientRect()
 
// DOM操作
element.appendChild(newElement)
element.removeChild(element)
element.innerHTML = 'new content'
 
// 样式修改
element.style.width = '100px'
element.style.height = '200px'

重绘(Repaint)

定义

重绘是指浏览器重新绘制元素外观的过程,不涉及几何属性的改变。

只触发重绘的属性

/* 颜色相关 */
color, background-color, background-image
 
/* 边框样式 */
border-style, border-radius
 
/* 阴影效果 */
box-shadow, text-shadow
 
/* 轮廓 */
outline, outline-color, outline-style, outline-width
 
/* 可见性 */
visibility

性能对比

操作类型重排重绘合成性能影响
修改width/height最高
修改color中等
修改transform最低

实际示例对比

触发重排的操作

// 坏的做法 - 触发多次重排
function badResize() {
  const element = document.querySelector('.box');
  
  element.style.width = '200px';  // 重排 + 重绘
  element.style.height = '200px'; // 重排 + 重绘
  element.style.margin = '10px';  // 重排 + 重绘
  
  // 每次都会触发重排
  console.log(element.offsetWidth);  // 强制重排
  console.log(element.offsetHeight); // 强制重排
}

只触发重绘的操作

function repaintOnly() {
  const element = document.querySelector('.box');
  
  element.style.color = 'red';           // 只重绘
  element.style.backgroundColor = 'blue'; // 只重绘
  element.style.boxShadow = '2px 2px 4px #000'; // 只重绘
}

只触发合成的操作

function compositeOnly() {
  const element = document.querySelector('.box');
  
  element.style.transform = 'translateX(100px)'; // 只合成
  element.style.opacity = '0.5';                 // 只合成
}

最佳实践总结

  1. 避免频繁读取布局属性
  2. 批量修改样式,使用CSS类或cssText
  3. 使用transform和opacity进行动画
  4. 合理使用will-change属性
  5. 使用文档片段进行批量DOM操作
  6. 避免在循环中修改样式
  7. 缓存布局信息,避免重复计算

理解重绘和重排的区别,有助于编写更高性能的前端代码,提升用户体验。