浏览器渲染

浏览器渲染原理

在这里插入图片描述

(一)、两个阶段

用户看到页面分为两个阶段:

  1. 页面内容加载完成(DOMContentLoaded);
  2. 页面资源加载完成(load);

(二)、五个步骤

浏览器渲染的过程分为五个步骤:

  1. 浏览器获取HTML文档解析成DOM树
  2. 处理CSS标记,解析CSS文件,构成层叠样式表模型CSSOM
  3. 将DOM和CSSOM合并为渲染树(Render Tree),代表一系列将被渲染的对象
  4. 进行元素布局(layout),从根节点开始
  5. 将各节点绘制(painting)到屏幕上,调用渲染器的paint()方法

(三)、解析HTML文档过程

  1. 解析HTML文档是一行一行读HTML代码的,包括了<script>标签,所以DOM树在构建过程中可能会被CSS和JS的加载而阻塞
  2. display:none的元素和script标签也会在DOM树种

(四)、DOM树和渲染树(Render Tree)

  1. 浏览器从DOM树的根节点开始遍历每个可见节点,然后根据CSS规则树找到每个节点适配的CSS样式规则并应用从而构成渲染树
  2. 渲染树与DOM树不完全对应:
    • display: none的元素不在Render Tree中
    • visibility: hidden的元素在Render Tree中

(五)、渲染阻塞

(script标签和css样式在文档中的位置)

1.JS阻塞

浏览器在构建DOM树的时候,遇到<script>标签的时候DOM构建将会暂停直到脚本完全执行再继续构建DOM;如果是外部脚本,则会等脚本下载完毕再继续构建DOM树。

2.CSS阻塞

由于CSSOM负责存储渲染信息,再合成渲染树之前应该完备(CSS内联、内部、外部都下载完并解析完),只有CSSOM和DOM的解析完全结束浏览器才会进入下一步的渲染,这就是CSS阻塞。

3.减小阻塞

  1. <script>标签位于body标签底部,减少First Paint(解析并显示部分内容)时间,可以尽快的减少白屏事件,但是不会较少DOMContentLoaded被触发的事件
  2. <script>标签上增加属性defer或者async
  • defer:异步下载js文件不会影响后续DOM渲染,脚本会在DOM渲染完毕后,DOMContentLoaded事件调用前执行,脚本按顺序执行。
    (适用于依赖DOM元素的脚本比如评论框。)
  • async:使脚本异步的加载并在允许的情况下执行,不影响DOMContentLoaded事件的调用,先加载完的脚本先执行。
    (适用于不关心DOM元素的脚本。)
  1. CSS样式放在head中,尽快解析CSS保证更快的First Paint,CSSOM完毕之前页面一直处于白屏状态。

(六)、回流和重绘

1.回流(reflow)

浏览器布局发生变化需要重新渲染。这个回退过程叫做回流,回流会从html的根节点root frame开始递归往下。

  • 优化:异步reflow或增量异步reflow,浏览器积攒到足够数量的变化后再做一次reflow。
  • 引起reflow:
    1. 页面第一次渲染
    2. DOM树变化(如增删节点)
    3. Render树变化(如padding改变)
    4. 获取元素的某些属性
    5. 元素CSS设置display:none

2.重绘(repaint)

当改变某个元素的背景色、文字颜色、边框颜色等不影响周围或内部布局的属性的时候,屏幕一部分需要重画但是布局没有发生改变。

  • 引起repaint:
    1. 背景色、颜色、字体改变(字体大小发生变化时,会触发回流)

reflow回流必定引起repaint重绘,重绘可以单独触发

3.优化

(减少reflow、repaint触发次数)

  1. 用transform做形变和位移可以减少reflow
  2. 避免逐个修改节点样式,尽量一次性修改
    使用DocumentFragment将需要多次修改的DOM元素缓存,最后一次性append到真实DOM中渲染
  3. 可以将需要多次修改的DOM元素设置display:none,操作完再显示。(因为隐藏元素不在render树内,因此修改隐藏元素不会触发回流重绘)
  4. 避免多次读取某些属性
  5. 通过绝对位移将复杂的节点元素脱离文档流,形成新的Render Layer,降低回流成本

(七)、优化渲染效率

  1. 样式文件在head标签中,脚本文件在body结束前,可以防止渲染阻塞
  2. 简化并优化CSS选择器
  3. DOM多个操作放在一起
  4. 不一条一条的改变样式,而是通过改变class一次性改变样式。
  5. 先将元素设为display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值