经典面试题---回流?重绘?如何优化?

253 阅读4分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

回流和重绘是由于浏览器的再次渲染所引起的一个话题,我们首先要知道浏览器的渲染过程:

通常来说,渲染引擎会解析HTML文档来构建DOM树,与此同时,渲染引擎也会用CSS解析器解析CSSDOM树。接下来,DOM树和CSSDOM树关联起来构成渲染渲染树(render tree),然后浏览器根据渲染树布局,渲染整个页面。

在这里插入图片描述

回流:当渲染树(render tree)的一部分或者全部元素因为尺寸,布局,显示和隐藏,或者元素内部的文字结构发生变化,导致页面需要重新构建页面的时候,回流就产生了。 重绘:当一个元素的尺寸,布局,显示和隐藏没有改变,而是改变了元素的外观风格的时候(比如修改字体颜色),重绘就发生了。

结论回流必定触发重绘,而重绘不一定触发回流。回流会导致渲染树需要重新计算,开销比重绘大,所以我们要尽量避免回流的产生。

回流的产生

  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时,也会触发回流,原理是一样的,都为求一个“即时性”和“准确性”。

重绘的产生

当render tree一些元素需要更新属性,这些属性是影响元素外观的,风格的,不影响布局,比如visibility,outline,背景颜色,字体颜色等等。

回流和重绘的优化

  1. 操作DOM的时候,尽量使用低层级的DOM节点继续操作。
  2. 尽量不要使用table布局,一个小小的改动可能会使整个table进行重新布局。
  3. 不要频繁操作元素的样式,对于静态页面,可以修改类名,而不是样式。
  4. 使用transform代替topleftmargin-left等属性。
  5. 不在循环中频繁获取操作DOM的元素样式,offsetWidth
  6. 使用fixedabsolute,使元素脱离文档流,他们发生变化不影响其他元素。
  7. 避免频繁操作DOM,可以创建一个文档片段documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
  8. 将元素先设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
  9. DOM的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机制。

两道面试题

1. documentFragment 是什么?用它跟直接操作 DOM 的区别是什么?

DocumentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。

当我们把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。

在频繁的DOM操作时,我们就可以将DOM元素插入DocumentFragment,之后一次性的将所有的子孙节点插入文档中。

和直接操作DOM相比,将DocumentFragment 节点插入DOM树时,不会触发页面的重绘,这样就大大提高了页面的性能。

2. 如何优化动画?

对于如何优化动画,我们知道,一般情况下,动画需要频繁的操作DOM,就就会导致页面的性能问题,我们可以将动画的position属性设置为absolute或者fixed,将动画脱离文档流,这样他的回流就不会影响到页面了。