首页 > 其他分享 >【DOM】重绘与重排详解及在性能优化中的应用

【DOM】重绘与重排详解及在性能优化中的应用

时间:2024-03-22 15:32:25浏览次数:15  
标签:浏览器 DOM 元素 渲染 重排 重绘 页面

DOM树

表示页面结构

渲染树

表示DOM节点如何展示

DOM树中需要展示的节点在渲染树中至少存在一个对应的节点(隐藏的DOM元素在渲染树中没有对应的节点)。渲染树中的节点被称为“帧(frames)”或“盒(boxes)”。符合CSS模型的定义。理解页面元素为一个具有内边距、外边距、边框、位置的盒子。一旦DOM和渲染树构建完成,浏览器就开始显示(绘制 paint)页面元素。

当DOM元素变化影响了元素的集合属性(宽和高)——比如改变边框宽度或者给段落添加文字,导致行数增加——浏览器需要重新计算元素的几何属性, 同样其他元素的几何属性和位置也会因此受到影响。 浏览器会使渲染树中受到影响的部分失效, 并重新构造渲染树。 这个过程称为 “ 重排(reflow)”。完成重排后, 阅览器会重新绘制受影响的部分到屏幕中,该过程称为 “ 重绘(repaint)"。

并不是所有的DOM变化都会影响几何属性。 例如, 改变一个元素的背景色并不会影响色的宽和高。 在这种情况下, 只会发生一次重绘(不需要重排), 因为元素的布局并没有改变。

重绘和重排操作都是代价昂贵的操作,它们会导致 Web 应用程序的 UI 反应迟钝。所以, 应当尽可能减少这类过程的发生。

重排何时发生

正如前文所提到的, 当页面布局和几何属性改变时就需要“重排”。下述情况中会发生重排。

  • 添加或删除可见的DOM元素。
  • 元素位置改变。
  • 元素尺寸改变(包括:夕|、边距、 内边距、 边框厚度、 宽度、 高度等属性改变)。内容改变, 例如: 文本改变或图片被另一个不同尺寸的图片替代。
  • 页面谊染器初始化。
  • 浏览器窗口尺寸改变。

根据改变的范围和程度, 渲染树中或大或小的对应的部分也需要重新计算。 有些改变会触发整个页面的重排: 例如, 当滚动条出现时。

渲染树变化的排队与刷新

由干每次重排都会产生计算消耗, 大多数浏览器通过队列化修改并批量执行来优化重排过程。 然而, 你可能会(经常不知不觉)强制刷新队列并要求计划任务立刻执行。 获取布局信息的操作会导致歹lj队刷新, 比如以下方法:

  • offsetTop, offsetleft, offsetWidth, offsetHeight
  • scrollTop, scrollleft, scrollWidth, scrollHeight
  • clientTop, clientleft, clientWidth, clientHeight
  • getComputedStyle() (currentStyle in IE)

以上属性和方在是需要返回最新的布局信息, 因此浏览器不得不执行渲染列队中的 “待处理变化” 井触发重排以返回正确的值。

在修改样式的过程中, 最好避免使用上面列出的属性。它们都会刷新渲染队列, 即使你是在获取最近未发生改变的或者与最新改变无关的布局信息。

最小化重绘和重排

重绘和重排可能代价非常昂贵,因此一个好的提高程序响应速度的策略就是减少此类操作的发生。为了减少发生次数,应该合并多次对DOM和样式的修改,然后一次处理掉。

改变样式

考虑这个例子:

var el= document.getElementByid( 'mydiv'); 
el.style.borderleft = 'lpx'  
el. style.borderRight = '2px '
el. style.padding = '5px'

示例中有三个样式属性被改变,每一 个都会影响元素的几何结构。 最糟糕的情况下,会导致浏览器触发三次重排。 大部分现代浏览器为此做了优化, 只会触发一次重排, 但是在旧版浏览器中或者有一个分离的异步处理过程时(比如使用计时器), 仍然效率低下。 如果在 上面代码执行时, 有其他代码请求布局信息, 这会导致触发三次重排。 而且, 这段代码四 次访问DOM, 可以被优化。

