浏览器渲染原理
DOM
CSSOM
注意: CSS选择器越详细,匹配工作越多,匹配节点越慢。
RenderTree
RenderTree包含了渲染网页所需的节点
无需渲染的节点不会被添加到RenderTree中。 如:<head>,display: none的节点
注意: 因为设置了visibility:hidden的元素虽不可见,但仍然占有空间,仍会被添加到RenderTree
Layout
计算渲染树节点位置大小
Viewport
<meta name="viewport" content="width=device-width">
device-width为浏览器的理想视口
在移动端,如果不设置viewport宽度为理想视口,viewport宽度通常为980px,这会导致文字很小,我们需要手动放大阅读。
触发Layout
屏幕旋转
浏览器视窗改变
与大小位置相关的CSS属性改变
Paint
根据background,border,box-shadow等样式,将Layout生成的区域填充为最终将显示在屏幕上的像素
资源对渲染的影响
资源
CSS
JS
Font
img
CSS
浏览器会在DOM和CSSOM加载完开始渲染页面
CSS阻塞初次渲染
通过以上两种方式定义的CSS,均会阻塞初次渲染
浏览器会在解析完CSS后,再进行渲染。这是为了防止样式突变带来的抖动。
通过link标签引入的CSS阻塞的时间可能更长,因为加载它需要一个网络来回时间
media query
此样式表仍会加载
当浏览器环境不匹配媒体查询条件时,该样式表不会阻塞渲染
我们可针对不同媒体环境拆分CSS文件,并为link标签添加媒体查询,避免为了加载非关键CSS资源,而阻塞初次渲染
通过DOM API添加link
var style = document.createElement('link');style.rel = 'stylesheet';style.href = 'index.css';document.head.appendChild(style);
不会阻塞初次渲染
preload
rel不是stylesheet,因此不会阻塞渲染
preload是resoure hint规范中定义的一个功能
resource hint通过告知浏览器提前建立连接或加载资源,以提高资源加载的速度。
浏览器遇到遇到标记为preload的link时,会开始加载它。
当onload事件发生时,将rel改为stylesheet,即可应用此样式
总结
引入CSS资源的方法 | 是否阻塞初次渲染 |
---|---|
<link rel="stylesheet" href="index.css" /> | 是 |
通过document.write写入以上标签 | 是 |
通过DOM API插入HTMLLinkElement对象 | 否 |
使用preload方式载入CSS | 否 |
为link添加media query | 当媒体查询不匹配时,不会阻塞 |
JavaScript
Javascript阻塞HTML Parser(解析器)
<-- inline js --><-- external js -->
通过以上两种方式引入js均会阻塞HTML parser,因而会阻塞出现在脚本后面的HTML标记的渲染。
外部script阻塞的时间一般更长,因为可能包含了一个网络来回时间。
Javascript可以通过document.write修改HTML文档流,因此在执行js时,浏览器会暂停解析DOM的工作。
CSS阻塞JS
<-- inline js --><-- external js -->
通过以上两种方式引入的JS均会被CSS阻塞
由于这些Javascript可能会读取或修改CSSOM,因此需等待CSSOM构造完成后,它们才能执行
将资源放到文档底部,延迟js执行
世界上最美丽的语言是什么?
使用defer延迟脚本执行
世界上最美丽的语言是什么?
当script标签拥有defer属性时,该脚本会被推迟到整个HTML文档解析完后,再开始执行
被defer的脚本,在执行时会严格按照在HTML文档中出现的顺序执行
注意: 使用defer时,浏览器会保证脚本按照在文档中出现的顺序执行
使用async异步加载脚本
Hello World
当script标签拥有async属性时,该脚本不会再阻塞HTML parser。且不会被CSS阻塞。
脚本只要加载完成,便可开始执行。
被async的脚本,在执行时会不会严格按照在HTML文档中出现的顺序执行
async适用于无依赖的独立资源
总结
引入JS资源的方法 | 是否阻塞文档内容初次渲染 |
---|---|
在head中引入外部脚本<script src="index.js"></script> 或内联脚本<script>/* app logics */</script> | 是 |
将脚本放到body底部 | 否 |
为脚本添加defer属性 | 否 |
为脚本添加async属性 | 否 |
Font
Font阻塞内容渲染
浏览器为了避免FOUT(Flash Of Unstyled Text),会尽量等待字体加载完成后,再显示应用了该字体的内容
只有当字体超过一段时间仍未加载成功时,浏览器才会降级使用系统字体。每个浏览器都规定了自己的超时时间
但这也带来了FOIT(Flash Of Invisible Text)问题。内容无法尽快地被展示,导致空白。
img
图片资源不会阻塞首次渲染