2014年12月17日

[外掛] jQuery 圖片延遲載入﹍Lazy Load 安裝懶人包 (徹底解決圖片 reflow 現象)

[外掛] jQuery 圖片延遲載入﹍Lazy Load 安裝懶人包 (徹底解決圖片 reflow 現象)

Wayne Fu 0 A+
當網頁圖片多的時候,「影響效能的最大因素就是圖片載入」。除了縮減圖片尺寸、壓縮檔案來縮短傳輸時間之外,更好的改善方法是讓圖片能延遲載入,先讓頁面把主要文字內容優先顯示出來──這正是 jQuery 圖片延遲載入外掛「Lazy Load」的作用。

好的,本篇的程式正是為了解決以上所有難題,自動幫文章中的圖片預先設定尺寸、並能執行最佳的 Lazy Load 效果。以下大致先說明原理,想直接安裝懶人包請跳至「二、準備動作」。




<< 請注意!本篇文章含會員限定內容 >>


一、新舊版 Lazy Load 及最佳化原理


1. 版本差異

目前「Lazy Load 官網」提供的 js 版本,要正常運作得將圖片的 HTML 碼改為以下格式:

<img class="lazy" data-original="img/example.jpg" width="640" height="480">
原本 img 應該是 src 屬性的位置,必須改為 "data-original" 這樣的屬性,且須手動設定圖片寬、高值。如果每張圖片都這麼搞,沒幾個人有這樣的耐性吧?

這篇「Lazy Load 最佳安裝方式」使用 Lazy Load 舊版的 js,圖片 img 的 HTML 不需做任何變更即可執行延遲載入,因此舊版的 js 比較適合懶人安裝法,本篇的程式碼依舊沿用這個版本。


2. 自動取得圖片寬高

這部分的原理是,利用 jQuery 的 on() 函數來監控 img 的 load 事件,就能取得圖片的寬高值,再設定到原本的 img 上,來避免 reflow 的發生。


3. Lazy Load 擺放位置

如同「舊版 Lazy Load 教學」的說明,網頁不需要全部圖片都 Lazy Load,最需要使用 Lazy Load 的是文章區塊的圖片。因此最佳的執行位置是「文章區塊結尾處」,而非 </body> 之前的位置。

也因為這一點,要安裝 Lazy Load 得先「找出文章區塊結尾處」這個位置。本篇教學提供 Blogger 的範例,而非 Blogger 平台的使用者,可能需學會操作「Chrome 開發人員工具」這樣的介面,來自行找出文章區塊的位置。



二、安裝準備動作


1. Blogger 平台

安裝過舊版本的話,這部分的動作可不必再做。

在修改範本之前,如果第一次安裝本站工具的讀者,建議先閱讀「備份範本的訣竅」系列文章。

