• 原文地址:Front-End Performance Checklist 2019 — 3
  • 原文作者:Vitaly Friedman
  • 譯文出自:掘金翻譯計劃
  • 本文永久鏈接:github.com/xitu/gold-mi
  • 譯者:Starriers
  • 校對者:Jingyuan0000, kikooo

2019 前端性能優化年度總結 — 第三部分

讓 2019 來得更迅速吧~你正在閱讀的是 2019 年前端性能優化年度總結,始於 2016。

目錄

  • 資源優化
    • 17. 使用 Brotli 或 Zopfli 來對純文本進行壓縮
    • 18. 使用響應圖像和 WebP
    • 19. 圖像的優化是否得當
    • 20. 視頻優化是否得當
    • 21. Web 字體優化過了么

資源優化

17. 使用 Brotli 或 Zopfli 來對純文本進行壓縮

2015 年,Google 推出了 Brotli,一種新開源的無損數據格式,現已被所有現代瀏覽器所支持。實際上,Brotli 比 Gzip 和 Deflate 有效得多。因為它比較依賴配置,所以這種壓縮可能會(非常)慢,但較慢的壓縮意味著更高的壓縮率。不過它解壓速度很快。所以你可以考慮 Brotli 為你的網站所節省的成本。

只有用戶通過 HTTPS 訪問站點時,瀏覽器才會接受這種格式。那代價是什麼呢?Brotli 並沒有預安裝在一些伺服器上,所以如果沒有自編譯 Nginx,那麼配置就會相對困難。儘管如此,它也並非是不可攻破的難題,比如,Apache 自 2.4.26 版本起,開始逐步對它進行支持。得益於 Brotli 被眾多廠商支持,許多 CDN 也開始支持它(Akamai、AWS、KeyCDN、Fastly、Cloudlare、CDN77),你甚至(結合 service worker 一起使用)可以在不支持它的 CDN 上,啟用 Brotli。

在最高級別壓縮時,Brotli 會非常緩慢,以至於伺服器在開始發送響應前等待動態壓縮資源所花費的時間,可能會抵消文件大小(被壓縮後)的潛在增益。但對於靜態壓縮,應該首選更高級別的壓縮。

或者,你可以考慮使用將數據編碼為 Deflate、Gzip 和 Zlib 格式的 Zopfli 的壓縮演算法。任何普通的 Gzip 壓縮資源都可以通過 Zopfli 改進的 Deflate 編碼達到比 Zlib 的最大壓縮率小 3% 到 8%的文件大小。問題是壓縮文件大約需要耗費 80 倍的時間。這就是為什麼在資源上使用 Zopfli 是個好主意,因為這些資源不會發生太大的變化,它們被設計成只壓縮一次但可以下載多次。

如果可以降低動態壓縮靜態資源的成本,那麼這種付出是值得的。Brotli 和 Zopfli 都可以用於任意純文本的有效負載 — HTML、CSS、SVG 和 JavaScript 等。

有何對策呢?使用最高級別的 Brotli + Gzip 來預壓縮靜態資源,使用 Brotli 在 1 — 4 級中動態壓縮(動態)HTML。確保伺服器正確處理 Brotli 或 Gzip 的協議內容。如果你在伺服器上無法安裝/維護 Brotli,請使用 Zopfli。

18. 使用響應圖像和 WebP

盡量使用帶有 srcsetsizes 屬性的響應式圖片和 <picture> 元素響應式圖片。當然,你還可以通過在原生 <picture> 上使用 WebP 圖片以及回退到 JPEG 的機制或者使用協議內容的方式中使用 WebP 格式(在 Chrome、Opera、Firefox 65、Edge 18 中都被支持的格式)(參見 Andreas Bovens 的代碼片段),或者使用協議內容(Accept 頭部)。Ire Aderinokun 也有關於將圖像轉換為 WebP 圖像的超詳細教程。

