本文转自微信公众号【前端大全】,作者:Leechikit
此文研究页面中的图片资源的加载和渲染时机,使得我们能更好的管理图片资源,避免不必要的流量和提高用户体验。
浏览器的工作流程
首先了解一下浏览器的工作原理(以 Webkit引擎 为例)
浏览器加载一个HTML页面后进行如下操作:
- 解析HTML —> 构建DOM树
- 加载样式 —> 解析样式 —> 构建样式规则树
- 加载javascript —> 执行javascript代码
- 把DOM树和样式规则树匹配构建渲染树
- 计算元素位置进行布局
- 绘制
上面无法很直观的判断图片资源什么时候开始加载,下面标出何时加载和渲染图片:
- 解析HTML 【遇到
<img>
标签加载图片】 —> 构建DOM树 - 加载样式 —> 解析样式 【遇到背景图片链接不加载】 —> 构建样式规则树
- 加载javascript —> 执行javascript代码
- 把DOM树和样式规则树匹配构建渲染树 【加载渲染树上的背景图片】
- 计算元素位置进行布局
- 绘制 【开始渲染图片】
图片加载与渲染规则
页面中不是所有的 <img>
标签图片和样式表背景图片都会加载。
1、display:none
a.设置了 display:none
属性的元素,图片不会渲染出来,但会加载;
|
|
把DOM树和样式规则树匹配构建渲染树时,会把可渲染元素上的所有属性(如 display:none
属性和 background-image
属性)结合一起产出到渲染树。 当解析渲染树时会加载 ( <img>
标签元素上的图片<img>
标签元素上的图片是在解析HTML时加载的,而不是在解析渲染树时加载),发现元素上有 background-image
属性时会加载背景图片。当绘制时发现元素上有 display:none
属性,则不计算该元素位置,也不会绘制该元素。
b.设置了 display:none
属性元素的子元素,样式表中的背景图片不会渲染出来,也不会加载;而 <img>
标签的图片不会渲染出来,但会加载。
|
|
构建渲染树时,只会把可渲染元素产出到渲染树。这就意味有不可渲染元素,当匹配DOM树和样式规则树时,若发现一个元素的属性上有 display:none
,浏览器会认为 该元素的子元素 是不可渲染的,因此不会把 该元素的子元素 产出到渲染树上。
当解析渲染树时渲染树上没有设置了 display:none
属性元素的子元素,因此不会加载该元素中子元素的背景图片。
当绘制时也因为渲染树上没有设置了 display:none
属性元素的子元素,因此该元素中子元素的背景图片不会渲染出来。
2、重复图片
页面中多个 <img>
标签或样式表中的背景图片路径是同一个,图片只加载一次。
|
|
浏览器请求资源时,都会先判断是否有缓存,若有缓存且未过期则会从缓存中读取,不会再次请求。先加载的图片会存储到浏览器缓存中,后面再次请求同路径图片时会直接读取缓存中的图片。
3、不存在元素的背景图片
不存在元素的背景图片不会加载。
|
|
不存在的元素不会产出到DOM树上,因此渲染树上也不会有不存在的元素,当解析渲染树时无法解析不存在的元素,不存在的元素上的图片自然不会加载也不会渲染。
4、伪类的背景图片
当触发伪类的时候,伪类样式上的背景图片才会加载。
|
|
触发hover前,DOM树与样式规则树匹配的是无hover状态选择器 .img-green
的样式,因此渲染树上 background-image
属性的值是 url(../image/green.png)
,解析渲染树时加载的是 green.png ,绘制时渲染的也是 green.png 。
触发hover后,因为 .img-green:hover
的优先级比较高,因此DOM树与样式规则树匹配的是有hover状态选择器 .img-green:hover
的样式,渲染树上 background-image
属性的值是 url(../image/red.png)
,解析渲染树时加载的是 red.png ,绘制时渲染的也是 red.png 。
相关应用
1、占位图
当使用样式表中的背景图片作为占位符时,要把背景图片转为 base64格式 。这是因为背景图片加载的顺序在标签后面,背景图片可能会在 <img>
标签图片加载完成后才开始加载,达不到想要的效果。
2、预加载
很多场景里图片是在改变或触发状态后才显示出来的,例如点击一个Tab后,一个设置 display:none
隐藏的父元素变为显示,这个父元素里的子元素图片会在父元素显示后才开始加载;又如当鼠标hover到图标后,改变图标图片,图片会在hover上去后才开始加载,导致出现闪一下这种不友好的体验。
在这种场景下,我们就需要把图片预加载,预加载有很多种方式:
- 若是小图标,可以合并成雪碧图,在改变状态前就把所有图标都一起加载了。
- 使用上文讲到的,设置了
display:none
属性的元素,图片不会渲染出来,但会加载。把要预加载的图片加到设置了display:none
的元素背景图或标签里。 - 在javascript创建
img
对象,把图片url
设置到img
对象的src
属性里。