发布于 2026-01-05 1 阅读
0

了解浏览器中的重排和重绘 重绘和重排 重排和重绘的原因 减少重绘和重排 Chrome 工具性能资源:DEV 全球展示挑战赛,由 Mux 呈现:展示你的项目!

了解浏览器中的重排和重绘

重喷和重流

导致重流和重绘的原因是什么?

最大限度减少重绘和重排

Chrome 工具性能

资源:

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

最近我了解到了重排(Reflow)和重绘(Repaint)技术,以及它们对网页性能的影响。我写这篇文章就是为了深入探讨重排和重绘。
在正式开始之前,我们先来了解一下浏览器是如何渲染网站的。

浏览器如何渲染网站

  • 当用户输入网址时,它会从服务器获取HTML源代码。
  • 浏览器解析HTML源代码并将其转换为Token。<, TagName, Attribute, AttributeValue, >
  • 令牌将转换为节点,并构建DOM 树。
  • CSSOM将根据 CSS 规则生成。
  • DOM 树和 CSSOM 树将合并成渲染树。
  • 渲染树的构造方式如下:
    • 从 DOM 树的根节点开始,计算哪些元素可见及其计算样式。
    • RenderTree 将忽略不可见的元素,例如(meta, script, link)display:none
    • 它会将可见节点与相应的 CSSOM 规则进行匹配并应用这些规则。
  • 重排:计算每个可见节点的位置和大小
  • 重绘:现在,浏览器会在屏幕上绘制渲染树。

重喷和重流

  • 当改变元素的可见性,但不影响布局时,就会发生重绘。
    • 例如:可见性、背景颜色、轮廓
  • 重排是指重新计算文档中元素的位置和几何形状。当元素发生更改,影响到部分或整个页面的布局时,就会发生重排。元素的重排会导致 DOM 中所有子元素和父元素的后续重排。

回流焊和重喷都是成本很高的操作。

根据 Opera 的说法,大多数页面重排本质上都会导致页面重新渲染:

页面重排会严重影响性能,是导致 DOM 脚本运行缓慢的主要原因之一,尤其是在
处理能力较低的设备(例如手机)上。在很多情况下,页面重排相当于重新布局整个页面。

这是重排可视化的视频。

导致重流和重绘的原因是什么?

  • 添加、删除或更新 DOM 节点时会发生重排。
  • 使用隐藏 DOM 元素display: none会导致页面重排和页面重绘。
  • 隐藏 DOM 元素visibility: hidden只会导致页面重绘,因为布局和位置不会发生变化。
  • 移动或动画化 DOM 节点会触发重排和重绘。
  • 调整窗口大小会触发重排。
  • 更改字体样式会改变元素的几何形状。这意味着它可能会影响页面上其他元素的位置或大小,而这两种情况都需要浏览器执行重排。一旦这些布局操作完成,任何受损的像素都需要重新绘制。
  • 添加或移除样式表会导致页面重排/重绘。
  • 脚本操作 DOM 是一项开销很大的操作,因为每次文档或文档的某个部分发生更改时,脚本都需要重新计算。正如我们从触发页面重排的各种因素中看到的那样,页面重排每秒可能发生成千上万次。


var bodyStyle = document.body.style; // cache

bodyStyle.padding = "20px"; // reflow, repaint
bodyStyle.border = "10px solid red"; // reflow, repaint

bodyStyle.color = "blue"; // repaint only, no dimensions changed
bstyle.backgroundColor = "#cc0000"; // repaint

bodyStyle.fontSize = "2em"; // reflow, repaint

// new DOM element - reflow, repaint
document.body.appendChild(document.createTextNode('Hello!'));


Enter fullscreen mode Exit fullscreen mode

最大限度减少重绘和重排

为了减少页面重排/重绘对用户体验的负面影响,策略很简单,就是减少页面重排和重绘的次数,以及对样式信息的请求,这样浏览器就能优化页面重排。那么​​,该如何实现呢?

  • 不要逐个修改样式。为了保持代码的简洁性和可维护性,最好修改类名,而不是样式本身。如果样式是动态的,请编辑cssText属性。


// bad
var left = 10,
    top = 10;
el.style.left = left + "px";
el.style.top  = top  + "px";

// better 
el.className += " theclassname";

// or when top and left are calculated dynamically...

// better
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";


Enter fullscreen mode Exit fullscreen mode
  • 批量 DOM 更改

    • 使用容器documentFragment来保持温度变化
    • 克隆、更新、替换节点
    • 隐藏元素display: none(1 次重排,1 次重绘),添加 100 次更改,恢复显示(总共 2 次重排,2 次重绘)
  • 不要重复请求计算样式,将它们缓存到变量中。

    • 多次读/写操作(例如对元素的高度属性进行读/写)
    • 多次向 DOM 写入数据,然后再读取数据,导致文档重排。
    • 读取(缓存),写入(使布局失效),读取(触发布局)。
    • 解决方法:先阅读所有内容,然后再写入所有内容。

Chrome 工具性能

Chrome 提供了一个很棒的工具,可以帮助我们了解代码的运行情况,例如有多少次重排(布局)和重绘,以及有关内存、事件等的更多详细信息。

错误代码



var box1Height = document.getElementById('box1').clientHeight;
document.getElementById('box1').style.height = box1Height + 10 + 'px';

var box2Height = document.getElementById('box2').clientHeight;
document.getElementById('box2').style.height = box2Height + 10 + 'px';

var box3Height = document.getElementById('box3').clientHeight;
document.getElementById('box3').style.height = box3Height + 10 + 'px';

var box4Height = document.getElementById('box4').clientHeight;
document.getElementById('box4').style.height = box4Height + 10 + 'px';

var box5Height = document.getElementById('box5').clientHeight;
document.getElementById('box5').style.height = box5Height + 10 + 'px';

var box6Height = document.getElementById('box6').clientHeight;
document.getElementById('box6').style.height = box6Height + 10 + 'px';


Enter fullscreen mode Exit fullscreen mode

性能监视器用于检测不良代码

优化代码



var box1Height = document.getElementById('box1').clientHeight;
var box2Height = document.getElementById('box2').clientHeight;
var box3Height = document.getElementById('box3').clientHeight;
var box4Height = document.getElementById('box4').clientHeight;
var box5Height = document.getElementById('box5').clientHeight;
var box6Height = document.getElementById('box6').clientHeight;

document.getElementById('box1').style.height = box1Height + 10 + 'px';
document.getElementById('box2').style.height = box2Height + 10 + 'px';
document.getElementById('box3').style.height = box3Height + 10 + 'px';
document.getElementById('box4').style.height = box4Height + 10 + 'px';
document.getElementById('box5').style.height = box5Height + 10 + 'px';
document.getElementById('box6').style.height = box6Height + 10 + 'px';


Enter fullscreen mode Exit fullscreen mode

用于优化代码的性能监视器

资源:

文章来源:https://dev.to/gopal1996/understanding-reflow-and-repaint-in-the-browser-1jbg