記得前百度工程師張雲龍說過,頁面前端優化問題絕對不僅僅是為頁面提速的問題,更是工程的問題,有興趣的同學可以閱讀《前端工程與效能優化》。裡面有提到根據雅虎14條優化原則,《高效能網站建設指南》以及《高效能網站建設進階指南》中提到的優化點梳理出來的優化方向:
張雲龍先生提及到的優化方向從提出到現在雖已相隔兩年時間,前端技術也在飛速發展,但其提到的工程化思想仍是前端優化的一個大方向,亦有很大的指導意義。
當然這是另外更大的話題了,這篇文章並不是將本次的優化點按照萌妹子暖暖寫的《前端優化不完全指南》一一列出(當然並沒有那麼多,前端優化永遠寫不完,寫不完:- O),而是重點結合專案總結這一次優化中如何尋找優化點以及收益比較大的常見方法,希望可以對遇到相似問題的同學有幫助,前端大神可輕輕淡笑而過。
高清圖適配優化
我們所說的高清圖一般是指至少具有 Retina 屏級別精度的圖片,就是平時所說的『2x』圖。對於高清圖的適配,一般會根據圖片特點以及專案實際情況去制定適配方案。
純色圖
純色圖一般應用到裝飾性的小 icon,如側導航的標題 icon:
此類圖示由單色組成,可以根據一定的繪製規則製成 iconfont 圖示,iconfont 的圖示具有向量性,其大小和顏色可以都可以通過樣式來控制。
新版首頁出現了 33 個單色圖示,這些圖示複用性很強,同一個圖示在不同頁面都有出現,而且同一個圖示還有不一樣的尺寸,如果用傳統方法做成圖片的話圖片數量會很多,即使全部合併成 sprite 圖,圖片的 K 數也會很大,而且後期如果有修改的話還得重新合併 sprite 圖,因此這次首頁改版所有的純色圖示的高清適配全部使用 iconfont 圖示:
ICONFONT圖示管理
改版所用到的 ICONFONT 圖示生成以及管理選擇了『阿里巴巴向量圖示庫』線上服務,在上面通過上傳圖示的 SVG 檔案生成對應的字型檔案,還可以根據圖示分專案管理:
圖示生成後,該服務還會自動打包好所需檔案,並製成 DEMO 網頁,供本地預覽查詢圖示對應的字型編碼以及使用方法:
相信前端的同學很早就使用過 ICONFONT 服務,筆者衷心感謝提供 ICONFONT 服務的 THX 組織,除了 ICONFONT 服務,THX 還提供了不少業界良心的前端精品工具服務,感謝他們為業界作出的貢獻。
非純色圖
非純色圖通常用『2X』圖適配,適配方案可以有很多選擇:媒體查詢、srcset屬性、image-set屬性、指令碼控制。
媒體查詢、srcset屬性 和 image-set屬性成功匹配的基本是高階瀏覽器,相容性略差,指令碼控制相容性更佳,專案具體用哪一種要看『國情』了:
上圖是我國PC端作業系統市場份額的大概分佈情況,可以看出 95% 以上的使用者都是使用 Windows 系統的,使用 Windows 系統的使用者裝置螢幕大部分都是普清屏,而使用高清屏的使用者基本都是使用 Mac OS 系統,Mac OS 系統的瀏覽器又以『高富帥』Chrome 和 Safari 為主,因此只考慮適配 Mac OS 裝置,最終選擇比媒體查詢更為方便的『srcset屬性』和『image-set屬性』方案:內容圖使用 srcset 屬性適配,背景圖使用 image-set 屬性適配高清圖:
1 |
<img src="images/bg_eco_v2_@1x.png" srcset="images/bg_eco_v2_@1x.png 1x, images/bg_eco_v2_@2x.png 2x" alt=""> |
1 2 3 4 |
.chain_item_icon{ background-image: -webkit-image-set(url("images/bg_chains_@1x.png") 1x, url("images/bg_chains_@2x.png") 2x); background-image: image-set(url("images/bg_chains_@1x.png") 1x, url("images/bg_chains_@2x.png") 2x); } |
設計類字型
新版京東雲出現了很多設計類字型,也就是我們平時所說的非系統字型,如新版京東雲首頁版塊標題用的字型 —-『方正蘭亭超細黑體』
對於設計類字型,前端和視覺會達成共識不會大面積使用,因為該類字型的實現只能用圖片或通過樣式 @font-face
屬性去實現:
- 圖片方案:雖然可以高精度還原,相容性強,但是每改動一處地方都需要換圖,不方便維護,內容擴充套件性差,而且如果要適配高清裝置,又得多一套圖。
@font-face
屬性方案:字型具有向量性,高清裝置可以輕鬆適配,內容擴充套件性強,但是不同的瀏覽器存在渲染的差異,相容性略弱,@font-face
字型檔案大小一般又是 M 級別,會不同程度影響頁面載入體驗。
如果非系統字型應用的地方只有幾個標題,而且不常改動的話,用圖片方案較優,但是新版京東雲在其它頻道的首頁也會應用到,內容較多,而且要適配高清圖,所以圖片方案並不適用,@font-face
屬性方案更合適。
針對 『@font-face
屬性方案』檔案體積大和瀏覽器渲染差異的兩個不足之處,採取了一個折中的方案,也就是瀏覽器的渲染差異在視覺可以接受的範圍下,只抽取要用到的字型生成體積相對較小的字型檔案。
Junmer 出品的 Fontmin 工具可以大大滿足這個需求,只需要將用到了字型源以及需要生成的文字內容加入到工具中,就可以生成相應的字型檔案:
原來 2MB 的字型
生成的字型檔案只有 11KB,字型檔案體積減少達到了 99%
圖片資源優化
存在的問題
額外請求數過多
舊版首頁載入的時候,一共有40個請求,其中圖片的請求就有 31 個,佔總請求數的 77%
有些可以合併的圖片並沒有做處理:
其中至少有 11 張圖片是可以合併成一張圖片的,也就是至少多了 27% 的額外請求數
資源浪費
首屏的圖片資源載入了 31個,但其可見的圖片只有 2 張,載入了 100% 的圖片資源,首屏圖片資源利用率只有 6%
只要使用者沒有完全瀏覽完網頁就跳到其它頁面的話,都會造成資源浪費。
圖片載入體驗差
首屏耗時較長的大圖載入過程並沒有做 Loading佔點陣圖 提示,有機會出現輪播圖區域空白時間過長:
上圖顯示頁面載入 1.8s 後,Banner 背景圖還是沒有出來,雖然網速飛快的使用者有可能不出現這種情況,但是不排除網路慢的使用者會碰上。
除此之外,圖片載入失敗的時候也沒有做容錯處理,就有機會出現圖片載入失敗的系統預設圖示樣式,會影響頁面的美觀性:
優化方案
雖然新版首頁的圖片資源的排版和內容有所不同,但至少可以針對舊版額外請求數多、資源浪費、載入體驗差這三個方向去改進。
減少額外請求數
減少圖片額外請求數,收益比較明顯的一般有三個方法:圖片合併、iconfont 圖示、Base64,三個方法都有各自的優缺點:
- 圖片合併優點:相容性強可快取可提前載入多型圖可提升圖片載入顯示體驗
缺點:維護性差、合併圖片型別以及大小控制限制高、有可能造成資源浪費
適合:修改更新少的常駐型低色位的裝飾小圖
- Iconfont優點:可快取向量性可控性強
缺點:存在瀏覽器渲染差異性、只能純色、檔案體積略大
適合:純色圖示
- Base64優點:無額外請求
缺點:不可快取、相容性差、程式碼冗餘、可讀性差、維護不便、CPU記憶體耗損大
適合:體積小複用率低的背景裝飾圖示
新版首頁一共有 70 個圖片資源,其中有 49 個是純色圖示,16 個是低色位非純色圖,5 個是高色點陣圖。
49 個純色圖示全部使用了 Iconfont 方法處理,13 個低色位非純色圖使用了合併方法,一共有 62 個圖片做了減少額外請求處理,最終圖片資源請求數一共只有 14 個,其中純色圖的請求數佔 2 個,低色位非純色圖請求數佔 6 個,圖片總請求數減少了 80% ,圖片合併和 Iconfont 的額外請求處理率分別達到了 56% 和 96%
可以看到 Iconfont 的額外請求處理率相當出色,因為適合應用他的物件特點比較簡單,而圖片合併會受到合併圖片的格式、資源分佈、模組分佈等情況影響,其額外請求處理率會相對低於 Iconfont。
我們可以得到一個優化圖片額外請求的小結論:純色圖示優先考慮 Iconfont,低色位非純色圖片根據專案實際需要來做合併優化,Base64非特殊圖片不使用
資源按需載入
新版首頁需要載入的圖片資源一共有 14個,其中首屏的圖片資源有 8 個,可見圖片有 5 個,如果不作處理,那麼首屏圖片資源的利用率只有 35%
如果進行資源按需載入,在非首屏的圖片資源實行懶載入,將輪播圖不可見的兩張圖片做觸發載入處理,這樣首屏的載入圖片資源只有 8 個,首屏圖片資源利用率則可達到 60%,提高了 70% 的圖片資源利用率,資源按需載入不失為一種避免資源浪費的最掛實踐方法
佔位提示圖提高載入體驗
圖片載入的時間長短由很多因素決定,如伺服器響應時間、使用者所用網路頻寬、圖片大小等,但無論是哪一種情況,總有一個等待的過程,在這過程總會有一個空白時間,特別是佔屏面積比較大的首屏輪播大圖和採取懶載入的圖片,即使圖片空白時間很短,使用者也會有不同程度的感知,會給使用者帶來一種唐突或漫長等待的感覺,如果載入過程給圖片加上體積比較小的佔位提示圖,則會讓使用者有一個圖片載入預知,當圖片載入完成後再呈現給使用者看,這樣使用者在圖片載入過程中看到的都是完整的圖片
當圖片載入失敗的時候,展示佔點陣圖,避免系統預設的圖片載入失敗圖示出現
漸進增強優化
漸進增強是指從最基本的功能出發,在保證系統在任何環境中的可用性基礎上,逐步增加功能,提高使用者體驗,
動畫效能漸進增強
出現在頁面比較重要位置的模組,如輪播圖、導航等,如果需要做動畫效果的話,在高低端瀏覽器上都應該能統一實現出來,新舊版首頁首屏都以輪播圖為主,輪播圖切換都使用了漸隱漸現的動畫效果。
舊版的動畫實現在高低端瀏覽器都使用了 JQ 第三方動畫庫
1 2 3 4 5 6 7 8 9 |
... <script type="text/javascript" src="js/jcloud_new/jquery.SuperSlide.2.1.1.js"></script> .. <script> //banner $(".banner-slider").slide({mainCell:".bd ul",effect:"fold",autoPlay:true,interTime:4000,delayTime:1000}); $(".box-slider").slide({mainCell: ".bd ul", effect: "left", autoPlay: true, interTime: 5000, scroll: 6, vis: 6}); ... </script> |
其實漸隱漸現的效果 CSS3 動畫也能實現。新版首頁的輪播圖動畫設定了 CSS3 動畫後,再利用指令碼控制樣變化以觸發 CSS3 動畫,這樣支援動畫屬性的瀏覽器就能以 CSS3 動畫實現效果,而不支援的瀏覽器則通過指令碼的屬性判斷,用 JQ 動畫實現:
1 2 3 4 5 6 7 8 9 10 11 |
.fc_item{ position: absolute; left: 0; top: 0; right: 0; bottom: 0; filter: alpha(opacity=0); opacity: 0; background: #fff; @include trst(opacity 0.8s linear); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 輪播圖切換 function imgChange(opt){ ... // 如果支援 transform 屬性,使用CSS3動畫 if(supports('transform')){ $imgList.eq(opt).addClass('active').css('opacity','1').siblings().removeClass('active').css('opacity','0'); }else{ // 如果不支援 transform 屬性,使用JQ動畫 $imgList.eq(opt).stop().animate({ 'opacity': '1' },800).addClass('active').siblings().stop().animate({ 'opacity': '0' },800).removeClass('active'); } ... } ... |
JQ 動畫雖然相容性好,但其動畫效能遠遠不及 CSS3 動畫,因此我們可以用以下的方法對動畫效能實現漸進增強:高階瀏覽器可以通過觸發 CSS3 動畫實現效果,低端瀏覽器則使用 JQ 動畫實現。
視覺漸進增強
視覺漸進增強通常可以通過 CSS3 屬性和增加 CSS3 動畫來實現,現主流的網站基本都會對視覺做漸進增強處理。本次首頁改版主要在多型元素、切換元素上做了處理
支援 CSS3 動畫的 SexyGuy
不支援 CSS3 動畫的 PoorGuy
Tab 鍵錨點聚焦優化
瀏覽頁面的時候,通過 Tab 鍵可以聚焦頁面上的連結錨點,這時候瀏覽器會在錨點增加一個系統預設邊框樣式告訴使用者錨點已選中,按 Enter
就可以開啟選中的錨點,如 Chrome 瀏覽器上 google 首頁的語音搜尋按鈕:
即使使用者在瀏覽頁面的時候滑鼠突然失靈了也可以通過鍵盤操作繼續完成瀏覽網頁,這樣的設計顯然是為了增強頁面的可用性。
但很多時候,在一些重要位置的內容,如全站的導航,產品經理或視覺設計師會要求將這個系統的樣式去掉,於是很多同學可能會選擇設定outline:none
去掉邊框樣式,有些甚至會在全域性 a 標籤上設定,如舊版的京東雲首頁:
outline:none
設定之後,頁面上的所有連結雖然能通過Tab
鍵聚焦,但連結並沒有被選中的樣式,沒有辦法直觀辨出選中的連結
雖然並非所有使用者都會用到 Tab 鍵,但還是會有少數使用者會用到,如鍵盤黨,而這種降低可用性的體驗存在表明頁面並沒有健全,因此並不建議去掉outline
樣式。
如果真的有去掉 outline
樣式的需求怎麼辦?其實,頁面連結一般都會被設計為多型的,利用連結的多型樣式,為連結加上:focus
偽類選中樣式,Tab 選中連結後就會展示 :focus
偽類樣式了,如新版首頁的導航:
可以為連結加上:focus
偽類樣式
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.mod_hd_nav_sub_col{ ... a{ color: #fff; text-decoration: none; outline: none; &:hover,&:focus{ color: #ffe400; text-decoration: none; } } ... } |
當選中連結還繫結有事件的時候,也應該為之繫結相應事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
... $navBox.on({ 'mouseenter': function () { ... }, 'focus': function(){ $(this).trigger('mouseenter'); // Tab 操作支援 }, 'mouseleave': function () { ... }, 'blur': function(){ $(this).trigger('mouseleave'); // Tab 操作支援 } }, '.mod_hd_nav_item'); ... |
處理完,雖然 outline
樣式去掉了,但依然可以用 Tab 鍵完成連結的選中
靜態資源更新發布
舊版首頁所有的靜態資源的更新發布方式都是採用覆蓋式更新:
1 2 3 4 5 6 |
... <script type="text/javascript" src="js/jcloud_new/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="js/jcloud_new/jquery.SuperSlide.2.1.1.js"></script> <script type="text/javascript" src="js/jcloud_new/login_w.js"></script> <script type="text/javascript" src="http://jcms.jd.com/resource/js/cms.js"></script> ... |
覆蓋式更新發布有機會遇到快取問題以及在釋出的時候導致頁面錯亂問題,詳情可以看一下張雲龍前輩在知乎對問題『大公司裡怎樣開發和部署前端程式碼?』的回答,解決覆蓋式更新產生的問題,現主流方法就是使用 MD5 檔名進行非覆蓋式釋出,京東雲新版首頁所有的靜態資源的更新發布都採用了這種方式。
1 2 3 4 5 |
... <script src="//labs.qiang.it/pc/jcloud/gb/js/lib.min_2f4dab0c.js"></script> <script src="//labs.qiang.it/pc/jcloud/gb/js/gb.min_b599b860.js"></script> <script src="//labs.qiang.it/pc/jcloud/home/js/index.min_9d957a15.js"></script> ... |
OK,優化永遠說不完的,以上所說的只是前端優化的冰山一角,業界絕不缺高大上的優秀優化方案,但從業務實際規模出發的話,這些小優化在本次改版中已得到很明顯的收益,期待以後有更具規模的專案可以揮霍高大上的優化方案,最後把新舊版的頁面都放到預覽伺服器上了