請到後台「範本」→「編輯 HTML」,游標點進範本區塊,搜尋 </head> 這個字串,找到後在此字串的前一行,插入以下程式碼:

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js'></script>
<script>//<![CDATA[(function($){$.fn.lazyload=function(options){var settings={threshold:0,failurelimit:0,event:"scroll",effect:"show",container:window};if(options){$.extend(settings,options);}
var elements=this;if("scroll"==settings.event){$(settings.container).bind("scroll",function(event){var counter=0;elements.each(function(){if($.abovethetop(this,settings)||$.leftofbegin(this,settings)){}else if(!$.belowthefold(this,settings)&&!$.rightoffold(this,settings)){$(this).trigger("appear");}else{if(counter++>settings.failurelimit){return false;}}});var temp=$.grep(elements,function(element){return!element.loaded;});elements=$(temp);});}
this.each(function(){var self=this;if(undefined==$(self).attr("original")){$(self).attr("original",$(self).attr("src"));}
if("scroll"!=settings.event||undefined==$(self).attr("src")||settings.placeholder==$(self).attr("src")||($.abovethetop(self,settings)||$.leftofbegin(self,settings)||$.belowthefold(self,settings)||$.rightoffold(self,settings))){if(settings.placeholder){$(self).attr("src",settings.placeholder);}else{$(self).removeAttr("src");}
self.loaded=false;}else{self.loaded=true;}
$(self).one("appear",function(){if(!this.loaded){$("").bind("load",function(){$(self).hide().attr("src",$(self).attr("original"))
[settings.effect](settings.effectspeed);self.loaded=true;}).attr("src",$(self).attr("original"));};});if("scroll"!=settings.event){$(self).bind(settings.event,function(event){if(!self.loaded){$(self).trigger("appear");}});}});$(settings.container).trigger(settings.event);return this;};$.belowthefold=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).height()+$(window).scrollTop();}else{var fold=$(settings.container).offset().top+$(settings.container).height();}
return fold<=$(element).offset().top-settings.threshold;};$.rightoffold=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).width()+$(window).scrollLeft();}else{var fold=$(settings.container).offset().left+$(settings.container).width();} return fold<=$(element).offset().left-settings.threshold;};$.abovethetop=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).scrollTop();}else{var fold=$(settings.container).offset().top;} return fold>=$(element).offset().top+settings.threshold+$(element).height();};$.leftofbegin=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).scrollLeft();}else{var fold=$(settings.container).offset().left;}
return fold>=$(element).offset().left+settings.threshold+$(element).width();};$.extend($.expr[':'],{"below-the-fold":"$.belowthefold(a, {threshold : 0, container: window})","above-the-fold":"!$.belowthefold(a, {threshold : 0, container: window})","right-of-fold":"$.rightoffold(a, {threshold : 0, container: window})","left-of-fold":"!$.rightoffold(a, {threshold : 0, container: window})"});})(jQuery);//]]></script>


第一行綠字的 js 檔連結可參考「引用 jQuery 的注意事項」,檢查範本是否已安裝過 jquery,以免重複安裝。


2. 非 Blogger 平台

說明一樣參考第 1 點,程式碼放在範本中 </head> 之前的位置即可。



三、安裝程式碼


1. Blogger 平台

A. 接著在範本中先找到 <b:if cond='data:post.hasJumpLink'> 這個字串,會看到類似下面「繼續閱讀」的程式碼:

<b:if cond='data:post.hasJumpLink'>
<div class='jump-link'>
<a expr:href='data:post.url + "#more"' expr:title='data:post.title'><data:post.jumpText/></a>
</div>
</b:if>


B. 緊接在以上程式碼後面,插入以下程式碼(這裡如安裝過舊版 lazy load,請先刪除舊版程式碼):


以下參數修改請參照以上程式碼行號:

F:預設讓 Lazy Load 抓文章區塊 .post-body 之間的 img 標籤來進行延遲載入,而頁面其他區塊的圖片將沒有 Lazy Load 效果。(如果要設定別的區塊的圖片,那麼 E、F 行的紅色字串得改為該區塊的 class 或 id,且全部程式碼得改放到該區塊的位置之後。)

Y:除了使用藍色字串參數 "fadeIn" 的淡入特效,還可用 "slideDown" 由小圖伸展到大圖的特效,或是使用 "show" 無特效。

2015.1.18 修訂:由於留言回報首頁圖片顯示會不正常,因此 Blogger 平台請將 Y~Z 兩行的內容置換為以下:

effect: "fadeIn"
<b:if cond='data:blog.pageType != "index"'>,
placeholder: "https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBSMPFDF3VOU81f1SAdcoAN2plSV0JBPng2yjNoe0iKq-9h1YnSTNXM6s5ttto1_Y5q6JnF8ZJuexVV4JDZki9_dKgWtfYItPx560Gs0nnnwkvvP1awaJoLidRhJcEKdafks2-ywB5rgRP/s0/grey.gif"
</b:if>



存檔後開一篇圖片多的文章即可看效果,或是也可參考 DEMO 網頁:



2. 非 Blogger 平台

A. 請先找出文章區塊的 class 或 id,可利用「Chrome 開發人員工具」這樣的介面。

