我在Medium瀏覽帖子的時(shí)候發(fā)現(xiàn)他們的圖片加載效果真的很贊誒。首先載入一個(gè)低像素的模糊圖片,然后逐漸轉(zhuǎn)變?yōu)楦咔宕髨D。這個(gè)過程體驗(yàn)真的很好,所以我希望能夠明白他們是使用什么方法做到的。
Medium的技術(shù)
我使用WebPageTest測試這個(gè)頁面的載入過程。如果你希望能夠測試同樣效果,可以打開Medium的頁面,禁用cache減慢圖片申請(qǐng)加載的過程,所以加載出原圖的時(shí)間會(huì)稍久。這樣就可以清楚看到整個(gè)圖片的加載效果。
具體執(zhí)行過程
使用div限定好圖片展示的區(qū)域,Medium使用div>標(biāo)簽并加入padding-bottom樣式設(shè)定對(duì)應(yīng)圖片的展示尺寸。通過這樣占位的方式可以防止在圖片加載后出現(xiàn)整體頁面回流的情況。這種方法通常被稱為intrinsic placeholders
加載小尺寸(像素低)的圖片,此時(shí)網(wǎng)頁會(huì)先請(qǐng)求一個(gè)像素質(zhì)量較低的小號(hào)縮略圖(大小為原圖的20%).這個(gè)小圖片使用img />標(biāo)簽,因此瀏覽器會(huì)在標(biāo)簽加載完成后,立即請(qǐng)求圖片資源。
只要圖片加載完成,它就會(huì)被“畫”到canvas />中。圖片數(shù)據(jù)會(huì)被main-base.bundle.js文件中自定義的Blur()函數(shù)重新計(jì)算,可以看到它會(huì)產(chǎn)生模糊圖片的效果。盡管有些不同,不過該函數(shù)與StackBlur的模糊函數(shù)實(shí)現(xiàn)效果是相似的。在模糊圖片生成的同時(shí),瀏覽器也會(huì)開始請(qǐng)求高清原圖資源。
最后原圖被加載到頁面上,canvas會(huì)被隱藏,只展示原圖。
最后的最后,感謝CSS的動(dòng)畫功能,上述所有轉(zhuǎn)變過程會(huì)很流暢。
Markup
整個(gè)展示圖片的結(jié)構(gòu)
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- figure>
- div>
- div/>
- img/>
- canvas/>
- img/>
- noscript/>
- /div>
- /figure>
- figure name="7012" id="7012" class="graf--figure graf--layoutFillWidth graf-after--h4">
- div class="aspectRatioPlaceholder is-locked">
- div class="aspect-ratio-fill" style="padding-bottom: 66.7%;">/div>
- div class="progressiveMedia js-progressiveMedia graf-image is-canvasLoaded is-imageLoaded" data-image-id="1*sg-uLNm73whmdOgKlrQdZA.jpeg" data-width="2000" data-height="1333" data-scroll="native">
- img src="https://cdn-images-1.medium.com/freeze/max/27/1*sg-uLNm73whmdOgKlrQdZA.jpeg?q=20" crossorigin="anonymous" class="progressiveMedia-thumbnail js-progressiveMedia-thumbnail">
- canvas class="progressiveMedia-canvas js-progressiveMedia-canvas" width="75" height="47">/canvas>
- img class="progressiveMedia-image js-progressiveMedia-image __web-inspector-hide-shortcut__" data-src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg" src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg">
- noscript class="js-progressiveMedia-inner">img class="progressiveMedia-noscript js-progressiveMedia-inner" src="https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg">/noscript>
- /div>
- /div>
- /figure>
PS:實(shí)際圖片大小要根據(jù)設(shè)備尺寸來設(shè)定。
嘗試重新實(shí)現(xiàn)同樣效果
我在CodePen重新通過使用CSS替代canvas實(shí)現(xiàn)同樣的加載效果。下面的圖片展示了整個(gè)加載過程中,圖片的轉(zhuǎn)變效果。
這么做是否值?
很明顯,現(xiàn)在有許多種方法來實(shí)現(xiàn)同樣的效果。要知道在幾年前如此高性能的方式實(shí)現(xiàn)動(dòng)畫和模糊效果還是不可能的。但事實(shí)上,大多數(shù)時(shí)候延遲瓶頸,并不是設(shè)備本身的原因,因此這些技巧值得我們探索。 控制加載圖片過程有以下優(yōu)點(diǎn):
懶加載:使用JS來請(qǐng)求資源讓我們可以靈活控制圖片資源選擇。小圖可以請(qǐng)求同一縮略圖,大圖則可以根據(jù)瀏覽器視窗大小來選擇加載尺寸不同的圖片。
更好的占位符: 相比于純色占位符,使用縮略圖添加模糊效果后會(huì)有更好的視覺效果,同時(shí)圖片大小也只有2k左右不會(huì)犧牲負(fù)載。
裁剪圖片大?。篗edium根據(jù)訪問設(shè)備的不同,返回不同尺寸的圖片,這樣可以很好的優(yōu)化頁面的加載速度,同時(shí)避免移動(dòng)設(shè)備浪費(fèi)過多流量。
其他版本
在實(shí)現(xiàn)Medium原方法之前,我覺得我可以在我的網(wǎng)站使用其他方法來實(shí)現(xiàn)。
內(nèi)聯(lián)圖片數(shù)據(jù)
我們可以在img中添加縮略圖的URLs來直接請(qǐng)求資源。這樣做雖然會(huì)增加HTML的內(nèi)容,但是可以加快占位符的生成速度。瀏覽器加載好HTML標(biāo)簽就立即下載圖片文件資源。加了模糊效果后圖片的質(zhì)量就無所謂了,我測試使用0.5k大小的圖片與2k大小的圖片得到相似的顯示效果。
模糊效果
默認(rèn)情況下,當(dāng)瀏覽器將一個(gè)小圖像放大,它應(yīng)用光滑效果處理圖像的模糊效果。圖像的效果也可以關(guān)閉,像QR碼。
[…]the browser would render it in a way that didn’t make it look blocky[…] from Google Developers.
它可以在Chrome、Safari和Firefox中有效,盡管光滑效果在Chrome中更有效,你可以在這里看效果。
下面我們看看如何做到光滑效果。圖片只有27px寬,并且像素非常低,將它放大會(huì)產(chǎn)生很可怕的效果。事實(shí)卻并沒有。如果上述效果能滿足你的要求,那你就不需要更復(fù)雜的效果替換了。
上述圖片模糊效果也可以使用CSS Filter Effects實(shí)現(xiàn),它還支持IE瀏覽器哦(IE一生黑)。我相信Medium在使用canvas方法之前一定也嘗試過使用這個(gè)功能更強(qiáng)的方法。但是可能是出于一定原因他們放棄了這一方法。這一方法的優(yōu)點(diǎn)是你可以設(shè)定模糊度,并且可以通過CSS達(dá)成其他目的。
也可以使用SVG的filter來達(dá)成同樣目的,如The “Blur Up” Technique for Loading Background Images 和 Textured Gradients in Pure CSS兩篇文章提到的。
其他辦法提升占位符:Google 圖片搜索
他們選擇圖片的一種主顏色,并用其作為占位塊的背景色。這樣做會(huì)給用戶一種圖片加載速度更快的體驗(yàn)。
更先進(jìn)的方法:Facebook的200 byte技術(shù)
年初Facebook發(fā)表過一篇"The technology behind preview photos"的文章,這篇文章主要說明如何預(yù)覽一個(gè)沒有JPEG頭的42 * 42px的圖片。 使用場景有些不同,這“圖片”被用于Facebook的手機(jī)端,它知道如何組成一個(gè)有效的JPEG圖片。此處我們?cè)赪eb端使用的話需要編寫JavaScript代碼,這樣做同樣會(huì)增加存儲(chǔ)資源。當(dāng)然我們可以通過在服務(wù)器端組成這個(gè)圖片解決這一問題,但是這樣仍需要一些JavaScript代碼發(fā)送申請(qǐng)圖片資源的請(qǐng)求。
無論如何,這個(gè)方法對(duì)于Web端來說有點(diǎn)大材小用,但我還是希望能夠?qū)⑵渥鳛橐粋€(gè)參考。Using WebP for generating this preview images同樣可以節(jié)省內(nèi)存,并且不需要使用如此創(chuàng)造性的解決方法。
LQIP: Low Quality Image Placeholders
與其等待最終的圖像呈現(xiàn),我們可以先提供一個(gè)高度壓縮的圖片,然后切換到大圖。這就是LQIP方法的思路。這一方法與Medium相似,不過是使用相同尺寸,但壓縮更高的圖片。
總結(jié)
隨著頁面加載的圖片越來越多,需要勤于思考頁面的加載過程。因?yàn)檫@會(huì)影響加載效率和用戶體驗(yàn)。 如果你生成幾個(gè)縮略圖大小的圖片,你可以實(shí)驗(yàn)使用一個(gè)非常小的圖片作為背景,等待最終圖片被加載出來。