重排和重绘

当页面加载完成后,用户的操作或数据的改变都有可能会导致页面的重新渲染,页面重新渲染可以分为两种:重排和重绘。

对元素的视觉属性修改,比如文字的颜色,元素的背景等,都会导致页面重绘。

元素布局发生变化时,会导致页面重排。比如窗口的改变,元素宽高,padding的改变,dom节点的增加、删除等。

通常来说,重排的影响更大,它会导致局部或全部页面重新运算:重新运算元素位置和大小。

不管是重排或重绘,都会阻塞浏览器,重新渲染的过程中,JavaScript会被阻塞,用户的交互行为也会被卡住,复杂的css动画甚至会拖慢JavaScript运行速度。

场景

css属性改变会导致页面重新渲染,具体看https://csstriggers.com/ 。
- display:none会导致重排和重绘。
- visibility:hidden会导致页面重绘。
- css动画
- 通过JavaScript添加和修改样式。

用户交互也会导致重新渲染。
- 缩放浏览器窗口
- 对dom节点新增、删除、修改都会导致重排
- 光标:hover,进入输入框,修改浏览器字体都会导致重排

最佳实践

  • css读写操作分开
  • 如果有下面这些属性的读操作,都会引发浏览器立即重新渲染:
offsetTop/offsetLeft/offsetWidth/offsetHeight
scrollTop/scrollLeft/scrollWidth/scrollHeight
clientTop/clientLeft/clientWidth/clientHeight
getComputedStyle()
  • 通过class或cssText批量更新样式
  • DOM 样式离线更新:尽量使用离线 DOM,而不是真实的网页 DOM 来改变元素样式。比如,操作 Document Fragment对象,完成后再把这个对象加入 DOM。再比如,使用 cloneNode() 方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。
  • 使用 display: none 进行样式批量更新:先将元素设为 display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。
  • 善用 position:position 属性为 absolute 或 fixed 的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。
  • 将元素设置为不可见:只在必要的时候,才将元素的 display 属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden 的元素只对重绘有影响,不影响重排。
  • 减少样式的更新频率:使用虚拟 DOM 脚本库,比如 React 等。
  • 调节 js 运行帧率:使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染的频率。
  • 慎用 table 布局:table 的单元格具有非常好的自适应特性,但是同时代价也很高,能不用就不用。如果非要使用 table ,给 table 添加 table-layout: fixed 属性,这个属性的目的是让后面单元格的宽度由表头的宽度来决定——减少布局的计算量。

发表评论

电子邮件地址不会被公开。 必填项已用*标注