B. 在後台範本中找到這個區塊的結尾處,於下一行插入「1. Blogger 平台」→ B 點的程式碼,並參照程式碼行號:

E~F:紅色字串得改為文章區塊的 class 或 id。

Y:除了使用藍色字串參數 "fadeIn" 的淡入特效,還可用 "slideDown" 由小圖伸展到大圖的特效,或是使用 "show" 無特效。



四、小結


若曾使用舊版 Lazy Load 安裝程式,由於圖片寬、高事先不知道數值,瀏覽器無法為圖片保留位置,畫面在捲動之間會不斷產生 reflow、版面區塊會不斷擠壓變動,增加瀏覽器無謂的運算量。使用了本篇新版的安裝程式後,相信畫面捲動的時候,可以明顯感受到兩者的差異性,為網頁帶來更好的效能。



五、常見 FAQ


日後若有常見問題,會持續補充在此。

Q1: 留言 #2 提到「進入任意一篇文章後再按導覽列上的"首頁"回到首頁,會出現圖片不見的狀況(重新整理後又正常出現)」?

Ans: 如果 Blogger 首頁會出現異常情形的話,請刪除 Y 行最後面的逗點 "," 以及 Z 行的內容即可。(2014.12.18 補充:由於多位使用者出現此情形,已將原程式碼 Y 行最後面的逗點 "," 以及 Z 行的內容去除 )


優化網站效能 相關文章:
0 0
如這篇文章對你有幫助,歡迎「分享」到 FB、「追蹤」粉絲團、「訂閱」最新文章

