回流(Reflow)
回流发生在页面的布局和几何属性发生变化时,需要重新计算元素的位置和尺寸。它是一个代价高昂的操作,因为它不仅会重新计算目标元素,还可能影响其所有子元素、父元素和兄弟元素。
触发回流的情况
添加、删除、修改DOM元素:
插入新元素。
删除现有元素。
修改元素的内容(例如更改文本)。
移动或调整元素:
修改元素的CSS属性,如width, height, margin, padding, border, top, left等。
改变元素的样式:
使用JavaScript修改元素的样式。
改变页面的布局:
改变窗口大小。
改变页面字体大小。
读取某些属性:
访问某些属性(如offsetHeight, offsetWidth, scrollTop, scrollLeft等)会强制浏览器执行回流,以确保返回正确的值。
重绘(Repaint)
重绘发生在元素的外观发生变化但不影响其布局时。例如,颜色、背景色、可见性等样式的改变。
触发重绘的情况
改变元素的外观样式:
修改颜色、背景色、透明度、可见性(例如visibility, color, background-color等)。
内容变化:
仅涉及视觉变化,但不影响布局的内容更新。
避免和减少回流和重绘的方法
批量修改样式:
将样式修改集中在一起,通过class进行一次性修改而不是逐条更改。
element.classList.add('new-class');
使用CSS Text:
使用style.cssText一次性应用多个样式变化。
element.style.cssText = "color: red; background-color: blue; width: 100px;";
避免逐条修改DOM:
使用DocumentFragment批量操作DOM。
const fragment = document.createDocumentFragment();
const newElement = document.createElement('div');
fragment.appendChild(newElement);
document.body.appendChild(fragment);
离线操作DOM:
在操作前将元素从DOM树中移除,完成后再将其添加回去。
const parent = element.parentNode;
parent.removeChild(element);
// Modify element...
parent.appendChild(element);
避免触发同步布局:
尽量减少访问会导致回流的属性,如offsetHeight、offsetWidth,可以缓存这些值。
const height = element.offsetHeight;
使用CSS3硬件加速:
使用CSS3动画、转换和过渡,这些通常由GPU处理,可以减少回流和重绘的成本。
.example {
transform: translateZ(0);
}
优化动画和过渡:
使用requestAnimationFrame来优化JavaScript动画。
function animate() {
// Animation logic...
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
避免使用table布局:
使用table元素会导致更多的回流,因为它们的布局依赖于其内容。