chst365's blog chst365's blog
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

chst365

DIV工程师
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 浏览器

    • 浏览器工作原理
    • 浏览器架构
    • 内存泄漏
    • 重排和重绘
      • 页面生成的过程
      • 重排比重绘大
      • 重排(reflow)
        • 哪些情况会发生重排
        • 重排影响的范围
      • 重绘(Repaints)
      • 重排优化建议
      • 如何在浏览器中查看页面渲染时间
    • DOM树
  • webpack

  • TypeScript

  • 性能

  • 工程化

  • React

  • JavaScript

  • 编程题

  • React技术揭秘

  • 算法

  • 前端
  • 浏览器
chst365
2021-04-09
目录

重排和重绘

# 页面生成的过程

  1. HTML 被 HTML 解析器解析成 DOM 树
  2. CSS 被 CSS 解析器解析成 CSSOM 树
  3. 结合 DOM 树和 CSSOM 树生成一颗渲染树 (Render Tree),此过程为 Attachment
  4. 生成布局(flow),浏览器在屏幕上画出渲染树中的所有节点
  5. 将布局绘制(paint)在屏幕上,显示出整个页面

# 重排比重绘大

  • 重绘不一定导致重排,但重排一定导致重绘

# 重排(reflow)

重排也叫回流,重新生成布局,重新排列元素

# 哪些情况会发生重排

  • 页面初始渲染
  • 添加/删除可见的 DOM 元素
  • 改变元素位置
  • 改变元素尺寸,如边距、填充、边框、宽高等
  • 改变元素内容,如文字数量,图片大小等
  • 改变元素字体大小
  • 改变浏览器窗口尺寸,如 resize 事件发生时
  • 激活 CSS 伪类,如:hover
  • 设置 style 属性的值,因通过设置 style 属性改变节点样式,每次设置都会触发一次 reflow
  • 查询某些属性或调用某些计算方法:offsetWidth,offsetHeight等,调用getComputedStyle方法
常见引起重排属性和方法 -- -- --
width height margin padding
display border-width border position
overflow font-size vertical-align min-height
clientWidth clientHeight clientTop clientLeft
offsetWidth offsetHeight offsetTop offsetLeft
scrollWidth scrollHeight scrollTop scrollLeft
scrollIntoView() scrollTo() getComputedStyle()
getBoundingClientRect() scrollIntoViewIfNeeded()

# 重排影响的范围

由于浏览器渲染界面是基于流式布局模型,所以触发重排时会对周围的 DOM 重新排列

  • 全局范围:从根节点 html 开始对整个渲染树进行重新布局
  • 局部范围:对渲染树的某部分或某一个渲染你对象进行重新布局

# 重绘(Repaints)

当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫重绘

常见的引起重绘的属性 -- -- --
color border-style visibility background
text-decoration background-image background-position background-repeat
outline-color outline outline-style border-radius
outline-width box-shadow background-size

# 重排优化建议

  • 减少重排范围

    • 尽可能在低层级的 DOM 节点上,不要通过父元素去影响子元素
    • 不要使用 table 布局,可能很小的改动造成整个 table 的重新布局,不得已使用 table,可设置table-layout:auto或table-layout:fixed使 table 一行一行渲染,限制 reflow 的影响范围
  • 减少重排次数

    • 样式集中改变

      • 样式统一在cssText变量中编辑
      • 更改类名而不是直接修改样式
      • //
        // bad
        var left = 10;
        var top = 10;
        el.style.left = left + "px";
        el.style.top = top + "px";
        
        // 当top和left的值是动态计算而成时...
        // better
        el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
        
        // better
        el.className += " className";
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
    • 分离读写操作

      • DOM 的多个读操作(或多个写操作),应该放在一起。
      • // bad 强制刷新 触发四次重排+重绘
        div.style.left = div.offsetLeft + 1 + "px";
        div.style.top = div.offsetTop + 1 + "px";
        div.style.right = div.offsetRight + 1 + "px";
        div.style.bottom = div.offsetBottom + 1 + "px";
        
        // good 缓存布局信息 相当于读写分离 触发一次重排+重绘
        var curLeft = div.offsetLeft;
        var curTop = div.offsetTop;
        var curRight = div.offsetRight;
        var curBottom = div.offsetBottom;
        
        div.style.left = curLeft + 1 + "px";
        div.style.top = curTop + 1 + "px";
        div.style.right = curRight + 1 + "px";
        div.style.bottom = curBottom + 1 + "px";
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
    • 将 DOM 离线

      • 使用 dispaly:none
      • 通过DocumentFragment (opens new window)创建一个dom碎片,在此上面批量操作dom,操作完成后,再添加到文档中,这样只会触发一次重排
      • 复制节点,在副本上工作,然后替换他
    • 使用 absolute 或 fixed 脱离文档流

      • 使用绝对定位会使该元素独立成为渲染树中body的一个子元素,一些其他在这个区域的节点可能需要重绘,但不需要重排
    • 优化动画

      • 把动画效果应用到position:absolute/fixed的元素上
      • 启用 CPU 加速:Canvas2D/布局合成、transitions、transforms、WebGL 和 video

# 如何在浏览器中查看页面渲染时间

  1. 打开开发者工具:点击 Performance 左侧有个小圆点 点击刷新页面会录制整个页面加载出来 时间的分配情况。如图

    • 蓝色:网络通信和 HTML 解析
    • 黄色:js 执行
    • 紫色:样式计算和布局,即重排
    • 绿色:重绘
  2. 点击 Event Log:单独勾选 Loading 项会显示 html 和 css 加载时间。如下

#浏览器
上次更新: 2021/04/22, 00:08:06
内存泄漏
DOM树

← 内存泄漏 DOM树→

最近更新
01
面试官
03-27
02
this&指针&作用域&闭包
03-27
03
前端
03-27
更多文章>
Theme by Vdoing | Copyright © 2019-2025 chst365 | 豫ICP备17031889号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式