前端優化實踐總結
記得前百度工程師張雲龍說過,頁面前端優化問題絕對不僅僅是為頁面提速的問題,更是工程的問題,有興趣的同學可以閱讀《前端工程與性能優化》。裡面有提到根據雅虎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 屬性適配高清圖:
<img src="images/bg_eco_v2_@1x.png" srcset="images/bg_eco_v2_@1x.png 1x, images/bg_eco_v2_@2x.png 2x" alt="">
.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 第三方動畫庫
...<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 動畫實現:
.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);}
// 輪播圖切換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偽類樣式
.mod_hd_nav_sub_col{ ... a{ color: #fff; text-decoration: none; outline: none; &:hover,&:focus{ color: #ffe400; text-decoration: none; } } ...}
當選中鏈接還綁定有事件的時候,也應該為之綁定相應事件
...$navBox.on({ mouseenter: function () { ... }, focus: function(){ $(this).trigger(mouseenter); // Tab 操作支持 }, mouseleave: function () { ... }, blur: function(){ $(this).trigger(mouseleave); // Tab 操作支持 }}, .mod_hd_nav_item);...
處理完,雖然 outline樣式去掉了,但依然可以用 Tab 鍵完成鏈接的選中
靜態資源更新發布
舊版首頁所有的靜態資源的更新發布方式都是採用覆蓋式更新:
...<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 文件名進行非覆蓋式發布,京東雲新版首頁所有的靜態資源的更新發布都採用了這種方式。
...<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,優化永遠說不完的,以上所說的只是前端優化的冰山一角,業界絕不缺高大上的優秀優化方案,但從業務實際規模出發的話,這些小優化在本次改版中已得到很明顯的收益,期待以後有更具規模的項目可以揮霍高大上的優化方案,最後把新舊版的頁面都放到預覽伺服器上了
舊版首頁
新版首頁
http://weixin.qq.com/r/VjuLk3DE1C2rrTTw925E (二維碼自動識別)
推薦閱讀:
※八個例子講解現代前端框架前置知識(講義)
※《Oli-Zhao的前端一萬小時》之:離不開的Git和GitHub(2)——Git、GitHub進階(提交代碼+團隊合作)
※【前端資訊】TypeScript 2.7 發布
※前端數據流哲學