什么是重排与重绘?如何减少重排?

        在页面的生命周期中,一些效果的交互都有可能发生重排(Layout)和重绘(Painting),这些都会使我们付出高额的性能代价。 浏览器从下载文件至本地到显示页面是个复杂的过程,这里包含了重绘和重排。通常来说,渲染引擎会解析HTML文档来构建DOM树,与此同时,渲染引擎也会用CSS解析器解析CSS文档构建CSSOM树。接下来,DOM树和CSSOM树关联起来构成渲染树(RenderTree),这一过程称为Attachment。然后浏览器按照渲染树进行布局(Layout),最后一步通过绘制显示出整个页面。

        其中重排和重绘是最耗时的部分,一旦触发重排,我们对DOM的修改引发了DOM几何元素的变化,渲染树需要重新计算, 而重绘只会改变vidibilityoutline、背景色等属性导致样式的变化,使浏览器需要根据新的属性进行绘制。更比而言,重排会产生比重绘更大的开销。所以,我们在实际生产中要严格注意减少重排的触发。 

触发重排的操作主要是几何因素:

1.页面第一次渲染 在页面发生首次渲染的时候,所有组件都要进行首次布局,这是开销最大的一次重排。

2.浏览器窗口尺寸改变

3.元素位置和尺寸发生改变的时候

4.新增和删除可见元素

5.内容发生改变(文字数量或图片大小等等)

6.元素字体大小变化。

7.激活CSS伪类(例如::hover)。

8.设置style属性

9.查询某些属性或调用某些方法。比如说: offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight 除此之外,当我们调用getComputedStyle方法,或者IE里的currentStyle时,也会触发重排,原理是一样的,都为求一个“即时性”和“准确性”。

触发重绘的操作主要有:

vidibilityoutline、背景色等属性的改变

我们应当注意的是:重绘不一定导致重排,但重排一定会导致重绘。

如何来避免或减少重排带来的巨大开销呢?

         1.分离读写操作

div.style.top = "10px";
div.style.bottom = "10px";
div.style.right = "10px";
div.style.left = "10px";
console.log(div.offsetWidth);
console.log(div.offseHeight);
console.log(div.offsetRight);
console.log(div.offsetLeft);

        原来的操作会导致四次重排和四次重绘,变换顺序之后只会触发一次重排 在第一个console的时候,浏览器把之前上面四个写操作的渲染队列都给清空了。因为渲染队列本来就是空的,所以剩下的console并没有触发重排,仅仅拿值而已。

        2.样式集中改变

        通过classcssText进行集中改变样式

//未进行优化的代码是这样的:
var left = 10;
var top = 10;
el.style.left = left + "px";
el.style.top = top + "px";

        虽然现在大部分现代浏览器都会有Flush队列进行渲染队列优化,但是有些老版本的浏览器比如IE6这样的坑货效率依然低下: 这时我们就可以通过上面所说的利用classcssText属性集中改变样式

//good
el.className += " className";
//or
el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

        3. 缓存布局信息

// bad 强制刷新 触发两次重排
div.style.left = div.offsetLeft + 1 + 'px';
div.style.top = div.offsetTop + 1 + 'px';

// good 缓存布局信息 相当于读写分离
let curLeft = div.offsetLeft;
let curTop = div.offsetTop;
div.style.left = curLeft + 1 + 'px';
div.style.top = curTop + 1 + 'px';

        4. 将DOM离线

        

  • DOM离线化
    一旦我们给元素设置display:none时,元素不会存在于渲染树中,相当于将其从页面“拿掉”,我们之后的操作将不会触发重排和重绘,这叫做DOM的离线化。
    JavaScript dom.display = 'none' // 修改dom样式 dom.display = 'block' 复制代码
  • 通过使用DocumentFragment创建一个dom碎片,在它上面批量操作dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
  • 复制节点,在副本上工作,然后替换它!

 

        5. 将position属性设置为absolutefixed

 position属性为absolutefixed的元素,重排开销比较小,不用考虑它对其他元素的影响

        6. 优化动画

  • 可以把动画效果应用到position属性为absolutefixed的元素上,这样对其他元素影响较小
    动画效果还应牺牲一些平滑,来换取速度,这中间的度自己衡量:
    比如实现一个动画,以1个像素为单位移动这样最平滑,但是Layout就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。
  • 启用GPU加速
    GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU 是专门为处理图形而设计,所以它在速度和能耗上更有效率。
    GPU 加速通常包括以下几个部分:Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。
    /* * 根据结论 将2d transform 换成3d 就可以强制开启GPU加速提高动画性能 */ 
    div { transform: translate3d(10px, 10px, 0); }

 