够达到同样效果且效率更高的方式是: 合并所有的改变然后一次处理, 这样只会修改DOM一次。 使用cssText属性可以实现:

el.style.cssText += ' ;border-left: 1px' ;

另一个一次性修改样式的办法是修改 css的class名称, 而不是修改内联样式。 这种方法适合那些不依赖于运行逻辑和计算的情况。 改变 css 的class名称的方也更清晰, 更易于维护。它有助于保持你的脚本与免除显示性代码, 尽管它可能带来轻微的性能影响, 因为 改变类时需要检查级联样式。

var el= document.getElementByld('mydiv'); 
el.className ='active'

批量修改DOM

当需要对DOM元素进行一系列操作时, 可以通过以下步骤来减少重绘和重排的次数:

  1. 使元素脱离文档流。
  2. 对其应用多重改变。
  3. 把元素带回文档中。

该过程里会触发两次重排一一一第一步和第三步。 如果你忽略这两个步骤, 那么在第二步所产生的任何修改都会触发一次重排。

有三种基本方法可以使DOM脱离文档:

  • 隐藏元素, 应用修改, 重新显示。
  • 使用文档片断(docuement fragment)在当前DOM之外构建一个子树, 再把它拷贝回文档。
  • 将原始元素拷贝到一个脱离文档的节点中,改副本, 完成后再替换原始元素。

缓存布局信息

如前文所述,浏览器尝试通过队列化修改和批量执行的方式最小化重排次数。当你查询布局信息时,比如获取偏移量(offsets)、滚动位置(scroll values)或计算出的样式值(computedsytle values)时,浏览器为了返回最新值,会刷新队列并应用所有变更。最好的做法是尽量减少布局信息的获取次数,获取后把它赋值给局部变量,然后再操作局部变量。

考虑一个例子,把myElement元素沿对角线移动,每次移动一个像素,从100像素×100像素的位置开始,到500像素x500像素的位置结束。在timeout循环体中你可以使用下面的方法:

//低效的
myElement.style.left = 1 + myElement.offsetLeft +'px'
myElement.style.top = 1 + myElement.offsetTop +'px'
if (myElement.offsetLeft >= 500) { 
	stop()
}

这种方法效率低下,因为元素每次移动时都会查询偏移量,导致浏览器刷新渲染列队而不利于优化。一个更好的方法是,获取一次起始位置的值,然后将其赋值给一个变量,比如var current = myElement.offsetleft。然后,在动画循环中,直接使用current变量而不再用偏移量:

current++ 
myElement.style.left = current+'px'
myElement.style.top = current+'px'
if (current >= 500) { 
	stop()
}

让元素脱离动画流

用展开/折叠的方式来显示和隐藏部分页面是一种常见的交互模式。它通常包括展开区域的几何动画,井将页面其他部分推向下方。

一般来说,重排只影响渲染树中的一小部分,但也可能影响很大的部分,甚至整个渲染树。 浏览器所需要重排的次数越少,应用程序的响应速度就越快。因此当页面顶部的一个动画推移页面整个余下的部分时,会导致一次代价昂贵的大规模重排,让用户感到页面一顿一 顿的。渲染树中需要重新计算的节点越多,情况就会越糟。

使用以下步嘱可以避免页面中的大部分重排:

  1. 使用绝对位置定位页面上的动画元素, 将其脱离文档流。
  2. 让元素动起来。 当它扩大时, 会的时覆盖部分页面。 但只是页面一个区域的重绘过程, 不会产生重排并重绘页面的大部分内容。
  3. 当动画结束时恢复定位, 从而只会下移一次文档的其他元素。

IE和:hover

从IE 7开始,IE允许在任何元素(严格模式下)上使用:hover这个 css 伪选择器。 然而,如果你有大量元素使用了:hover, 那么会降低响应速度。 此问题在IE8中更为明显。

例如,如果你创建一个5列和500~1000行的表格,并使用tr:hover改变背景色来高亮显示鼠标所在的当前行, 当鼠标在表格上移动时, 性能会降低。 高亮过程会变慢, CPU使用率会提高到80%~90%。所以在元素很多时应避免使用这种效果,比如很大的表格或很长的列表。

标签:浏览器,DOM,元素,渲染,重排,重绘,页面
From: https://blog.csdn.net/chtazycdf/article/details/136750698

