彻底理解浏览器的渲染原理

一个网页从输入URL地址到显示是一个怎样的过程?

  • 输入地址后,地址通过DNS服务器进行域名解析出对应的ip地址
  • ip地址对应的主机发送http请求获取对应的静态资源
  • 默认情况下服务器会返回index.html文件

index.html是怎么被解析渲染的?

一个网页下载下来后由渲染引擎进行解析,下面内容都是由浏览器内核(比如苹果的webkit内核的WebCore部分和谷歌的blink)进行解析渲染的,详细图解如下:

在这里插入图片描述

1. HTML解析

浏览器内核解析HTML会构建DOM Tree

在这里插入图片描述

2. 生成CSS规则

  • 在解析过程中当遇到link元素引入CSS文件时,浏览器会下载CSS文件
  • 下载CSS文件不会影响HTML的解析,是和DOM Tree的生成同时进行的
  • 下完后会对CSS文件进行解析,解析出对应的规则树,即CSSOMCSS Object Model CSS对象模型)

在这里插入图片描述

3. 构建Render Tree

  • DOM TreeCSSOM Tree结合构建Render Tree
  • 因此link元素不会阻塞DOM Tree的构建,但是会阻塞Render Tree的构建
  • Render TreeDOM Tree并不是一一对应的,比如DOM Tree中设置display:none的元素就不会出现在Render Tree
  • Render Tree 仅包含需要显示的可见元素,并应用了CSS样式,但是不表示每个节点的尺寸、位置等信息

在这里插入图片描述

4. 布局(Layout

布局生成渲染树中所有节点的宽度、高度和位置信息,结果存储在一个或多个框架或盒子对象中

回流

第一次确定节点的大小位置称为布局(Layout) ,之后对节点大小位置改变后的重新计算称为回流(reflow),也可称重排

什么情况下会引起回流?
总结一句话就是,只要操作会改变元素大小和布局都会引起回流,回流一定会引起重绘

  • DOM结构发生改变(添加新的节点或者移除节点)
  • 改变布局(修改了width、height、padding、font-size等值)
  • 修改浏览器窗口的尺寸
  • 调用getComputedStyle获取大小位置信息本身不会直接引起回流,但为了返回准确的样式信息,有的浏览器可能会执行回流以确保数据的准确性

如何减少回流?

  • 修改样式时尽量一次性修改,比如通过cssText和添加class修改
  • 尽量避免频繁的操作DOM,可以在一个DocumentFragment或者父元素中将要操作的DOM操作完成,再一次性的操作
  • 对于频繁变化的元素,使用position: absoluteposition: fixed以避免影响其他元素的布局
  • 尽量避免频繁读取会导致回流的属性

5. 绘制(Paint

在绘制阶段,浏览器将布局阶段计算的每个frame(也称为渲染对象或渲染盒子)转为屏幕上实际的像素点,包括将每个元素的视觉特性(颜色、边框、阴影等)绘制到多个图层上

重绘

第一次对元素的颜色背景阴影等的渲染叫绘制,之后当元素背景色、文字颜色、边框颜色、样式外观等属性发生变化时的再次渲染叫重绘

6. 合成(composite

在这里插入图片描述

  • 将图层组合成最终的屏幕图像
  • 绘制过程中会绘制到多个合成图层中,这是浏览器的一种优化手段
  • 默认情况下,标准流中的内容都是被绘制在同一个图层(Layer)中的
  • 一些特殊的属性会创建一个新的合成层(CompositingLayer),并且新的图层可以利用GPU来加速绘制,因为每个合成层都是单独渲染的
  • 分层确实可以提高性能,但是它以内存管理为代价,因此不应作为web性能优化策略的一部分过度使用

常见的一些特殊的属性如下:
调试时可以在浏览器更多工具中的layer里看到以下属性是否会生成新的图层

  • 3D transforms
  • video、canvas、iframe
  • opacity 动画转换时;
  • position: fixed
  • will-change:一个实验性的属性,提前告诉浏览器元素可能发生哪些变化;
  • animationtransition 设置了opacity、transform

JavaScript脚本和页面解析的关系

  • 浏览器在解析HTML的过程中,遇到script元素会停止构建DOM Tree
  • 然后会下载JavaScript代码并执行JavaScript脚本
  • JavaScript脚本执行完后才会继续解析HTML,构建DOM Tree
  • 这是因为JavaScript作用之一就是操作和修改DOM,若等DOM Tree构建和渲染之后再执行JavaScript,会造成严重的回流和重绘,影响页面性能

若想让JavaScript代码的下载不阻塞构建DOM Tree,则需要用到下面script元素的两个属性

defer属性

<!DOCTYPE html>
<html>
<head>
  <title>Defer Example</title>
  <script src="first.js" defer></script>
  <script src="second.js" defer></script>
</head>
<body>
  <h1>Hello, world!</h1>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      console.log('DOMContentLoaded event triggered');
    });
  </script>
</body>
</html>
  • defer 属性告诉浏览器不要等待脚本下载,继续解析HTML,构建DOM Tree
  • 如果所有带有 defer 属性的脚本都已经提前下载好了,它会等待DOM Tree构建完成,然后触发 DOMContentLoaded事件
  • 确保了当 DOMContentLoaded 事件触发时,整个 DOM Tree已经构建完成,所有依赖的脚本都已经执行,可以安全地进行 DOM 操作
  • 多个带defer的脚本是可以保持正确的顺序执行的
  • defer可以提高页面的性能,并且推荐放到head元素中
  • defer仅适用于外部脚本

async属性

  • async属性也不会阻塞解析HTML
  • async脚本不能保证顺序,它是独立下载、独立运行,不会等待其他脚本
  • async不能保证在DOMContentLoaded之前或者之后执行;
  • async通常用于独立的脚本,对其他脚本和DOM没有依赖的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值