<think>好的,我现在需要回答用户关于“重排有什么区别”的问题。首先,我应该回忆一下这两个概念的定义和它们在浏览器渲染过程中的作用。 重排(Reflow)应该是指浏览器计算元素的位置和几何属性,新构建页面的布局。当元素的尺寸、位置等发生变化时,浏览器需要新计算其他元素的位置,这可能会导致整个或部分页面布局的新计算。这个过程可能比较消耗性能,特别是在复杂的页面结构中。 (Repaint)则是在元素的外观发生变化,但不影响布局的情况下发生的。比如改变颜色、背景等样式时,浏览器只需要制受影响的部分,而不需要新计算布局。因此,的性能开销比重排小。 接下来,我需要确定这两个概念在浏览器渲染流程中的位置。通常,浏览器的渲染流程包括解析HTML生成DOM树,解析CSS生成CSSOM树,合并成渲染树,然后进行布局(Layout,即重排),最后制(Paint,即)。因此,重排发生在布局阶段,而发生在制阶段。 然后,我需要考虑触发重排的常见操作。例如,改变元素的宽度、高度、位置(如left、top)等会触发重排,而改变颜色、背景、边框样式等则只会触发。不过需要注意的是,某些操作可能会同时触发两者,比如改变元素的宽度可能会导致重排,之后浏览器需要新的尺寸。 另外,现代浏览器可能会对连续的重排操作进行优化,比如将它们合并成一次操作。但作为开发者,仍然应该尽量减少不必要的重排,以提高页面性能。例如,使用CSS的transform属性来做动画,而不是直接修改元素的top/left属性,因为transform通常不会触发重排,可以利用GPU加速,只触发。 还要提到如何避免不必要的重排的方法。比如,使用DocumentFragment进行多次DOM操作后一次性添加到文档中,或者将元素的display设置为none进行修改后再显示,这样修改过程不会触发多次重排。 可能需要举例说明两者的区别,比如修改元素的背景颜色只会导致,而修改元素的宽度会导致重排。此外,获取某些布局信息(如offsetWidth、scrollTop等)会强制浏览器触发重排以获取最新值,这可能会影响性能,特别是在循环中频繁读取这些属性。 最后,总结两者的区别:重排涉及布局变化,消耗较大;仅涉及外观变化,消耗较小。优化时应优先减少重排次数,避免强制同步布局,合理使用CSS属性。</think>(Repaint)和重排(Reflow)是浏览器渲染页面的两个核心机制,它们的区别主要体现在**触发条件**和**性能消耗**上: --- ### 一、本质区别 1. **重排(Reflow)** 浏览器需要**新计算元素的位置和尺寸**(布局阶段)。 - 触发条件:修改影响布局的属性(如宽度、高度、位置、字体大小等) - 示例:`width`, `height`, `margin`, `padding`, `display: none`, `offsetHeight`等 2. **(Repaint)** 浏览器**仅制元素的视觉效果**(制阶段),不涉及布局变化。 - 触发条件:修改仅影响外观的属性(如颜色、背景、边框等) - 示例:`color`, `background`, `border-radius`, `visibility: hidden`等 --- ### 二、性能差异 | | 重排 | | |----------|-----------------------|---------------------| | **消耗** | 高(需新布局整棵树) | 低(仅局部制) | | **关系** | 重排必然引起 | 不一定触发重排 | --- ### 三、典型场景 1. **触发重排操作** ```js element.style.width = "100px"; // 修改尺寸 element.style.left = "20px"; // 修改位置 element.classList.add("new-layout");// 添加影响布局的CSS类 ``` 2. **仅触发操作** ```js element.style.color = "red"; // 修改颜色 element.style.backgroundColor = "#f00"; // 修改背景 ``` --- ### 四、优化建议 1. **避免频繁操作DOM** 使用 `DocumentFragment` 或虚拟DOM技术批量更新。 2. **优先使用CSS动画** 用 `transform` 和 `opacity` 实现动画(触发GPU加速,跳过重排)。 3. **读写分离** 避免在读取布局属性(如 `offsetWidth`)后立即修改样式,防止强制同步布局: ```js // 错误示例(触发多次重排) for (let i = 0; i < 100; i++) { element.style.width = i + "px"; // 写操作 console.log(element.offsetWidth);// 读操作,强制重排 } // 正确做法:先读后写 const width = element.offsetWidth; // 一次性读取 for (let i = 0; i < 100; i++) { element.style.width = width + i + "px"; // 批量写 } ``` 4. **隐藏元素再操作** 对需要大量修改的元素先设置 `display: none`,操作完成后再显示。 --- ### 五、流程图解浏览器渲染过程 ``` 1. 解析HTML → 生成DOM树 2. 解析CSS → 生成CSSOM树 3. 合并DOM+CSSOM → 渲染树(Render Tree) 4. 计算布局 → **重排(Reflow)** 5. 制像素 → **(Repaint)** 6. 合成图层 → 显示页面(Composite) ``` 通过理解重排的机制,开发者可以更高效地优化网页性能,尤其是在高频交互场景(如动画、滚动)中效果显著。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值