Sketch 原生地支持 WebP 的,可以使用 Phtotshop 的 WebP 插件從 Photoshop 中導出 WebP 圖像。當然也存在其他可用的選項。如果你正在使用 WordPress 或 Joomla,也可以使用一些擴展來幫助你自己輕鬆實現對 WebP 的支持,比如適用於 WordPress 的 Optimus 和 Cache Enabler,Joomla 當然也存在對應可提供支持的擴展 (通過使用 Cody Arsenault)。

需要注意的是,儘管 WebP 圖像文件大小等價於 Guetzli 和 Zopfli,但它並不支持像 JPEG 這樣的漸進式渲染,這也是用戶以前通過 JPEG 可以更快地看到實際圖像的原因,儘管 WebP 圖像在網路中的傳輸速度更快。使用 JPEG,我們可以將一半甚至四分之一的數據提供給用戶,然後再載入剩餘數據,而不是像 WebP 那樣可能會導致有不完整的圖像。你應該根據自己的需求來進行取捨:使用 WebP,你可以有效減少負載,使用 JPEG,你可以提高性能感知。

在 Smashing Magazine 中,我們使用 -opt 後綴來為圖像命名 — 比如,brotli-compression-opt.png;這樣,當我們發現圖像包含該後綴時,團隊成員就會明白這個圖像已經被優化過了。— 難以置信!— Jeremy Wagner 出了一本關於 WebP 的書,寫的很好。

響應式圖片端點生成器會自動生成圖像和標記。

19. 圖像的優化是否得當?

當你在開發 landing page 時,特定圖像的載入必須很快,要確保 JPEG 是漸進載入的並且經過了 [mozJPEG] 或者 Guetzli 的壓縮(通過操作掃描級別來改進開始渲染的時間),Google 新開源的編碼器專註於性能感知,並利用了從 Zopfli 和 WebP 中所學的優點。唯一的缺點是:處理時間慢(每百萬像素需要一分鐘的 CPU)。對於 PNG 來說,我們可以使用 Pingo,對於 SVG 來說,我們可以使用 SVGO 或 SVGOMG。如果你需要快速預覽、複製或下載網站上的所有 SVG 資源,那麼你可以嘗試使用 svg-grabber。

