看似日常的事物,每每會蘊含的巨大的智慧。把看似日常的事物簡單作好,可能很正常。若是能把日常的事物作精,作細,這個不日常。css
每個開發者在開發項目中,不可避免要和圖片打交道,優化圖片彷佛也成了一個必修課。圖片優化也不只僅是性能上的優化,還要進行體驗上的優化。至於怎麼優化圖片,沒有固定的方式,只能具體場景,具體分析,選擇合適的方案。很少說,下面也簡單介紹下本身處理過,瞭解過的一些方式。若是你們有補充,建議。歡迎在評論區留言,交流學習下。html
‘概念用法’ 這個詞是本身亂起的,可能不太準確,是由於詞窮了,不知道怎樣形容。總得來講,這部分介紹的處理方式,就是講一下就知道怎麼用的方式,不須要怎麼放代碼,運行圖等。只須要籠統的介紹一下,你們都會懂的一些方式。css3
這個沒有隱含的意思,就是把圖片的大小進行壓縮。目前本身用的比較多的兩個壓縮網站是TinyPng和智圖。使用比較方便,品質也基本保持一致。git
一些比較小的圖標,使用 base64 編碼代替能夠減小 http 請求。可是有一個缺點就是轉成 base64 後,編碼會比原圖更大,圖片越大,差異就越大。1K左右的圖標,轉碼出來的 base64 大概是 1.1K-2K。若是是 8K 的圖片,轉碼出來的 base64 可能超過10K。就本身項目開發而言,只有小於 4K 的圖標,纔會進行轉碼。github
因爲 icon-font 看着是圖片,其實是字體。瀏覽器
優勢:就是在於能夠矢量縮放,大小圖標均可以使用,也能夠改變顏色,使用也不麻煩。緩存
缺點:須要引入的文件很多(.svg,.ttf,.woff,.eot )。文件大小也比較大。建議是項目的圖標要達到必定量才使用 icon-font,若是是幾個圖標,仍是用圖片吧。若是須要引入的圖標多,就建議使用 icon-font。bash
上面說的 icon-font 因爲是字體,因此不支持多色圖標。有了解到,如今 icon-font 能夠支持多色圖標了(symbol引用)。只是兼容性很差。微信
雪碧圖就是把不少小的圖整合到一塊兒,製做成一張比較大的圖,而後做爲元素的背景圖片使用,定位到相應的圖片便可。dom
優勢:減小了大量的 http 請求。
缺點:背景定位和在移動端適配大小有點麻煩。
除此以外,使用雪碧圖,有兩個個注意地方
1.不要把頁面全部的圖片都合併,好比把 logo 整合會破壞 html 的語義結構。圖像複雜的 banner 也不要合併
2.儘可能只把顏色相近的圖標整合在一張圖片上,若是圖片顏色相差太大,合併出來的圖片可能會很大。
好比頁面上有一張尺寸是 100*100 的圖片,可是圖片的實際尺寸是 1000*1000 的。這樣的狀況建議在多準備一張 100*100 的圖片。否則可能會形成資源浪費。
以下例子,好比頁面有這個圖標
在特定狀況下會是下面這個顏色。
同一個圖標,在不一樣的時候是不一樣的顏色。icon-font 能夠經過改變 color 實現。或者用兩張圖片。除了這兩個方法,用 CSS3 的混合模式,同樣能夠實現。兩行代碼搞定。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
div{
/*容器必須有背景*/
background: #09f;
display: inline-block;
}
img{
width: 100px;
vertical-align: top;
}
img:hover{
/*設置混合模式*/
mix-blend-mode: lighten;
}
</style>
</head>
<body>
<div><img src="images/icon-good.jpg" class="u-icon"/></div>
<div><img src="images/icon-good.png" class="u-icon"/></div>
</body>
</html>
複製代碼
運行效果
展現完 mix-blend-mode,順便提下 background-blend-mode 。用法基本一致,只是 mix-blend-mode 做用於 html 元素的混合模式,background-blend-mode 做用於元素背景的混合模式。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
div{
display: inline-block;
width: 100px;
height: 100px;
/*設置背景*/
background: url(images/icon-good.jpg) no-repeat center,#09f;
background-size:100%;
/*設置背景混合模式*/
background-blend-mode: lighten;
}
</style>
</head>
<body>
<div></div>
</body>
</html>
複製代碼
注意事項
1.圖片必須是白底純色圖標
2.現代的瀏覽器,支持這個屬性的瀏覽器
若是圖片是透明純色背景,獲得的結果會是這樣
受限篇幅影響,混合模式暫時就介紹這麼多,之後發現好玩的再寫文章。有興趣能夠看下面的參考資料。
難以想象的混合模式 background-blend-mode
有一些簡單的圖標,可使用 CSS 代替。好比下面這些
本身而言,項目上畫的最多的就是各類箭頭
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
.icon-arrow-bottom {
width: 0;
height: 0;
border: 100px solid #000;
border-color: #000 transparent transparent transparent;
}
.icon-arrow-top {
width: 0;
height: 0;
border: 100px solid #000;
border-color: transparent transparent #000 transparent;
}
</style>
</head>
<body>
<div class="icon-arrow-bottom"></div>
<div class="icon-arrow-top"</div>
</body>
</html>
複製代碼
優勢:矢量縮放,顏色可變,不須要發送請求
缺點:只適合用簡單圖形,1-5行 CSS 代碼能夠搞定的才建議用,超過的不建議。想得痛苦,寫也麻煩,花時間也多,效果未必比其它方案好。建議仍是圖片 base64,或者 icon-font。
這裏就簡單舉個例子,須要知道 css3 還能夠畫什麼圖形。看參考資料。
1.從這裏開始。下面的demo,有些會用到 ecDo 這個庫(本身寫的一個經常使用函數庫,歡迎star)。以前的文章有介紹過,這裏就再也不重複。你們不知道的時候點開看下相應的 API ,運行下,調試下就好。
2.爲方便展現,下面的demo,除了懶加載,都有在 network 把網速調至了慢速的3G。
有些項目圖片比較多,若是一次性加載,用戶等待時間會太久,可能會形成體驗效果不好,甚至致使用戶流失,不少網站用到的一個體驗優化方式是隱式預加載。
等待首屏加載,在用戶看首屏(第一張大圖)的時候,悄悄的加載其它圖片(這裏爲了展現效果,在項目上其餘的小圖片不該在第一屏)。
<body>
<p><img src="lawyerOtherImg.jpg"/></p>
<p>這是預加載的圖片</p>
<div>
<img data-src="https://materialdb.zhaoyl.com/201809/106796.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/105567.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/103097.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/10205.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/001.jpg" class="load-img" width="100" height="100"/>
</div>
</body>
複製代碼
//測試請先清空緩存
window.onload = function () {
ecDo.loadImg('load-img', function () {
console.log('加載完畢')
});
}
複製代碼
注意事項:
1.大概預測,用戶看首屏的時候,很大機率會往下面看。
2.該方式,用戶等待的時間比較短。可是圖片超大,要慎重考慮。由於該方式沒法保證用戶在瀏覽的時候,能把下一屏(好比瀏覽第一屏的時候,要加載第二屏)的圖片加載完畢,讓用戶無感知。若是切換的下一屏還沒加載完畢,也可能會影響體驗。
告訴用戶正在加載,等到加載完了再一次性渲染在頁面上。
<style>
div{
display: none;
}
</style>
<body>
<p id="p">顯示預加載進行中</p>
<div id="div">
<img data-src="https://materialdb.zhaoyl.com/201809/106796.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/105567.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/103097.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/10205.jpg" class="load-img" width="100" height="100"/><img
data-src="https://materialdb.zhaoyl.com/201809/001.jpg" class="load-img" width="100" height="100"/>
</div>
</body>
複製代碼
let oP1=document.getElementById('p');
let oDiv=document.getElementById('div');
//測試請先清空緩存
window.onload = function () {
ecDo.loadImg('load-img', function () {
oDiv.style.display='block';
oP1.style.display='none';
});
}
複製代碼
注意事項:
1.大概預測,用戶看首屏的時候,很大機率會往下面看。
2.該方式好處在於加載完畢以後,就全部圖片都加載完畢了,體驗比較好。若是圖片所有過大,加載時間會比較長,loading 的時間也會很長,會影響體驗。
demo地址:github.com/chenhuiYj/e…
這個你們應該很熟悉了,簡單點說就是圖片一開始不加載,當用戶瀏覽到什麼位置的時候,相應位置得圖片就加載出來。
<body>
<p><img data-src="lawyerOtherImg.jpg" class="load-img" width='528' height='304'/></p>
<p><img data-src="lawyerOtherImg.jpg" class="load-img" width='528' height='304'/></p>
<p><img data-src="lawyerOtherImg.jpg" class="load-img" width='528' height='304'/></p>
<p><img data-src="https://materialdb.zhaoyl.com/201809/105567.jpg" class="load-img" width='528' height='304'/></p>
<p><img data-src="https://materialdb.zhaoyl.com/201809/106796.jpg" class="load-img" width='528' height='304'/></p>
<p><img data-src="https://materialdb.zhaoyl.com/201809/103097.jpg" class="load-img" width='528' height='304'/></p>
<p><img data-src="https://materialdb.zhaoyl.com/201809/10205.jpg" class="load-img" width='528' height='304'/></p>
<p><img data-src="https://materialdb.zhaoyl.com/201809/001.jpg" class="load-img" width='528' height='304'/></p>
</body>
複製代碼
window.onload = function () {
//根據load-img 這個 class 遍歷,元素距離頁面底部 100像素的時候就開始加載,加載錯誤就顯示error.jpg
ecDo.delayFn(ecDo.lazyLoadImg('load-img', 100, 'error.jpg'),100,200);
window.onscroll = function () {
ecDo.delayFn(ecDo.lazyLoadImg('load-img', 100, 'error.jpg'),100,200);
}
}
複製代碼
這個例子,當網速比較慢的時候,想要加載的圖片沒有立刻出來。或者圖片路徑錯誤,這個時候頁面可能會出現一部分空白的地方,或者頁面佈局會出現錯亂,比較經常使用的作法是先顯示一張 loading 圖或者是 logo 圖。告訴用戶,這裏是圖片,正在加載,體驗上會好不少,好比下面這個例子。
下面也簡單的實現一下。
好比網站上有這樣的圖片
<p><img src="error.jpg" data-src="https://materialdb.zhaoyl.com/201809/105567.jpg" width="264"/></p>
<p><img src="error.jpg" data-src="https://materialdb.zhaoyl.com/201809/106796.jpg" width='264'/></p>
<p><img src="error.jpg" data-src="https://materialdb.zhaoyl.com/201809/1067961.jpg" width='264'/></p>
複製代碼
在 network 把網速調至了慢速的3G,以方便調試。
//測試前請先清空緩存
window.onload = function () {
let oImg=document.getElementsByTagName('img');
for(let i=0;i<oImg.length;i++){
ecDo.aftLoadImg({
dom:oImg[i],
url:oImg[i].dataset.src,
errorUrl:oImg[i].src
})
}
}
複製代碼
能夠看到,一開始顯示的是一張默認圖片,等須要加載的圖片,加載完了以後,再加載須要加載的圖片。(最後一張圖片,是故意把路徑寫錯,因此出來的圖片是以前的圖片)
關於項目上,優化圖片的各類方式,本身用過的,聽過的,大概就在這裏了。實現方案,也不敢說是最好。若是你們有更好的想法,建議,歡迎在評論區留言。
-------------------------華麗的分割線--------------------
想了解更多,和我交流,內推職位,請添加我微信。或者關注個人微信公衆號:守候書閣