<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          圖片懶加載從簡單到復雜

          共 4004字,需瀏覽 9分鐘

           ·

          2020-11-27 15:24

          加星標,提升前端技能

          作者:hateonion

          https://hateonion.me/posts/19jan30/


          圖片懶加載是一個很重要的前端性能優(yōu)化手段。這篇文章將從懶加載的最簡單場景開始介紹,逐步增加復雜度,希望能講清楚常見的圖片懶加載場景及在該場景下對應(yīng)的解決辦法,也希望對你有所幫助。


          為什么要做圖片的懶加載


          假設(shè)在用戶訪問某個頁面時就加載這個頁面全部的圖片(即使這些圖片并不處在用戶的當前的視窗中),在弱網(wǎng)環(huán)境或者網(wǎng)速較慢的環(huán)境下,這些“冗余”圖片的下載會占用用戶本來就非常有限的帶寬,傷害用戶體驗(比如影響其他資源的下載)。所以對于網(wǎng)站的圖片,理想的做法是懶加載(按需加載)。


          圖片懶加載的原理


          在瀏覽器內(nèi)部對于各種資源有著一套自己的優(yōu)先級定義,瀏覽器會優(yōu)先加載優(yōu)先級高的資源。
          如果我們不去進行圖片的懶加載,默認情況下,資源的priority如下。
          這些優(yōu)先級標記為high的圖片會占用其他資源的下載帶寬,可能會造成某些比較關(guān)鍵的資源(比如xhr call)加載緩慢,拖慢頁面速度。


          圖片懶加載的簡單實現(xiàn)


          圖片懶加載的思路一般時當頁面加載時加載一個尺寸很小的占位圖片(1kb以下),然后再通過js選擇性的去加載真正的圖片。
          一個最簡單的的實現(xiàn)如下:
            
          // index.css
          img[src] { filter: blur(0.2em); }
          img { filter: blur(0em); transition: filter 0.5s; }
          (function lazyLoad(){ const imageToLazy = document.querySelectorAll('img[src]'); const loadImage = function (image) { image.setAttribute('src', image.getAttribute('src')); image.addEventListener('load', function() { image.removeAttribute("src"); }) }
          imageToLazy.forEach(function(image){ loadImage(image); })})()
          通過懶加載之后,資源優(yōu)先級如下。


          圖片懶加載的進階實現(xiàn)–滾動加載


          上面的方案并不完美,對于用戶來說,不在視窗中的圖片可能根本不是用戶當前關(guān)心的圖片,所以我們可以讓這些圖片出現(xiàn)在用戶視窗中再進行加載。
          運用Intersection Observer 我們可以做到當圖片滾動到視窗后再加載該圖片。
          (function lazyLoad(){ const imageToLazy = document.querySelectorAll('img[src]'); const loadImage = function (image) { image.setAttribute('src', image.getAttribute('src')); image.addEventListener('load', function() { image.removeAttribute("src"); }) }

          const intersectionObserver = new IntersectionObserver(function(items, observer) { items.forEach(function(item) { if(item.isIntersecting) { loadImage(item.target); observer.unobserve(item.target); } }); });
          imageToLazy.forEach(function(image){ intersectionObserver.observe(image); })})()
          上面的這些demo都在https://github.com/hateonion/lazy-load 這個repo里面。


          如何選擇合適的Placeholder圖片


          在上面的demo中我們使用了placeholder圖片,實際上,圖片所占的位置是否確定對于我們選擇placeholder圖片有著很大的影響。


          圖片尺寸已知


          圖片尺寸已知出現(xiàn)的場景一般是博文的題圖或者網(wǎng)站中一些固定尺寸的thumbnail,這些圖的尺寸一般固定且一般不會發(fā)生改變。對于這種場景,我們可以加載對應(yīng)尺寸的placeholder圖片(如上一節(jié)的demo)。我們可以自己裁剪對應(yīng)尺寸的的placeholder圖片或者使用類似http://placeholder.com/?這樣的服務(wù)來獲取placeholder圖片。


          圖片尺寸未知


          圖片尺寸未知的情況下一般我們需要生成對應(yīng)的thumbnail然后去加載我們生成的thumbnail去做placeholder。為了生成這些thumbnail你可以調(diào)用imagemagick或者調(diào)用一些在線的圖片分割服務(wù)(比如七牛)


          懶加載防止布局抖動


          在圖片懶加載時,由于圖片的尺寸不定,瀏覽器難以計算需要給圖片預(yù)留出的位置。所以當圖片加載完成后會出現(xiàn)網(wǎng)頁布局的抖動。
          (image from From?http://davidecalignano.it/lazy-loading-with-responsive-images-and-unknown-height/)
          即使我們選擇的placeholder很小,可以在毫秒級別完成下載,用戶可能意識不到布局的抖動。但是在一些性能比較差的設(shè)備上,這種布局的抖動還是會一定程度上影響用戶的體驗。為了完全避免布局閃動,我們可以采用aspect ratio boxes 的技術(shù)來制作一個占位用的元素。
          .lazy-load__container{ position: relative; display: block; height: 0;}
          .lazy-load__container.feature { // feature image 的高寬比設(shè)置成42.8% // 對于其他圖片 比如 post圖片,高寬比可能會不同,可以使用其他css class去設(shè)置 padding-bottom: 42.8%;}
          .lazy-load__container img { position: absolute; top:0; left:0; height: 100%; width: 100%;}
          結(jié)果
          上面這個實現(xiàn)的原理其實很簡單,由于 padding-bottom (或者 padding-top)聲明為百分比時是根據(jù)元素生成的box的 width 去計算百分比的,所以我們通過padding-bottom去聲明一個對應(yīng)高寬比的container。而這個container的具體尺寸會由尺寸確定的外層元素確定,但是高寬比始終保持一致。
          而圖片的尺寸設(shè)置成100%container的尺寸保證圖片始終和container的尺寸保持一致。
          需要注意的是上面這個方法并不能適配圖片比例不一致的網(wǎng)站(比如本站),不過好在,為了用戶體驗,現(xiàn)在絕大多數(shù)網(wǎng)站的圖片比例都有明確的要求,絕大多數(shù)情況下我們只適配保證網(wǎng)站常用的的幾種圖片寬高比例即可。


          像Medium一樣懶加載圖片


          Medium的懶加載圖片的體驗相信去 Medium 讀過文章的同學都體驗過了,可以說是非常的流暢。而其背后的技術(shù)其實也就是我們上面講到的幾種技術(shù)的組合。


          1. 使用 aspect ratio box 創(chuàng)建占位元素。
          2. 在html解析時只加載一個小尺寸的圖片,并且添加blur效果。
          3. 最后使用js選擇性的加載真實圖片。


          Demo 如下?codePen by José M. Pérez


          總結(jié)

          1. 懶加載用戶當前視窗中的圖片可以提升頁面的加載性能。
          2. 懶加載的思路是在html解析時先加載一個placeholder圖片,最后再用js選擇性的加載真實圖片。
          3. 如果需要滾動加載可以使用 Intersection Observer 。
          4. 對于固定尺寸和不定尺寸的圖片,我們可以選擇不同的服務(wù)去或者placeholder圖片。
          5. 對于圖片尺寸不確定引起的布局抖動問題我們可以使用 aspect ratio box 來解決。

          參考資料

          Progressive Loading
          Lazy loading with responsive images and unknown height
          Simple image placeholders for lazy loading images
          How Medium does progressive image loading
          Sizing Fluid Image Containers with a Little CSS Padding Hack

          掃碼關(guān)注公眾號,訂閱更多精彩內(nèi)容。



          你點的每個贊,我都認真當成了喜歡
          瀏覽 60
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中国女人一级片 | 欧美一级二级三级 | 欧美经典怡红院肏肥屄淫荡视频在线观看 | 免费黄色一级片 | 欧美系列在线 |