重绘重排拖慢网页?这几种HTML写法正在偷偷卡你页面

网页时突然卡顿、动画掉帧、滚动不跟手——很多开发者第一反应是“浏览器太卡”,其实问题常出在自己写的 HTML 和 CSS 上。重绘(Repaint)和重排(Reflow)这两个词听起来专业,但说白了就是浏览器在“反复擦黑板、重新画图”,而每一次擦和画,都在消耗性能。

啥时候浏览器会重排?

只要改动了影响元素几何属性的样式,比如 widthheightpaddingmargintopleft,或者增删 DOM 节点、改变 display 值(比如从 none 改成 block),浏览器就得重新计算整个布局树,这就是重排。它比重绘代价高得多,因为牵一发而动全身——一个 <div> 宽度变了,它下面所有兄弟、子元素的位置都可能要重算。

重绘又是什么?

只改颜色、背景、阴影、visibility 这类不影响位置和大小的样式,浏览器不用重算布局,但得重画像素,叫重绘。单独看好像不严重,但如果高频触发(比如用 mouseover 不停改 color),也会让页面变“糊”、变卡。

一个真实翻车现场

有位朋友做后台表格,想实现“鼠标悬停整行高亮”。他写了这么一段:

.table-row:hover {
  background-color: #f5f5f5;
  box-shadow: 0 1px 2px rgba(0,0,0,.1);
}

看着没问题?但表格用了 border-collapse: collapse,且每行都有 border-bottom。结果一 hover,浏览器发现边框渲染逻辑被扰动,立刻触发重排——上百行表格,每次悬停都卡半秒。

后来他把 box-shadow 换成纯背景色过渡,再加 will-change: background-color 提前告知浏览器,流畅多了。

怎么避开坑?几个顺手就能改的习惯

① 少用 table 布局做复杂交互:老式表格重排开销极大,现代页面优先用 flexgrid

② 批量改样式,别一句一句问:别这样写 JS:

el.style.width = '200px';
el.style.height = '100px';
el.style.opacity = '0.8';

改成一次性加 class:

el.className = 'card-active';

③ 动画尽量走 transform 和 opacity:这两者由合成器(Compositor)单独处理,不触发重排重绘。比如滑入效果,用 transform: translateX(100px),别用 left: 100px

④ 避免强制同步布局:像 offsetTopgetComputedStyle() 这类 API 会逼浏览器立刻完成重排再返回值。如果前后夹着样式修改,就等于“改完马上算,算完再改”,恶性循环。实在要用,把读取操作集中到一起,写在修改之前或之后,别穿插。

小技巧:用 Chrome DevTools 看一眼

打开 F12 → “Rendering” 面板 → 勾选 “Paint flashing” 和 “Layout Shift Regions”。鼠标划过页面,绿色闪动是重绘区域,红色是重排区域。真实场景下试一试,哪些按钮、哪些弹窗一展开就满屏红,立马定位问题源头。

优化不是追求极致,而是让日常操作不卡顿、加载不肉眼可见延迟。很多时候,换一种写法,用户就感觉“这网站真快”。