此文研究頁面中的圖片資源的加載和渲染時機,使得咱們能更好的管理圖片資源,避免沒必要要的流量和提升用戶體驗。javascript
要研究圖片資源的加載和渲染,咱們先要了解瀏覽器的工做原理。以Webkit引擎的工做流程爲例:java
從上圖可看出,瀏覽器加載一個HTML頁面後進行以下操做:web
解析HTML —> 構建DOM樹segmentfault
加載樣式 —> 解析樣式 —> 構建樣式規則樹瀏覽器
加載javascript —> 執行javascript代碼緩存
把DOM樹和樣式規則樹匹配構建渲染樹佈局
計算元素位置進行佈局url
繪製spa
從上圖咱們不能很直觀的看出圖片資源從何時開始加載,下圖標出圖片加載和渲染的時機:code
解析HTML【遇到<img>
標籤加載圖片】 —> 構建DOM樹
加載樣式 —> 解析樣式【遇到背景圖片連接不加載】 —> 構建樣式規則樹
加載javascript —> 執行javascript代碼
把DOM樹和樣式規則樹匹配構建渲染樹【遍歷DOM樹時加載對應樣式規則上的背景圖片】
計算元素位置進行佈局
繪製【開始渲染圖片】
頁面中不是全部的<img>
標籤圖片和樣式表背景圖片都會加載。
<style> .img-purple { background-image: url(../image/purple.png); } </style> <img src="../image/pink.png" style="display:none"> <div class="img-purple" style="display:none"></div>
圖片資源請求以下:
設置了display:none
屬性的元素,圖片不會渲染出來,但會加載。
原理
把DOM樹和樣式規則樹匹配構建渲染樹時,只會把可見元素和它對應的樣式規則結合一塊兒產出到渲染樹,這就意味有不可見元素,當匹配DOM樹和樣式規則樹時,若發現一個元素的對應的樣式規則上有display:none
,瀏覽器會認爲該元素是不可見的,所以不會把該元素產出到渲染樹上。
上面代碼中,當解析HTML時會加載<img>
標籤元素上的圖片。
當把DOM樹和樣式規則樹匹配構建渲染樹時,遍歷DOM樹上的元素,發現元素對應的樣式規則上有background-image
屬性時會加載背景圖片,可是由於這個元素是不可見元素(對應的樣式規則上有diaplay:none
),不會把該元素和它對應的樣式規則產出到渲染樹。
當繪製時由於渲染樹上沒有該元素,所以不會繪製該元素的背景圖片。
<style> .img-yellow { background-image: url(../image/yellow.png); } </style> <div style="display:none"> <img src="../image/red.png"> <div class="img-yellow"></div> </div>
圖片資源請求以下:
設置了display:none
屬性元素的子元素,樣式表中的背景圖片不會渲染出來,也不會加載;而<img>
標籤的圖片不會渲染出來,但會加載。
原理
正如上面所說的,當匹配DOM樹和樣式規則樹時,若發現元素的對應的樣式規則上有display:none
,瀏覽器會認爲該元素的子元素是不可見的,所以不會把該元素的子元素產出到渲染樹上。
當構建渲染樹遇到了設置了display:none
屬性的不可見元素時,不會繼續遍歷不可見元素的子元素,所以不會加載該元素中子元素的背景圖片。
當繪製時也由於渲染樹上沒有設置了display:none
屬性元素,也沒有改元素的子元素,所以該元素中子元素的背景圖片不會渲染出來。
.img-blue { background-image: url(../image/blue.png); } <div class="img-blue"></div> <img src="../image/blue.png"> <img src="../image/blue.png">
圖片資源請求以下:
頁面中多個<img>
標籤或樣式表中的背景圖片圖片路徑是同一個,圖片只加載一次。
原理
瀏覽器請求資源時,都會先判斷是否有緩存,如有緩存且未過時則會從緩存中讀取,不會再次請求。先加載的圖片會存儲到瀏覽器緩存中,後面再次請求同路徑圖片時會直接讀取緩存中的圖片。
.img-blue { background-image: url(../image/blue.png); } .img-orange{ background-image: url(../image/orange.png); } <div class="img-orange"></div>
圖片資源請求以下:
不存在元素的背景圖片不會加載。
原理
不存在的元素不會產出到DOM樹上,構建渲染樹過程當中遍歷DOM樹時沒法遍歷不存在的元素,所以不會加載圖片,也不會產出到渲染樹上。當解析渲染樹時沒法解析不存在的元素,不存在的元素天然也不會渲染。
.img-green { background-image: url(../image/green.png); } .img-green:hover{ background-image: url(../image/red.png); } <div class="img-green"></div>
觸發hover前的圖片資源請求以下:
觸發hover後的圖片資源請求以下:
當觸發僞類的時候,僞類樣式上的背景圖片纔會加載。
原理
觸發hover前,構建渲染樹過程當中,遍歷DOM樹時,該元素匹配的樣式規則是無hover狀態選擇器.img-green
的樣式,所以加載無hover狀態選擇器.img-green
的樣式上green.png圖片。該元素是可見元素,所以會被產出到渲染樹上,繪製時渲染的也是green.png。
觸發hover後,由於.img-green:hover
的優先級比較高,構建新的渲染樹過程當中,該元素匹配的是有hover狀態選擇器,所以加載有hover狀態選擇器.img-green:hover
的樣式上的red.png圖片。該元素是可見元素,所以會被產出到渲染樹上,繪製時渲染的也是red.png。
當使用樣式表中的背景圖片做爲佔位符時,要把背景圖片轉爲base64格式。這是由於背景圖片加載的順序在<img>
標籤後面,背景圖片可能會在<img>
標籤圖片加載完成後纔開始加載,達不到想要的效果。
不少場景裏圖片是在改變或觸發狀態後才顯示出來的,例如點擊一個Tab後,一個設置display:none
隱藏的父元素變爲顯示,這個父元素裏的子元素圖片會在父元素顯示後纔開始加載;又如當鼠標hover到圖標後,改變圖標圖片,圖片會在hover上去後纔開始加載,致使出現閃一下這種不友好的體驗。
在這種場景下,咱們就須要把圖片預加載,預加載有不少種方式:
如果小圖標,能夠合併成雪碧圖,在改變狀態前就把全部圖標都一塊兒加載了。
使用上文講到的,設置了display:none屬性的元素,圖片不會渲染出來,但會加載。把要預加載的圖片加到設置了display:none
的元素背景圖或<img>
標籤裏。
在javascript建立img對象,把圖片url設置到img對象的src屬性裏。
歡迎關注:Leechikit
原文連接:segmentfault.com到此本文結束,歡迎提問和指正。寫原創文章不易,若本文對你有幫助,請點贊、推薦和關注做者支持。