25 則留言:

  1. 感謝您的分享!晚上來安裝!

    回覆刪除
    回覆
    1. Wayne您好:請問一下,我在安裝後,當我進入任意一篇文章後再按導覽列上的"首頁"回到首頁,會出現圖片不見的狀況(重新整理後又正常出現)
      問題截圖https://lh4.googleusercontent.com/-M7VyNavCK9k/VJF61xyLF5I/AAAAAAABFMI/M9DDGHBGMSE/w973-h545-no/%E5%9C%96%E7%89%871.jpg
      網址:http://www.hairblog.tw/
      麻煩您,謝謝

      刪除
    2. 請問是將Z行整行去除嗎?還是Z行的 gif 檔網址去除呢?謝謝您!

      刪除
    3. 已可正常顯示了!感謝你^^

      刪除
  2. 感謝 Wayne~
    安裝了新版的 Lazy Load,預留圖片寬高位置,讓我的BLOG更加的流暢 :)
    而經過測試後,也一樣出現和樓上相同的問題,但刪除Z行後問題就解決了!
    網址:http://taipeilifemap.blogspot.com/

    回覆刪除
  3. 想再請教一個問題。安裝這個版本後,後續寫的新文章是否還需要照您的文章「減少網頁 reflow(回流) 的 CSS 實作技巧﹍優化網站效能(3)」裡面第三項第1點來加上圖片尺寸呢?謝謝

    回覆刪除
    回覆
    1. 這麼說也是!目前使用後,網頁速度感覺不出來有影響到!感謝解惑^^

      刪除
  4. 謝謝WFU的懶人包,每次都受惠良多~
    試用了好幾天,覺得這個真的是很完美的解決方案,
    只是我好像遇上了點問題,也似乎只有我一人遇到?
    事發擷圖: http://i.imgur.com/FJdytLm.jpg
    網址: http://totoasims.blogspot.com/2014/06/lot-display-8thdorm.html#more
    有時候有些圖片會呈現成圖中的樣子,
    不正常地縮小了(似乎只有使用Firefox才會這樣)
    詭異的是重新整理後就回復正常了,
    雖然如此,還是想知道原因在哪,讓我對症下藥。
    會不會是我哪個步驟做錯了呢?

    回覆刪除
    回覆
    1. 謝謝WFU的回覆~
      其實我是安裝了本篇的Lazyload後,發現blogger本身的燈箱無法有效運作,只會讀取每篇的第一張圖片,才安裝Fancybox的耶!反而是用fancybox才可以正常地使用燈箱,可以在燈箱模式看到文章的圖片。
      我暫時拿走了fancybox,似乎還是有同一個問題,
      這邊也會試著逐一移除其他js,來推論是不是有某個js跟它打架了,不過這的確需要時間。
      謝謝你~

      刪除
    2. 直接開了一個新的部落格來測試,似乎真的是由於圖片太多了……
      在新的部落格,放十張圖的時候,在FF的環境也運作正常,但二十張就不行了。
      把jquery版本換成2.1.1,問題還是會出現。
      只好換回舊版lazyload,謝謝WFU的幫忙~

      刪除
  5. Wayne您好:剛剛看到我的網頁圖片出現這個問題 https://lh6.googleusercontent.com/-CBG-o4FGhbw/VLi4umgXgMI/AAAAAAABGVY/XErUn3ytkfY/w1000-h563-no/%E5%87%BA%E9%8C%AF1.jpg 這個狀況只在火狐(Chrome正常沒發生過)上出現(F5後又恢復正常),請問一下是跟"自動取得圖片寬高"有關係嗎??謝謝您

    回覆刪除
    回覆
    1. 已修正!!感謝您!!我再觀察看看!!
      不過有點納悶,我的網頁感覺不出有淡入特效耶!這正常嗎??
      而且用Chrome檢查,看到Lazy Load的js有錯誤

      刪除
    2. 沒想到只是jquery跟js的順序不同就錯了= =感謝嚕!!已修正!!
      改版後的程式碼"Y 行最後面的逗點 "," 以及 Z 行的內容"不用刪除了嗎??

      刪除
    3. Wayne您好:我照個程式碼安裝後還是出現了如我在#1發問的問題,圖片只出現1x1的白色灰點小圖,麻煩您看一下

      刪除
  6. 已更新!更快了~

    我的行動版即使使用「網頁版」,載入也頗快的,就用「網頁版」頂著先。

    官方行動範本/自訂,都 ... 太簡潔/無法正常顯示(內文也沒出來),令人一度很困擾。
    偏偏行動瀏覽的數量一直遞增,有時候幾乎跟網頁瀏覽各佔一半了。

    回覆刪除
    回覆
    1. 4. 我的手機是現在來說,很掉漆的紅米一代,
      因為連它都跑的了網頁版,所以才想說直接那樣做。

      目前啟用行動版的「自訂」了,
      隨便一篇文章都是沒有內文、廣告等該有的基本樣式,
      隨便一篇傳送門:lasjargon.blogspot.tw/2015/04/mkvtoolnix.html?m=1

      首頁基本上也算是空蕩蕩了...,不知道該從哪裡形容了...,
      大概就是...跟大家都差很多...這樣。

      本來想說等你的行動裝置系列文都完結、吸收了,再來看看有沒有辦法自救。
      那就麻煩你提前出手,先幫我把脈一下,荒廢好久又增添你的麻煩了 >"<

      刪除
    2. 又要除蟲了(捕蟲網 check),請給我一大把時間抓蟲去~~

      對耶,那三個廣告一直是我的困擾點,頂部那個在 opera 沒法顯示...。
      (破破爛爛的語法,成就破破爛爛的 blog,耶~~)
      順便先來研究一下「在 Blogger 文章各種位置插入 Adsense 廣告﹍安裝懶人包」,你忙先,讓我的腦細胞先遊盪一下。

      刪除
    3. 結果我看完所有 .js,嘗試遮蔽或移動到</head>,都無果。

      最後偷吃步,
      索性參照這篇「Blogger 自訂行動版範本實作﹍(2) 文章+側邊欄+頁尾」→「六、文章區塊」→「2. 懶人作法」,將判斷式遮蔽,行動版終於顯示了,雖然目前版面看起來有點小混亂 XD。

      Q:我這樣的作法正確嗎?還是我並沒有除到錯?

      刪除
    4. .js的部份有以下這些:

      jquery.min.js|lazyload-min.js
      這 2 個基於主觀判斷,位置本來就在</heae>之上,完全沒動到

      adsbygoogle.js
      一開始的嫌疑犯,在<body...>內被我腦殘的重複了三次,
      後來按照「Blogger 文章各種位置插入 Adsense 廣告﹍安裝懶人包」所示的位置刪除、移動與使用,舊有的 code 已經全數刪掉了。

      Analytics分析 ga.js|plusone.js
      這 2 個完全沒有動到,直接照本宣科搬到乾淨的範本似乎意義不大?

      google_top_exp.js
      這一個我不知道它是誰 XD,所以也沒移動

      相關文章 related-post-140416-min.js|留言分頁 commTab-min-140729.js
      這 2 個基於感性的判斷 XD,我也完全沒移動。

      留言區塊作者虛線高亮 jquery-latest.js
      嘗試移動到</heae>之上,但會影響到 lazyload-min.js 的執行,所以又搬回原位。

      這些動作因為行動版內文完全無顯示的時間壓力,只被我粗糙的搜尋出來並直接在原來的範本上做更動,明天會再到弄到測試的部落格範本試試,還好我現在知道了連<script>的標籤也要去掉,多謝 Wayne 大提醒了門外漢。

      另外我想問,尚未更動前,我不乾淨範本的判斷式如下:
      <b:widget id='Blog1' locked='false' title='網誌文章' type='Blog'>
      ...
      <b:if cond='data:mobile == "false"'>
      ...
      這是正常的嗎?

      (ps.請原諒門外漢不知所謂的描述與問題 >"<)

      刪除
    5. 哈哈!門外漢不小心清過頭了。

      好的,跳!移動~

      刪除
  7. 用Chrome的F12檢測貴站圖片載入情形
    LazyLoad貌似還是會一次下載所有圖片...
    只是顯示圖片會慢慢出現...
    這樣應該跟LazyLoad有段差距...

    回覆刪除
  8. 版大 你好,我按你的教學在網站加入安裝代碼,但是沒有變化…照樣一次載入圖片

    回覆刪除
  9. 「三、安裝程式碼」的部分要搜尋「 」
    但是在「編輯 HTML」中搜尋不到。

    回覆刪除
    回覆
    1. 似乎沒有成功,把程式碼都放上去後去pagespeed做測速,還是檢驗出建議「延後載入畫面外圖片」。
      檢測網址:https://cosmicwack.blogspot.com/2019/04/blog-post_28.html

      刪除
    2. 感覺剛剛提供的資訊不夠充足。再次比對程式後,我發現兩個奇怪的地方。
      如果資訊還是不夠,請還需要提供哪方面的資訊才有辦法處理,十分感謝。

      刪除

張貼留言注意事項:

◎ 勾選「通知我」可收到後續回覆的mail!
◎ 請在相關文章留言,與文章無關的主題可至「Blogger 社團」提問。
◎ 請避免使用 Safari 瀏覽器,否則無法登入 Google 帳號留言(只能匿名留言)!
◎ 提問若無法提供足夠的資訊供判斷,可能會被無視。建議先參考這篇「Blogger 提問技巧及注意事項」。
◎ CSS 相關問題非免費諮詢,建議使用「Chrome 開發人員工具」尋找答案。
◎ 手機版相關問題請參考「Blogger 行動版範本的特質」→「三、行動版範本不一定能執行網頁版工具」;或參考「Blogger 行動版範本修改技巧 」,或本站 Blogger 行動版標籤相關文章。
◎ 非官方範本問題、或貴站為商業網站,請參考「Blogger 免費諮詢 + 付費諮詢
◎ 若是使用官方 RWD 範本,請參考「Blogger 推出全新自適應 RWD 官方範本及佈景主題」→ 不建議對範本進行修改!
◎ 若留言要輸入語法,"<"、">"這兩個符號請用其他符號代替,否則語法會消失!
◎ 為了過濾垃圾留言,所有留言不會即時發佈,請稍待片刻。
◎ 本站「已關閉自刪留言功能」。

TOP