重新认识浏览器的回流和重绘

1,195 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

前言

在学习回流和重绘的知识点之前,我们应该了解一下浏览器渲染过程:

  1. 浏览器发送请求下载了所有的 HTML 资源,然后解析 HTML, 生成 DOM 树,解析 CSS,生成 CSSOM 树。
  2. DOM 树和 CSSOM 树结合,生成 渲染树(Render Tree)
  3. 根据生成的渲染树,进行 回流(Layout) ,得到节点的几何信息(位置,大小)。
  4. 根据 渲染树 以及 回流 得到的几何信息,重绘(Painting) 得到节点的绝对像素。
  5. 将像素发送给GPU,展示(Dsiplay) 在页面上 。

其实渲染的过程有点类似于 绘画 一样:

  1. 构图 — 规划 整体的结构(Render Tree)
  2. 找出结构线 — 确定每块区域的 位置、大小(Layout)
  3. 填充内容 — 得到节点的绝对像素 重绘(Painting)
  4. 深入刻画 — 合并合成层、将像素发送给GPU,展示在页面上等操作 展示(Dsiplay)

关于对绘画的抽象仅代表我个人,我对于浏览器渲染和绘画的理解可能还不到位,如果有不对的地方,还请见谅哈😂 ~~

重绘 (repaint)

概念: 当页面中元素样式的改变并不影响它在文档流中的位置时(例如:colorbackground-colorvisibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

重绘全名就是重新绘画,可以理解为 绘画 时在 画布 上重新给某个东西加上一些颜色或者阴影,而且是在不影响

整个画布排版的情况下。

几个触发重绘的例子:

  • 修改元素的 color
  • 修改元素的 background-color
  • 添加阴影效果 box-shaow
  • 隐藏或者显示 visibility

回流 (reflow)

概念: 当部分或者全部元素的尺寸、大小、结构发生改变时,会触发浏览器重新渲染部分或者全部页面的过程称为回流。

回流也可以叫作 重排 ,就是重新排版的意思,可以理解为 绘画 时 因为某一块地方修改了 结构 导致要重新画一次。

几个触发重绘的例子:

  • input 输入文字
  • 修改元素的宽高、内外边距(padding、margin)
  • 添加或删除 DOM 元素
  • CSS 伪元素触发,例如 hover
  • js 中一些常用的 api,例如修改元素的 offsetWidthoffsetHeight 等等
  • 浏览器尺寸大小发生变化,例如 resize 事件

两者之间的关系

回流比重绘的代价要高,因为回流会导致部分或者全部页面重新渲染。

经典的代表就是 ul li 元素,这是大家机场使用的标签之一,如果我们在多个 li 之间添加或删除 一个或者多个 li ,就会导致他的父元素以及依赖他的元素产生回流,就像 蝴蝶效应 一般。

大家可以通过在 谷歌浏览器 中 F12 开启控制台,在摁 ESC 打开窗口,点击下图中的 Rendering,勾选上 Paint flashing 就可以查看页面中触发回流和重绘的情况。

image-20220410212634910.png

image-20220410212802954.png

如何减少和优化

我们知道了回流和重绘对浏览器渲染造成了一定的性能影响,那我们应该怎么样减少回流和重绘呢?

CSS 方面:

  • 避免使用 table 布局
  • 避免设置多层内联样式
  • dispaly:none 隐藏元素,应用修改,重新显示
  • 让元素脱离文档流,这样他就不会影响到其他元素的排列布局了
  • 使用 animation 动画效果 代替 postion:absolute 移动元素

JS 方面:

  • 避免频繁操作 DOM,使用文档碎片 documentFragment 进行 DOM 操作,最后再把它添加到页面中

  • 创建多个 calss 来集中切换元素的样式

  • CSS3 硬件加速(GPU加速)

    如果你为太多元素使用 CSS3 硬件加速,会导致内存占用较大,也会有性能问题,有利也有弊吧~~

    常见的触发硬件加速的 CSS 属性:

    • transform
    • opacity
    • filters

总结

以上就是本次分享的全部内容~~

如果觉得文章写得不错,对你有所启发的,请不要吝啬 点个 关注 并在 评论区 留下你宝贵的意见哦~~😃