相关文章

  • 论文精读系列文章——Point-LIO: Robust High-Bandwidth Light Detection and Ranging
    论文精读系列文章下面是SLAM算法与工程实践系列文章的总链接,本人发表这个系列的文章链接均收录于此论文精读系列文章链接下面是专栏地址:论文精读系列文章专栏文章目录论文精读系列文章论文精读系列文章链接论文精读系列文章专栏前言论文精读系列文章——......
  • 前端基础之JavaScriptDOM和BOM
    一、JavaScript的组成JavaScript的实现包括以下3个部分:ECMAScript(核心)描述了JS的语法和基本对象文档对象模型(DOM)处理网页内容的方法和接口浏览器对象模型(BOM)与浏览器交互的方法和接口核心(Core):核心部分包括语言的基本语法、数据类型、控制结构等。这些......
  • 一文弄懂浏览器的重排(回流)与重绘
    浏览器渲染过程在浏览器从服务器下载到资源后解析HTML形成DOM树,解析CSS形成CSSOM树。渲染树:将DOM树和CSSOM树结合创建render树。Layout:根据渲染树进行布局,得到节点的几何信息(位置大小)。Painting:布局完成后浏览器根据结果和渲染树,将具体的像素绘制出来。重......
  • 关于衍射光波导设计中的K阈(k-domain)分析的一些学习
     对于衍射光波导的设计来说,不能简单利用几何光的方法对光线的传播路径进行描述。因此可以基于K空间波矢的矢量运算来进行描述。 在阈值分析中,衍射光波导的光线传播遵循二个引导条件,分别为全内反射条件和引导模式条件。如图所示。             ......
  • pikachu靶场第八关——XSS(跨站脚本)之DOM型xss(附代码审计)
    什么是DOM?简单来说DOM文档就是一份XML文档,当有了DOM标准之后,DOM便将前端html代码化为一个树状结构,方便程序和脚本能够轻松的动态访问和更新这个树状结构的内容、结构以及样式,且不需要经过服务端,所以DOM型xss在js前端自己就可以完成数据的输入输出,不与服务器产生交互,这样来说DO......
  • Windows 系统中进行一些域管理操作 net group /domain 命令 参数
    Windows系统中进行一些域管理操作。以下是一些常见的用法和参数:列出所有域用户组:bashCopyCodenetgroup/domain查看特定用户组的成员:bashCopyCodenetgroup"GroupName"/domain添加用户到指定用户组:bashCopyCodenetgroup"GroupName"UserName/add/domain......
  • 重排和重绘
    重绘与重排的重排:部分渲染树(或者整个渲染树)需要重新分析并且节点尺寸需要重新计算,表现为重新生成布局,重新排列元素重绘:由于节点的几何属性发生改变或者由于样式发生改变,例如改变元素背景色时,屏幕上的部分内容需要更新,表现为某些元素的外观被改变单单改变元素的外观,肯定不......
  • DOM事件流
      DOM事件流描述了在HTML文档中,事件是如何从触发元素传播到文档根节点的过程。DOM事件流  DOM事件流分为三个阶段:捕获阶段(CapturingPhase)、目标阶段(TargetPhase)和冒泡阶段(BubblingPhase)。捕获阶段(CapturingPhase):事件从文档根节点开始向下传播,经过父级元素直到......
  • react使用map循环渲染dom时,增加或删减数组,但想保持其余的dom与数据不发生改变
     核心思路:dom渲染与key值有关系,如果想实现上述需求,则需要关注改变前后的循环项的key值是否发生改变currentCabinet?.map((item,index)=><BaseInfokey={`currentCabinet${item?.ciId}`}sceneKey={sceneKey}currentCabinet={item}/>)如以上示例,以ciId为key值,可以保证即......
  • L2-022 重排链表
    这道题真的烦,输出想半天。反正就是要区分奇偶,才能知道那个结点最后要打印出-1.我看网上遇到的都是测试点3的问题,不过我有问题的是测试点1,前三个出问题就是节点数奇偶的问题。#include<bits/stdc++.h>usingnamespacestd;map<int,pair<int,int>>mp;intmain(){ ints......