雖然每一篇圖像優化文章都會說,但是我還是要提醒應該保證矢量資源的乾淨和緊湊。要記得清理未使用的資源,刪除不必要的元數據以及圖稿中的路徑點數量(比如 SVG 這類代碼)(感謝 Jeremy!

還有更高級的選項,比如:

  • 使用 Squoosh 以最佳壓縮級別(有損或無損)壓縮。調整和操作圖像。
  • 使用響應式圖像斷點生成器或 Cloudinary、Imgix 這樣的服務來實現自動化圖像優化。此外,在許多情況下,使用 srcsetsizes 可以獲得最佳效果。
  • 要檢查響應標記的效率,你可以使用 imaging-heap(一個命令行工具)來檢測不同視窗大小和設備像素比的效果。
  • 使用 lazysizes 來延遲載入圖像和 iframes,這是一個通過檢測用戶交互(或之後我們將討論的 IntersectionObserver)來觸發任何可見性修改的庫。
  • 注意默認載入的圖像,它們可能永遠也用不到 —— 例如,在 carousels、accordions 和 image galleries。
  • 考慮根據請求類型來指定的不同圖像顯示以通過 Sizes 屬性切換圖像,比如,操作 sizes 來交換 magnifier 組件中的數據源。
  • 為防止前景和背景圖像的意外下載,請檢查圖像下載的不一致性。
  • 為了從根本上優化存儲,你可以使用 Dropbox 的新格式(Lepton)來對 JPEG 執行平均值可達到 22% 的無損壓縮。
  • 注意 CSS 屬性中的 aspect-ratio 屬性 和 intrinsicsize 屬性,它們允許為圖像設置寬高和尺寸,因此瀏覽器為了避免樣式錯亂,可以在頁面載入期間提前預留一個預定義的布局槽。
  • 如果你喜歡冒險,為了更快地通過網路傳輸圖像,可以使用基於 CDN 的實時過濾器 Edge workers 來終止並重排 HTTP/2 流。Edge workers 使用你可以控制的 JavaScript 流模塊(它們是運行在 CDN 上的,可以修改響應流),這樣你就可以控制圖像的傳輸。相對於 service worker 來說,這個過程時間稍長,因為你無法控制傳輸過程,但它確實適用於 Edge workers。因此,你可以在針對特定登錄頁面逐步保存的靜態 JPEG 上使用它們。

imaging-heap(一個用於檢測跨視窗大小及設備像素比的載入效率的命令行工具)的輸出樣例,(圖像來源)(詳細預覽)

響應式圖像的未來可能會隨著採用客戶端提示而發生巨變。客戶端提示內容是 HTTP 的請求頭欄位,例如 DPRViewport-WidthWidthSave-DataAccept(指定圖像格式首選項)等。它們應該告知伺服器用戶的瀏覽器、屏幕、連接等細節。因此,伺服器可以決定如何用對應大小的圖像來填充布局,而且只提供對應格式所需的圖像。通過客戶端提示,我們將資源從 HTML 標記中,遷移到客戶端和伺服器之間的請求響應協議中。

就像 Ilya Grigorik 說的那樣,客戶端提示使圖像處理更加完整 —— 它們不是響應式圖像的替代品。<picture> 在 HTML 標記中提供了必要藝術方向的控制。客戶端提示為請求的圖像提供注釋來實現資源選擇的自動化。Service Worker 為客戶端提供完整的請求和響應管理功能。比如,Service Worker 可以在請求中附加新的客戶端提示 header 值,重寫 URL 並將圖像請求指向 CDN,根據鏈接調整響應,用戶偏好等。它不僅適用於圖像資源,也適用於所有其他請求。

對於支持客戶端提示的客戶端,可以檢測到在圖像上已經節省了 42% 的位元組和超過 70% 的 1MB+ 位元組數。在 Smashing 雜誌上,我們同樣可以檢測到已經提高了 19-32% 的性能。不幸的是,客戶端提示仍然需要得到瀏覽器的支持才行。Firefox 和 Edge 正在考慮對它的支持。但如果同時提供普通的響應圖像標記和客戶端提示的 <meta> 標記,瀏覽器將評估響應圖像標記並使用客戶端提示 HTTP header 請求相應的圖像。

還不夠?那麼你可以使用多種背景圖像技術來提高圖像的感知性能。請記住,處理對比以及模糊不必要細節(或刪除顏色)也可以減小文件大小。你想放大一張小照片而不至於損失質量的話,可以考慮使用 Letsenhance.io。

到目前為止,這些優化只涉及基本內容。Addy Osmani 出版了一份非常詳細的關於基本圖像優化的指南,這份指南對於圖像壓縮和顏色管理的細節有很深入的講解。例如,你可以模糊圖像中不必要的部分(通過應用高斯模糊過濾器)來減小文件大小,甚至可以移除顏色或將圖像轉換為黑白來進一步縮小文件。對於背景圖像,從 Photoshop 中導出的照片質量只有 0 到 10% 是完全可以接受的。不要在 web 上使用 JPEG-XR — 「在 CPU 上解碼 JPEG-XRs 軟體端這個過程會讓節省位元組大小這個潛在地積極影響失效,甚至更糟,尤其是在 SPAs 情況下」。

20. 視頻優化是否得當?

到目前為止,我們的已經討論完了圖像的相關內容,但我們避免了關於 GIF 優點的探討。坦白說,與其載入影響渲染性能和帶寬的重動畫 GIF,不如選擇動態 WebP(GIF 作為回退)或者用 HTML5 videos 循環來替換它們。是的,href="calendar.perfplanet.com">帶有 <video> 的瀏覽器性能極差,而且與圖像不同的是,瀏覽器不會預載入 <video> 內容,但它們往往比 GIF 更輕量級、更小。別無他法了么?那麼至少我們可以通過 Lossy GIF、gifsicle 或 giflossy 來有損壓縮 GIF。

早期測試表明帶有 img 標籤的內聯視頻相較於等效的 GIF,除了文件大小問題外,前者的顯示的速度要快 20 倍,解碼要快 7 倍。雖然在 Safari 技術預覽中聲明了對 <img src=".mp4"> 的技術支持,但是這個特性還遠未普及,因此它在近期內不會被採用。

Addy Osmani 推薦用循環內聯視頻來取代 GIF 動畫。文件大小差異明顯(節省了 80%)。(預覽)

前端是不停進步的領域,多年來,視頻格式一直在不停改革。很長一段時間裡,我們一直希望 WebM 可以成為格式的統治者,而 WebP(基本上是 WebM 視頻容器中的一個靜止圖像)將取代過時的圖像格式。儘管這些年來 WebP 和 WebM 獲得了支持,但我們所希望看到的突破並未發生。

在 2018,Alliance of Open Media 發布了一種名為 AV1 的視頻格式。AV1 具有和 H.265(H.264 的改進版本)編碼器類似的壓縮,但與後者不同的是,AV1 是免費的。H.265 的許可證價格迫使瀏覽器供應商採用性能相同的 AV1:AV1(與 H.265 一樣)的壓縮性能是 WebP 的兩倍

AV1 很有可能成為網路視頻的終極標準。(圖像來源:Wikimedia.org)(詳細預覽)

事實上,目前 Apple 使用的是 HEIF 格式和 HEVC(H.265),最新的 IOS 中,所有的照片和視頻都以這些格式保存,而不是純 JPEG 格式。儘管 HEIF 和 HEVC(H.265) 並沒有在網上被公開使用,但被瀏覽器已經開始對慢慢支持 AV1 了。因此在你的 <video> 標籤中可以添加 AV1,因為所有的瀏覽器供應商都會慢慢加入對它的支持。

目前來說,使用最廣泛的是 H.264,由 MP4 文件提供服務,因此在提供文件之前,請確保你的 MP4 文件用 multipass-encoding 處理過,用 frei0r iirblur 進行了模糊處理(如果適用),moov atom metadata 也被移動到文件頭部,而你的伺服器接受位元組服務。Boris Schapira 提供了 FFmpeg 的確切說明來最大限度地優化視頻。當然,提供 WebM 格式作為替代方案也會有所幫助。

視頻回放性能本身就有很多內容可以研究,如果你想深入了解它的細節,可以參閱 Doug Sillar 關於當前視頻現狀和視頻傳輸最佳實踐的系列視頻。包括視頻傳輸指標、視頻預載入、壓縮和流媒體等詳細信息。

Zach Leatherman 的字體載入策略綜合指南為 web 字體傳輸提供了十幾種選擇。

21. Web 字體優化過了么?

值得提出的第一個問題就是,你是否可以首選 UI 系統字體。如果不是上述情況,那你所提供的 Web 字體很有可能包括系統字體沒有使用的字形或額外的特性或者字體粗細。你可以要求字體提供方將字體分組,或者如果你使用的是開源字體,你可以使用 Glyphhanger 或 Fontsquirrel 自行對它們進行子集化。你甚至可以使用 Peter Müller 的 subfont,一個可以自動化你整個流程的命令行工具,它可以靜態分析你的頁面,生成最佳 Web 字體子集,然後注入頁面中。

WOFF2 的支持性是最好的,你可以使用 WOFF 作為不支持 WOFF2 的瀏覽器的備用選項 — 畢竟,系統字體對遺留的瀏覽器版本會更友好。Web 字體的載入有很多,很多,很多的選項。你可以從 Zach Leatherman 的 "字體載入策略綜合指南"中選擇一種策略(代碼片段也可以在 Web 字體載入中找到)。

現在,更好的選項應該是使用 Critical FOFT 結合 preload 和 "The Compromise" 方法。它們都使用兩階段渲染來逐步提供 Web 字體 —— 首先是使用 Web 字體快速準確地渲染頁面所需的小超集,然後再非同步載入剩餘部分,不同的是 "The Compromise" 技術只在字體載入事件不受支持的的情況下才非同步載入 polyfill,所以默認情況下不需要載入 polyfill。需要快速入門?Zach Leatherman 有一個 快速入門的 23 分鐘教程和案例研究來幫助你使用字體。

一般而言,使用 preload 資源提示來預載入字體是個好主意,但需要在你的標記中包含 CSS 和 JavaScript 的鏈接。否則,字體載入會在第一次渲染時消耗時間。儘管如此,有選擇性地選擇重要文件是個好主意。比如,渲染至關重要的文件會有助於你避免可視化和具有破壞性的文本刷新文件。總之,Zach 建議預載入每個系列的一到兩個字體。如果這些字體不是很關鍵的話,延遲載入一些字體也是有意義的。

沒有人喜歡等待內容的顯示。使用 font-display CSS 描述符,我們可以控制字體載入行為並使內容可被立即讀取(font-display: optional),或者幾乎是立即被讀(font-display: swap)。然而,如果你想避免文本被重排,我們仍然需要使用字體載入 API,尤其是 group repaints,或者當你使用第三方主機時。除非你可以 用 Cloudflare workers 的 Google 字體。討論 Google 字體:考慮使用 google-webfonts-helper,這是一種輕鬆自我託管 Google 字體的方式。如果可以,那麼自行託管你的字體會賦予你對字體最大程度的控制。

一般而言,如果你選擇 font-display: optional,那麼就需要放棄使用 preload,因為它會提前觸發對 Web 字體的請求(如果你有其他需要獲取的關鍵路徑資源,就會導致網路阻塞)。preconnect 可以更快地獲取跨域字體請求,但要謹慎使用 preload,因為來自不同域的預載入字體會導致網路競爭。所有這些技術都包含在 Zach 的 Web 字體載入。

此外,如果用戶在輔助功能首選項中啟用了 Reduce Motion 或選擇數據保護模式(詳細內容可參閱 Save-Data header),那麼最好是選擇不使用 Web 字體(至少是第二階段的渲染中)。或者當用戶碰巧鏈接速度較慢時(通過 網路信息 API)。

要檢測 Web 字體的載入性能,可以考慮使用所有文本可視化的度量標準(字體載入的時,所有內容立即以 Web 字體顯示),以及首次渲染後的 Web 字體重排計數。顯然,這兩種指標越低,性能越好。重要的是考慮到變數字體對性能的需求。它們為設計師提供了更大的字體選擇空間,代價是單個串列請求與許多單獨的文件請求相反。這個單一的請求可能會緩慢地阻止頁面上的整個排版外觀。不過,好的一面是,在使用可變字體的情況下,默認情況下我們將得到一個重新的文件流,因此不需要 JavaScript 對重新繪製的內容進行分組。

有沒有一種完美的 Web 字體載入策略? 子集字體為二階段渲染做好準備,使用 font-display 描述符來聲明它們,使用字體載入 API 對重新繪製的內容進行分組並將字體存儲在持久化的 service worker 緩存中。如果有必要,你可以回到 Bram Stein 的 Font Face Observer。如果你有興趣檢測字體載入的性能,Andreas Marschke 研究了使用 字體 API 和 UserTiming API 的性能。

最後,不要忘記加入 unicode-range,將一個大字體分解成更小的特定語言字體,使用 Monica Dinculescu 的 font-style-matcher 來最小化布局上的不和諧變化,這是因為回退和 Web 字體之間的大小會產生不一致。

  • [譯] 2019 前端性能優化年度總結 — 第一部分
  • [譯] 2019 前端性能優化年度總結 — 第二部分
  • [譯] 2019 前端性能優化年度總結 — 第三部分
  • [譯] 2019 前端性能優化年度總結 — 第四部分
  • [譯] 2019 前端性能優化年度總結 — 第五部分
  • [譯] 2019 前端性能優化年度總結 — 第六部分

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久鏈接 即為本文在 GitHub 上的 MarkDown 鏈接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。

推薦閱讀:

相关文章