2020前端性能優(yōu)化清單(二)
- 原文地址:https://www.smashingmagazine.com/2020/01/front-end-performance-checklist-2020-pdf-pages[1]
- 翻譯:陳隆德
- 本翻譯僅做學(xué)習(xí)交流使用,轉(zhuǎn)載請(qǐng)注明原處
- 本文是性能優(yōu)化清單系列第二篇,可以先看看前面的文章:2020前端性能優(yōu)化清單(一)
資源優(yōu)化
17 使用 Brotli 進(jìn)行純文本壓縮
2015 年,Google推出了[2]Brotli[3],這是一種全新的開源無(wú)損數(shù)據(jù)格式,并被現(xiàn)在所有現(xiàn)代瀏覽器支持[4]。實(shí)際上,Brotli 似乎比 Gzip 和 Deflate更有效[5]得多[6]。取決于您的設(shè)置,壓縮可能會(huì)(非常)緩慢,但是這樣慢的壓縮速度最終也會(huì)帶來(lái)較高的壓縮率。不管怎樣,它都能快速解壓縮。這篇文章可以估算站點(diǎn)使用 Brotli 壓縮可以節(jié)省的大小[7]。
問(wèn)題在于,使用 Brotli 壓縮所有資源非常耗費(fèi)計(jì)算資源和時(shí)間。因此,僅由于其產(chǎn)生的成本開銷,許多服務(wù)器就無(wú)法使用它。實(shí)際上,在最高壓縮級(jí)別下,Brotli 是如此之慢,以至于服務(wù)器等待動(dòng)態(tài)資源資產(chǎn)時(shí),服務(wù)器開始發(fā)送響應(yīng)所花費(fèi)的時(shí)間會(huì)抵消文件大小減少帶來(lái)的任何潛在收益。但是,對(duì)于靜態(tài)資源壓縮,應(yīng)該首選更高壓縮比的壓縮設(shè)置[8]。
如果您可以避開動(dòng)態(tài)壓縮靜態(tài)資產(chǎn)的成本,Brotli 就是值得的。Brotli 可用于任何純文本的內(nèi)容-HTML,CSS,SVG,JavaScript 等。
策略?使用最高壓縮比配置的Brotli+Gzip 預(yù)壓縮靜態(tài)資源[9],并使用 Brotli 配置 3~5 級(jí)壓縮比來(lái)快速壓縮(動(dòng)態(tài))HTML。確保服務(wù)器正確處理 Brotli 或 gzip 的內(nèi)容協(xié)商頭。
04-compression-front-end-performance-checklist-2020無(wú)論是在桌面還是移動(dòng)設(shè)備上,有大約 15%使用 Brotli 壓縮。使用 gzip 壓縮則大約是 65%。其余部分完全沒有壓縮。(圖像來(lái)源:?Web 年鑒:壓縮[10])
18 使用響應(yīng)式圖像和 WebP
盡可能使用具有?srcset,sizes?和??元素的響應(yīng)式圖像[11]。在使用它的同時(shí),還可以通過(guò)??元素和 JPEG 兜底(請(qǐng)參閱 Andreas Bovens 的代碼片段[12])來(lái)使用webP 格式[13](除 Safari 和 iOS Safari 外,所有現(xiàn)代瀏覽器均支持)?;蚴褂脙?nèi)容協(xié)商(使用 Accept 標(biāo)頭)。Ire Aderinokun 有一個(gè)非常詳細(xì)的教程[14],將圖像轉(zhuǎn)換為 WebP。
Sketch 內(nèi)置支持 WebP,而 Photoshop 可以使用的WebP 插件[15]從 Photoshop 導(dǎo)出 WebP 圖像。也有其他選項(xiàng)可用[16],如果您使用的是 WordPress 或 Joomla,也可以使用擴(kuò)展來(lái)幫助您輕松實(shí)現(xiàn)對(duì) WebP 的支持,例如 WordPress 的Optimus[17]和Cache Enabler[18]以及Joomla 自己支持的擴(kuò)展[19](通過(guò) Cody Arsenault)。
值得注意的是,雖然 WebP 圖像文件大小與同等的 Guetzli 和 Zopfli 相比[20],該格式不支持像 JPEG 那樣的漸進(jìn)式渲染[21],這就是為什么用戶使用好的 JPEG 可能會(huì)更快地看到實(shí)際圖像,盡管 WebP 圖像的網(wǎng)絡(luò)加載速度可能會(huì)更快。使用 JPEG,我們可以用一半甚至四分之一的時(shí)間就提供給“像樣的”用戶體驗(yàn),并在稍后加載其余的數(shù)據(jù),而不是像 WebP 那樣只有半空的圖像。您的決定將取決于您想要的是什么:使用 WebP,您將減少圖像大小,而使用 JPEG,您將提高圖像的可感知性。
在 Smashing Magazine 上,我們使用后綴?-opt?作為圖像名稱-例如?brotli-compression-opt.png;每當(dāng)圖像包含該后綴時(shí),團(tuán)隊(duì)中的每個(gè)人都知道該圖像已經(jīng)過(guò)優(yōu)化。并且-不需要再加后綴了!-Jeremy Wagner 甚至在Smashing book 上出版了一本《WebP》[22]。
responsive-breakpoints-opt響應(yīng)式圖像斷點(diǎn)生成器[23]可自動(dòng)執(zhí)行圖像適配和標(biāo)記生成
19 圖像是否經(jīng)過(guò)適當(dāng)優(yōu)化?
當(dāng)您在落地頁(yè)上時(shí),快速加載特定圖像非常關(guān)鍵,請(qǐng)確保 JPEG 是漸進(jìn)式渲染的,并使用mozJPEG[24]壓縮(通過(guò)操縱掃描級(jí)別來(lái)縮短圖像初始化渲染的時(shí)間),或者看看Guetzli[25],這是 Google 的新型開源編碼器,專注于用戶感知性能,并利用了 Zopfli 和 WebP 的經(jīng)驗(yàn)。唯一的缺點(diǎn)[26]是:處理時(shí)間慢(每百萬(wàn)像素一分鐘的 CPU)。對(duì)于 PNG,我們可以使用 Pingo,對(duì)于 SVG,我們可以使用SVGO[27]或SVGOMG[28]。而且,如果您需要從網(wǎng)站上快速預(yù)覽和復(fù)制或下載所有 SVG 資源,svg-grabber[29]也可以為您做到這一點(diǎn)。
每一篇圖像優(yōu)化文章都會(huì)說(shuō)的,但是有特別重要的一點(diǎn):矢量資源整潔和緊密。確保清理未使用的資源,刪除不必要的元數(shù)據(jù),并減少圖稿中路徑點(diǎn)的數(shù)量(從而減少 SVG 代碼)。(謝謝 Jeremy?。?/p>
但是,還有更多高級(jí)的方案。你可以:
- 使用Squoosh[30]壓縮、調(diào)整大小和處理圖像,以獲得最佳的壓縮級(jí)別(有損或無(wú)損)
- 使用響應(yīng)式圖像斷點(diǎn)生成器[31]或Cloudinary[32]或Imgix[33]等服務(wù)來(lái)自動(dòng)進(jìn)行圖像優(yōu)化。同樣,在大多數(shù)情況下,僅使用?
srcset?和?size?將會(huì)獲得顯著的好處 - 檢查響應(yīng)式標(biāo)記的效率,可以使用Imaging-heap[34],這是一個(gè)命令行工具,可以測(cè)量視口大小和設(shè)備像素比率之間的效率
- 對(duì)圖片和 Iframe 進(jìn)行懶加載,可以使用混合懶加載[35]、本地懶加載,或懶加載[36]庫(kù),它檢測(cè)通過(guò)用戶交互觸發(fā)的可見性更改來(lái)實(shí)現(xiàn)懶加載(使用 IntersectionObserver,我們將在后面進(jìn)行探討)
- 對(duì)于屏幕外圖像,我們可以先顯示一個(gè)占位符,然后當(dāng)圖像出現(xiàn)在視口中時(shí),使用 IntersectionObserver 觸發(fā)網(wǎng)絡(luò)調(diào)用,以將圖像下載到后臺(tái)。然后,我們可以推遲渲染直到調(diào)用 img.decode()完成解碼[37];如果Image Decode API[38]不可用,就直接下載圖像。渲染圖像時(shí),我們可以使用淡入動(dòng)畫。Katie Hempenius 和 Addy Osmani 在他們的性能提升:網(wǎng)絡(luò)性能優(yōu)化建議和技巧[39]文章中分享了更多這方面的觀點(diǎn)
- 您可以配置在“Pull Request”中自動(dòng)圖像壓縮[40],因此任何圖像都會(huì)在構(gòu)建時(shí)完成壓縮。這個(gè) Github Actions 會(huì)對(duì) PNG 和 JPG 使用 mozjpeg 和 libvips 進(jìn)行壓縮
- 請(qǐng)注意默認(rèn)情況下加載但可能永遠(yuǎn)都不會(huì)渲染的圖像,例如網(wǎng)頁(yè)中的“輪播圖”,“手風(fēng)琴”和“圖像畫廊”
- 考慮使用“Sizes”屬性更換請(qǐng)求的圖像[41],通過(guò)根據(jù)媒體查詢來(lái)確定不同的圖像顯示尺寸。例如在“放大鏡”組件中,通過(guò)設(shè)置?
sizes?來(lái)觸發(fā)替換圖像資源 - 每次上線前 Review頁(yè)面中圖像下載過(guò)程是否有不同[42],以防止意外下載不需要的前景和背景圖像
- 有時(shí)僅靠?jī)?yōu)化圖像并不能解決問(wèn)題。為了縮短開始渲染關(guān)鍵圖像所需[43]的時(shí)間,請(qǐng)延遲加載不太重要的圖像,并在關(guān)鍵圖像渲染完成后再加載任何異步腳本
- 如果要優(yōu)化內(nèi)部存儲(chǔ),可以使用 Dropbox 新的Lepton 格式[44],它的 JPEG 無(wú)損壓縮率平均可以達(dá)到 22%
- 請(qǐng)注意 CSS 中的aspect-ratio 屬性[45]和internalsize 屬性[46],這將允許我們?cè)O(shè)置圖像的縱橫比和尺寸,因此瀏覽器可以提前保留預(yù)定義的布局槽,這樣在頁(yè)面加載期間就可以避免出現(xiàn)布局跳躍[47]
- 如果您在技術(shù)上喜歡冒險(xiǎn),則可以使用Edge worker[48](CDN 上的實(shí)時(shí)過(guò)濾器)對(duì) HTTP/2 流進(jìn)行切割和重排,以便更快地通過(guò)網(wǎng)絡(luò)發(fā)送圖像。Edge Worker 使用的 JavaScript 流使用可以控制的塊(它們是在 CDN Edge 上運(yùn)行的 JavaScript,可以修改流響應(yīng)),因此您可以控制圖像的傳遞。對(duì)于 service worker,這時(shí)間點(diǎn)太晚了,因?yàn)槟鸁o(wú)法控制線路上的內(nèi)容,但可以與 Edge Worker 一起使用。因此在為特定的落地頁(yè)中,您可以逐步在的靜態(tài) JPEG 上使用它們以節(jié)省傳輸大小
viewport-percentage-match通過(guò)imaging-heap[49]輸出的樣本,這是一種命令行工具,可測(cè)量跨視口大小和設(shè)備像素比率的效率(圖片來(lái)源[50])
隨著客戶提示的應(yīng)用,響應(yīng)式圖像的未來(lái)可能會(huì)發(fā)生巨大變化??蛻舳颂崾局傅氖?HTTP 請(qǐng)求標(biāo)頭字段,例如?DPR,?Viewport-Width,?Width,?Save-Data,?Accept(指定圖像格式首選項(xiàng))等。他們會(huì)將用戶瀏覽器,屏幕,連接等的詳細(xì)信息通知服務(wù)器。因此,服務(wù)器可以決定如何用適當(dāng)大小的圖像填充布局,并僅以所需格式提供這些圖像。通過(guò)客戶端提示,我們將資源選擇從 HTML 標(biāo)記移到了客戶端和服務(wù)器之間的請(qǐng)求-響應(yīng)協(xié)商中。
正如 Ilya Grigorik 所指出的那樣,客戶的提示令響應(yīng)式圖像的應(yīng)用更加完整-它們不是響應(yīng)式圖像的替代方案。“?元素在 HTML 標(biāo)記中提供了必要的藝術(shù)方向控制??蛻舳颂崾驹诮Y(jié)果圖像請(qǐng)求上提供注釋,從而實(shí)現(xiàn)資源選擇自動(dòng)化。ServiceWorker 在客戶端上提供完整的請(qǐng)求和響應(yīng)管理功能。” 例如,服務(wù)人員可以向請(qǐng)求添加新的客戶端提示標(biāo)頭值,重寫 URL 并將圖像請(qǐng)求指向 CDN,根據(jù)連接性和用戶首選項(xiàng)調(diào)整響應(yīng),等等。它不僅適用于圖像資源,而且適用幾乎所有其他類型的請(qǐng)求。
對(duì)于支持客戶端提示的客戶端,測(cè)試結(jié)果可以為圖像節(jié)省了 42%的字節(jié)[51],70%以上測(cè)試結(jié)果少了 1MB +的字節(jié)。在 Smashing Magazine 上,我們也可以測(cè)試得到19-32%的改善[52]。不幸的是,客戶端提示還必須獲得一些瀏覽器支持[53],比如Firefox[54]仍在考慮中。但是,如果同時(shí)為客戶端提示提供正常的響應(yīng)圖像標(biāo)記和??標(biāo)簽,則瀏覽器將評(píng)估響應(yīng)圖像標(biāo)記,并使用客戶端提示的 HTTP 標(biāo)頭返回適當(dāng)?shù)膱D像資源。
還不夠好?另外,您還可以使用多背景圖像技術(shù)[55]來(lái)提高圖像的感知性能。請(qǐng)記住,調(diào)整對(duì)比度[56]和模糊不必要的細(xì)節(jié)(或消除顏色)也可以減小文件大小。嗯,如果您需要放大一張小照片而不損失畫質(zhì)嗎?考慮使用Letsenhance.io[57]。
到目前為止,這些優(yōu)化僅涉及基礎(chǔ)知識(shí)。Addy Osmani 已發(fā)布了有關(guān)圖像優(yōu)化的非常詳細(xì)的指南[58],該指南非常深入地介紹了圖像壓縮和顏色管理的細(xì)節(jié)。例如,您可以使圖像的不必要部分模糊(通過(guò)應(yīng)用高斯模糊濾鏡)以減小文件大小,最終您甚至可以刪除顏色或?qū)D片變成黑白以進(jìn)一步減小大小。對(duì)于背景圖像,在 Photoshop 中以 0 到 10%的質(zhì)量導(dǎo)出圖片也是絕對(duì)可以接受的。此外,不要在 web 開發(fā)中使用 JPEG-XR[59]-“使用 CPU 上對(duì) JPEG-XRs 進(jìn)行解碼的處理將影響渲染性能,增加的耗時(shí)可能使字節(jié)大小節(jié)省的優(yōu)化無(wú)效,甚至超過(guò)其大小節(jié)省的積極影響,尤其是在 SPA 的 web 應(yīng)用中”。
replace-animated-gifsAddy Osmani 建議用循環(huán)播放的內(nèi)聯(lián)視頻替換動(dòng)畫 GIF,文件大小差異明顯(節(jié)省 80%)
20 視頻是否經(jīng)過(guò)適當(dāng)優(yōu)化?
到目前為止,我們已經(jīng)討論完了圖像,但是我們避開了有關(guān)優(yōu)化 GIF 的事情。坦白說(shuō),與其加載會(huì)影響渲染性能和帶寬的沉重動(dòng)畫 GIF,不如改用動(dòng)畫 WebP(將 GIF 用作兜底),或?qū)⑵淙刻鎿Q為循環(huán)的 HTML5 視頻,這是一個(gè)好主意。是的,與圖像不同,瀏覽器不會(huì)預(yù)加載??內(nèi)容,但 HTML5 視頻往往比 GIF 更輕,更小。沒有選擇嗎?好吧,至少我們可以使用有損 GIF[60],gifsicle[61]或giflossy[62]對(duì) gif 進(jìn)行有損壓縮以減小圖像大小。
測(cè)試表明,與 gif 相比,使用?img?標(biāo)簽內(nèi)聯(lián)視頻的顯示速度快 20 倍,解碼速度快 7 倍,而且文件大小非常小。
好消息是,視頻格式多年來(lái)一直在不斷發(fā)展。長(zhǎng)期以來(lái),我們一直希望 WebM 成為統(tǒng)一所有的格式,而 WebP(基本上是 WebM 視頻容器內(nèi)部的一個(gè)靜止圖像)將替代過(guò)時(shí)的圖像格式。但是,盡管這些年 WebP 和 WebM 已經(jīng)獲得了不錯(cuò)的支持,但并沒有實(shí)現(xiàn)重大突破。
2018 年,開源媒體聯(lián)盟發(fā)布了一種新的有前途的視頻格式,稱為 AV1。AV1 的壓縮與 H.265 編解碼器(H.264 的演進(jìn))相似,但與后者不同,AV1 是免費(fèi)的。H.265 許可證的價(jià)格迫使瀏覽器供應(yīng)商改為使用性能相同的 AV1:(就像 H.265 一樣)AV1 壓縮的效果是 WebM 的兩倍。
av1-logo-2018-fullAV1 很有可能成為網(wǎng)絡(luò)視頻的最終標(biāo)準(zhǔn)(圖片來(lái)源:Wikimedia.org[63])
實(shí)際上,Apple 當(dāng)前使用的是HEIF[64]和HEVC(H.265)[65],并且最新 iOS 上的所有照片和視頻均以這些格式保存,而不是 JPEG。雖然 HEIF 和 HEVC(H.265)還不可以正確顯示在 web 網(wǎng)頁(yè)上(或許您讀這篇文章的時(shí)候可能已經(jīng)不是這樣了?),但 AV1 已經(jīng)可以 -- 并且正在不斷獲得瀏覽器支持[66]。因此,在所有??標(biāo)簽中添加?AV1?資源是合理的,因?yàn)樗坪跛袨g覽器供應(yīng)商都在使用。
目前,使用最廣泛且受支持的編碼是 H.264,由 MP4 文件提供,因此在提供文件之前,請(qǐng)確保您的 MP4 經(jīng)過(guò)多遍編碼處理[67],并用frei0r iirblur 效果[68]模糊處理(如果適用的話),并且在服務(wù)器接受字節(jié)服務(wù)[69]時(shí),將atom 元數(shù)據(jù)移動(dòng)[70]到文件的頭部。Boris Schapira 提供了FFmpeg 的準(zhǔn)確說(shuō)明[71],以最大限度地優(yōu)化視頻。當(dāng)然,提供 WebM 格式作為替代方案也會(huì)有所幫助。
是否需要開始更快地渲染視頻,但是視頻文件仍然太大?例如,當(dāng)您在目標(biāo)網(wǎng)頁(yè)上有大型背景視頻時(shí)如何優(yōu)化?常用的技術(shù)是先將第一幀顯示為靜止圖像,或顯示經(jīng)過(guò)優(yōu)化的短循環(huán)段,將其作為為視頻的一部分,然后等視頻有足夠的緩沖,再開始播放實(shí)際的視頻。Doug Sillars 撰寫的詳細(xì)的背景視頻性能優(yōu)化指南[72],在這種情況下可能會(huì)有所幫助。(謝謝,Guy Podjarny?。?/p>
視頻播放性能本身就是一個(gè)很長(zhǎng)很龐大的故事,如果您想深入了解它,請(qǐng)查看 Doug Sillars 另一系列文章,有關(guān)當(dāng)前視頻[73]和視頻交付最佳做法[74]的內(nèi)容,其中包括有關(guān)視頻交付指標(biāo)的詳細(xì)信息,視頻預(yù)加載,壓縮和流式傳輸?shù)鹊葍?nèi)容。
font-loading-strategies-optZach Leatherman 的字體加載策略綜合指南[75]提供了十幾種更好的 Web 字體交付方案
21 網(wǎng)絡(luò)字體是否經(jīng)過(guò)優(yōu)化?
首先要問(wèn)的一個(gè)問(wèn)題是,您是否可以擺脫使用UI 系統(tǒng)的字體[76]的麻煩?再次檢查它們?cè)诟鞣N平臺(tái)上的顯示是否正確[77]。如果不是這種情況,您提供的網(wǎng)絡(luò)字體很有可能會(huì)包含字形以及未使用的額外功能和粗細(xì)。您可以用字體代工廠將 Web 字體轉(zhuǎn)換成較小的子集,或者如果您使用的是開源字體,則可以使用Glyphhanger[78]或Fontsquirrel[79]對(duì)它們進(jìn)行子集化。您甚至可以使用 PeterMüller 的subfont[80]來(lái)自動(dòng)完成整個(gè)字體子集化的工作流程,subfont 是一個(gè)命令行工具,可以靜態(tài)分析您的頁(yè)面以生成最佳的 Web 字體子集,然后將其注入到您的頁(yè)面中。
WOFF2 的瀏覽器支持非常好,您可以將 WOFF 作為不支持 WOFF2 的瀏覽器的兜底字體 - 也可以用系統(tǒng)字體兜底,以便更好地支持舊版瀏覽器。Web 字體加載有很多很多的選擇,您可以從 Zach Leatherman 的“字體加載策略綜合指南”[81]中選擇一種策略(這個(gè)代碼片段也可以作為web 字體加載方法使用[82])。
目前可以使用的更好的選擇是:預(yù)加載關(guān)鍵 FOFT[83]和“compromise”技術(shù)[84]。他們兩個(gè)都分兩階段渲染來(lái)逐步交付 Web 字體-首先需要一個(gè)小的超級(jí)子集,以便使用 Web 字體快速準(zhǔn)確地渲染頁(yè)面,然后加載異步家族的其余部分。所不同的是,只有在不支持字體加載事件[85]的場(chǎng)景中,“compromise”技術(shù)才會(huì)異步加載 polyfill,因此默認(rèn)情況下您無(wú)需加載 polyfill。需要快速達(dá)到目標(biāo)嗎?Zach Leatherman 提供了23 分鐘的快速教程和案例研究[86],可以讓您的字體的處理井井有條。
通常情況下,使用?preload?資源提示來(lái)預(yù)加載字體是一個(gè)好主意,但是在您的頁(yè)面中標(biāo)記中,predload 字體需要放在關(guān)鍵 CSS 和 JavaScript 的鏈接之后。對(duì)于?preload,優(yōu)先級(jí)經(jīng)常令人困惑[87],因此請(qǐng)考慮在外部腳本阻塞之前將?rel=" preload"?元素注入到 DOM 中。根據(jù) Andy Davies 的說(shuō)法,“使用腳本注入的資源將在瀏覽器中隱藏,直到腳本執(zhí)行為止,我們可以使用此行為來(lái)延遲瀏覽器發(fā)現(xiàn)?preload?元素?!?否則,字體加載將在第一次渲染時(shí)就耗費(fèi)您的時(shí)間。
有選擇性地[88]選擇最重要的文件是一個(gè)好主意,例如,那些對(duì)渲染至關(guān)重要的文件,或者那些可以幫助頁(yè)面提升可見性的和避免破壞性文本重排的文件。一般來(lái)說(shuō),Zach 建議預(yù)加載每個(gè)系列的一到兩種字體-如果字體不那么關(guān)鍵,推遲一些字體加載時(shí)機(jī)也是有意義的。
在?@font-face?規(guī)則中定義?font family?時(shí),使用?local()?值(按名稱引用本地字體)已經(jīng)是非常普遍的做法了:
/*?Warning!?Probably?not?a?good?idea!?*/
@font-face?{
??font-family:?Open?Sans;
??src:?local('Open?Sans?Regular'),
???????local('OpenSans-Regular'),
???????url('opensans.woff2')?format?('woff2'),
???????url('opensans.woff')?format('woff');
}
這個(gè)方案是合理的:因?yàn)橐恍┝餍械拈_源字體,如 Open Sans,會(huì)預(yù)裝在一些驅(qū)動(dòng)程序或應(yīng)用程序中,所以如果字體是本地可用的,瀏覽器就可以立即顯示本地字體,而不需要下載網(wǎng)頁(yè)字體。但是,正如Bram Stein 所指出的[89],“盡管一種本地字體與一種網(wǎng)絡(luò)字體的名稱相同,但它很可能本質(zhì)上不是同一種字體。許多網(wǎng)絡(luò)字體與它們的‘桌面’版本不同。文本可能是不同的,一些字符也可能會(huì)退回到其他字體,Open-Type 特色可能會(huì)被遺漏,或者行高可能會(huì)有所不同?!?/p>
另外,隨著字體隨著時(shí)間的推移而發(fā)展,本地安裝的版本也可能與網(wǎng)絡(luò)字體大不相同,字符看起來(lái)也大不相同。因此,根據(jù) Bram 的說(shuō)法,最好不要在?@font-face?規(guī)則中混合本地安裝的字體和網(wǎng)絡(luò)字體。
沒有人喜歡等待內(nèi)容顯示。因此我們可以使用 font-display 這個(gè) CSS 描述符來(lái)控制字體的加載行為并使內(nèi)容立即(font-display: optional)或幾乎立即(font-display: swap)可讀 但是,如果要避免文本重排[90],我們?nèi)匀恍枰褂米煮w加載 API,特別是在對(duì)文本重繪進(jìn)行分組時(shí)或者在使用第三方代理的時(shí)候。除非您可以將 Google Fonts 與 Cloudflare Workers[91]一起使用,那就不用考慮使用字體加載 API 了。
論及 Google Fonts:盡管它最近增加了對(duì)字體顯示的支持[92],但還是建議大家考慮使用google-webfonts-helper[93],這是一種輕松自如地托管 Google Fonts 的方案。如果可以的話,請(qǐng)始終自行托管字體[94]以實(shí)現(xiàn)對(duì)字體行為最大程度的控制。
通常,如果您使用?font-display: optional,則同時(shí)使用?preload?可能不是一個(gè)好主意,因?yàn)樗鼘⑻崆坝|發(fā)該 Web 字體請(qǐng)求(如果此時(shí)您需要獲取其他關(guān)鍵路徑資源,則該字體加載會(huì)導(dǎo)致網(wǎng)絡(luò)擁塞)。使用?preconnect?可以更快地進(jìn)行跨域字體請(qǐng)求,但請(qǐng)謹(jǐn)慎使用預(yù)加載,因?yàn)閺牟煌搭A(yù)加載字體會(huì)引發(fā)網(wǎng)絡(luò)爭(zhēng)用。所有這些技術(shù)都在 Zach 的Web 字體加載食譜[95]中進(jìn)行了介紹。
如果用戶啟用了輔助功能首選項(xiàng)中的減少動(dòng)效[96]或省流量模式(請(qǐng)參閱Save-Data 頭[97]),那么選擇延遲 Web 字體加載(或至少第二階段才渲染)可能是個(gè)好主意。或者當(dāng)用戶碰巧具有慢速連接時(shí)(通過(guò)Network_Information_API[98]檢測(cè))也是如此。最后,如果用戶選擇了省流量模式,我們還可以使用`Preferences-Reduced-Data`[99]?CSS 媒體查詢來(lái)清除字體聲明。如果來(lái)自客戶端 HTTP 擴(kuò)展中的 Save-Data 請(qǐng)求標(biāo)頭是?on/off,則省流量模式的媒體查詢的結(jié)果在大多數(shù)情況下都是公開的,可以在 CSS 中使用。雖然還不完全是。
要測(cè)量 Web 字體加載性能,請(qǐng)考慮所有文本可見時(shí)間[100](所有字體均已加載且所有內(nèi)容均以 Web 字體顯示的時(shí)刻)、變?yōu)檎鎸?shí)斜體的時(shí)間[101]以及首次渲染后的Web 字體回流數(shù)[102]。顯然,這兩個(gè)指標(biāo)越低,性能就越好。需要注意的是,可變字體[103]可能需要更重視性能影響[104]。它們?yōu)樵O(shè)計(jì)者提供了更廣闊的排版選擇設(shè)計(jì)空間,但這是以一系列單個(gè)的串行請(qǐng)求為代價(jià)的,而不是將多個(gè)單獨(dú)的文件并行請(qǐng)求。單個(gè)請(qǐng)求可能會(huì)很慢,從而阻塞頁(yè)面上內(nèi)容的渲染。因此,設(shè)置字體子集并將其拆分成字符集仍然很重要。不過(guò),好的一面是,有了可變字體,默認(rèn)情況下我們將只有一次回流,因此不需要 JavaScript 來(lái)對(duì)重繪進(jìn)行分組。
那么,怎樣才能制定一個(gè)防彈(安全)的網(wǎng)絡(luò)字體加載策略呢?將字體子集化并在第二階段渲染做好準(zhǔn)備,使用?font-display?描述符聲明它們,使用字體加載 API 對(duì)重繪進(jìn)行分組,并將字體存儲(chǔ)在持久的 service worker 緩存中。第一次訪問(wèn)時(shí),在阻塞的外部腳本之前插入腳本預(yù)加載字體。如有必要,您可以退回到 Bram Stein 的Font Face Observer[105]。如果您對(duì)測(cè)量字體加載的性能感興趣,Andreas Marschke 研究的文章可以看看:使用 Font API 和 UserTiming API 來(lái)跟蹤性能[106]。
最后,不要忘了使用unicode range[107],它可以將大字體分解成小的語(yǔ)言專用字體,并使用 Monica Dinculescu 的font-style-matcher[108]來(lái)最小化布局中由于兜底字體和 Web 字體之間的大小差異而造成的不和諧變化。
網(wǎng)頁(yè)字體處理的未來(lái)如何?隨著漸進(jìn)式字體的發(fā)展,我們最終或許能夠?qū)崿F(xiàn):“在任何給定的頁(yè)面上只下載所需的字體部分,并且對(duì)于對(duì)該字體的后續(xù)請(qǐng)求,根據(jù)后續(xù)頁(yè)面查看所需的附加字形集來(lái)動(dòng)態(tài)地‘修補(bǔ)’原始下載”,就像 Jason Pamental 所說(shuō)的。這里有個(gè)類似這種增量傳輸方案的演示[109],并且正在不斷完善中。
參考資料
[1]https://www.smashingmagazine.com/2020/01/front-end-performance-checklist-2020-pdf-pages:?https://www.smashingmagazine.com/2020/01/front-end-performance-checklist-2020-pdf-pages
[2]推出了:?https://opensource.googleblog.com/2015/09/introducing-brotli-new-compression.html
[3]Brotli:?https://github.com/google/brotli
[4]并被現(xiàn)在所有現(xiàn)代瀏覽器支持:?http://caniuse.com/#search=brotli
[5]更有效:?https://quixdb.github.io/squash-benchmark/#results-table
[6]得多:?https://paulcalvano.com/index.php/2018/07/25/brotli-compression-how-much-will-it-reduce-your-content/
[7]估算站點(diǎn)使用 Brotli 壓縮可以節(jié)省的大小:?https://tools.paulcalvano.com/compression.php
[8]首選更高壓縮比的壓縮設(shè)置:?https://css-tricks.com/brotli-static-compression/
[9]Brotli+Gzip 預(yù)壓縮靜態(tài)資源:?https://css-tricks.com/brotli-static-compression/
[10]Web 年鑒:壓縮:?https://almanac.httparchive.org/en/2019/compression
[11]響應(yīng)式圖像:?https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/
[12]代碼片段:?https://dev.opera.com/articles/responsive-images/#different-image-types-use-case
[13]webP 格式:?https://www.smashingmagazine.com/2015/10/webp-images-and-performance/
[14]教程:?https://bitsofco.de/why-and-how-to-use-webp-images-today/
[15]WebP 插件:?http://telegraphics.com.au/sw/product/WebPFormat#webpformat
[16]也有其他選項(xiàng)可用:?https://developers.google.com/speed/webp/docs/using
[17]Optimus:?https://wordpress.org/plugins/optimus/
[18]Cache Enabler:?https://wordpress.org/plugins/cache-enabler/
[19]Joomla 自己支持的擴(kuò)展:?https://extensions.joomla.org/extension/webp/
[20]同等的 Guetzli 和 Zopfli 相比:?https://www.ctrl.blog/entry/webp-vs-guetzli-zopfli
[21]像 JPEG 那樣的漸進(jìn)式渲染:?https://youtu.be/jTXhYj2aCDU?t=630
[22]Smashing book 上出版了一本《WebP》:?https://www.smashingmagazine.com/ebooks/the-webp-manual/
[23]響應(yīng)式圖像斷點(diǎn)生成器:?http://www.responsivebreakpoints.com/
[24]mozJPEG:?https://github.com/mozilla/mozjpeg
[25]Guetzli:?https://github.com/google/guetzli
[26]唯一的缺點(diǎn):?https://medium.com/@fox/talk-the-state-of-the-web-3e12f8e413b3
[27]SVGO:?https://www.npmjs.com/package/svgo
[28]SVGOMG:?https://jakearchibald.github.io/svgomg/
[29]svg-grabber:?https://chrome.google.com/webstore/detail/svg-grabber-get-all-the-s/ndakggdliegnegeclmfgodmgemdokdmg
[30]Squoosh:?https://squoosh.app/
[31]響應(yīng)式圖像斷點(diǎn)生成器:?http://www.responsivebreakpoints.com/
[32]Cloudinary:?Cloudinary
[33]Imgix:?https://www.imgix.com/
[34]Imaging-heap:?https://github.com/filamentgroup/imaging-heap
[35]混合懶Z加載:?https://www.smashingmagazine.com/2019/05/hybrid-lazy-loading-progressive-migration-native/
[36]懶加載:?https://github.com/verlok/lazyload
[37]推遲渲染直到調(diào)用 img.decode()完成解碼:?https://youtu.be/YJGCZCaIZkQ?t=570
[38]Image Decode API:?https://medium.com/dailyjs/image-loading-with-image-decode-b03652e7d2d2
[39]性能提升:網(wǎng)絡(luò)性能優(yōu)化建議和技巧:?https://youtu.be/YJGCZCaIZkQ?t=436
[40]配置在“Pull Request”中自動(dòng)圖像壓縮:?https://github.com/marketplace/actions/image-actions
[41]考慮使用“Sizes”屬性更換請(qǐng)求的圖像:?https://www.filamentgroup.com/lab/sizes-swap/
[42]頁(yè)面中圖像下載過(guò)程是否有不同:?https://csswizardry.com/2018/06/image-inconsistencies-how-and-when-browsers-download-images/
[43]渲染關(guān)鍵圖像所需:?https://calendar.perfplanet.com/2019/the-ugly-truth-about-optimising-beautiful-images/
[44]Lepton 格式:?https://github.com/dropbox/lepton
[45]aspect-ratio 屬性:?https://drafts.csswg.org/css-sizing-4/#ratios
[46]internalsize 屬性:?https://github.com/ojanvafai/intrinsicsize-attribute
[47]避免出現(xiàn)布局跳躍:?https://24ways.org/2018/jank-free-image-loads/
[48]Edge worker:?https://youtu.be/jTXhYj2aCDU?t=854
[49]imaging-heap:?https://github.com/filamentgroup/imaging-heap
[50]圖片來(lái)源:?https://pbs.twimg.com/media/DY1XZ28VwAAwjd8.jpg
[51]為圖像節(jié)省了 42%的字節(jié):?https://twitter.com/igrigorik/status/1032657105998700544
[52]19-32%的改善:?https://www.smashingmagazine.com/2016/01/leaner-responsive-images-client-hints/
[53]獲得一些瀏覽器支持:?http://caniuse.com/#search=client-hints
[54]Firefox:?https://bugzilla.mozilla.org/show_bug.cgi?id=935216
[55]多背景圖像技術(shù):?http://csswizardry.com/2016/10/improving-perceived-performance-with-multiple-background-images/
[56]調(diào)整對(duì)比度:?https://css-tricks.com/contrast-swap-technique-improved-image-performance-css-filters/
[57]Letsenhance.io:?https://letsenhance.io/
[58]有關(guān)圖像優(yōu)化的非常詳細(xì)的指南:?https://images.guide/
[59]不要在 web 開發(fā)中使用 JPEG-XR:?https://calendar.perfplanet.com/2018/dont-use-jpeg-xr-on-the-web/
[60]有損 GIF:?https://kornel.ski/lossygif
[61]gifsicle:?https://github.com/kohler/gifsicle
[62]giflossy:?https://github.com/pornel/giflossy
[63]Wikimedia.org:?https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/AV1_logo_2018.svg/2560px-AV1_logo_2018.svg.png
[64]HEIF:?https://caniuse.com/#search=heif
[65]HEVC(H.265):?https://caniuse.com/#search=hevc
[66]正在不斷獲得瀏覽器支持:?https://caniuse.com/#feat=av1
[67]多遍編碼處理:?https://medium.com/@borisschapira/optimize-your-mp4-video-for-better-performance-dareboost-blog-fb2f3f3dce77
[68]frei0r iirblur 效果:?https://yalantis.com/blog/experiments-with-ffmpeg-filters-and-frei0r-plugin-effects/
[69]接受字節(jié)服務(wù):?https://medium.com/@borisschapira/optimize-your-mp4-video-for-better-performance-dareboost-blog-fb2f3f3dce77
[70]atom 元數(shù)據(jù)移動(dòng):?http://www.adobe.com/devnet/video/articles/mp4_movie_atom.html
[71]FFmpeg 的準(zhǔn)確說(shuō)明:?https://medium.com/@borisschapira/optimize-your-mp4-video-for-better-performance-dareboost-blog-fb2f3f3dce77
[72]詳細(xì)的背景視頻性能優(yōu)化指南:?https://calendar.perfplanet.com/2019/performance-tips-for-background-video/
[73]有關(guān)當(dāng)前視頻:?https://www.smashingmagazine.com/2018/10/video-playback-on-the-web-part-1/
[74]視頻交付最佳做法:?https://www.smashingmagazine.com/2018/10/video-playback-on-the-web-part-2/
[75]字體加載策略綜合指南:?https://www.zachleat.com/web/comprehensive-webfonts/
[76]UI 系統(tǒng)的字體:?https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/
[77]再次檢查它們?cè)诟鞣N平臺(tái)上的顯示是否正確:?http://fontfamily.io/Roboto,Segoe_UI,TImes,Helvetica,sans-serif
[78]Glyphhanger:?https://www.afasterweb.com/2018/03/09/subsetting-fonts-with-glyphhanger/
[79]Fontsquirrel:?https://www.fontsquirrel.com/tools/webfont-generator
[80]subfont:?https://github.com/Munter/subfont#readme
[81]“字體加載策略綜合指南”:?https://www.zachleat.com/web/comprehensive-webfonts/
[82]web 字體加載方法使用:?https://github.com/zachleat/web-font-loading-recipes
[83]預(yù)加載關(guān)鍵 FOFT:?https://www.zachleat.com/web/comprehensive-webfonts/#critical-foft-preload
[84]“compromise”技術(shù):?https://www.zachleat.com/web/the-compromise/
[85]字體加載事件:?https://www.igvita.com/2014/01/31/optimizing-web-font-rendering-performance/#font-load-events
[86]23 分鐘的快速教程和案例研究:?https://www.zachleat.com/web/23-minutes/
[87]優(yōu)先級(jí)經(jīng)常令人困惑:?https://andydavies.me/blog/2019/02/12/preloading-fonts-and-the-puzzle-of-priorities/
[88]有選擇性地:?https://youtu.be/FbguhX3n3Uc?t=1637
[89]Bram Stein 所指出的:?https://www.bramstein.com/writing/web-font-anti-patterns-local-fonts.html
[90]避免文本重排:?https://www.zachleat.com/web/font-display-reflow/
[91]將 Google Fonts 與 Cloudflare Workers:?https://blog.cloudflare.com/fast-google-fonts-with-cloudflare-workers/
[92]最近增加了對(duì)字體顯示的支持:?https://css-tricks.com/google-fonts-and-font-display/
[93]google-webfonts-helper:?https://google-webfonts-helper.herokuapp.com/fonts
[94]自行托管字體:?https://speakerdeck.com/addyosmani/web-performance-made-easy?slide=55
[95]Web 字體加載食譜:?https://github.com/zachleat/web-font-loading-recipes
[96]減少動(dòng)效:?https://webkit.org/blog/7551/responsive-design-for-motion/
[97]Save-Data 頭:?https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/save-data/
[98]Network_Information_API:?https://developer.mozilla.org/en-US/docs/Web/API/Network_Information_API
[99]Preferences-Reduced-Data:?https://github.com/w3c/csswg-drafts/issues/2370
所有文本可見時(shí)間:?https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#s5IYiho
[101]變?yōu)檎鎸?shí)斜體的時(shí)間:?https://vimeo.com/336091879#t=1550s
[102]Web 字體回流數(shù):?https://noti.st/zachleat/KNaZEg/the-five-whys-of-web-font-loading-performance#sJw0KSc
[103]可變字體:?https://alistapart.com/blog/post/variable-fonts-for-responsive-design
[104]更重視性能影響:?https://youtu.be/FbguhX3n3Uc?t=2161
[105]Font Face Observer:?https://github.com/bramstein/fontfaceobserver
[106]使用 Font API 和 UserTiming API 來(lái)跟蹤性能:?https://www.andreas-marschke.name/posts/2017/12/29/Fonts-API-UserTiming-Boomerang.html
[107]unicode range:?https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2015/august/how-to-subset-fonts-with-unicode-range/
[108]font-style-matcher:?https://meowni.ca/font-style-matcher/
[109]增量傳輸方案的演示:?https://fonts.gstatic.com/experimental/incxfer_demo
推薦閱讀
我的公眾號(hào)能帶來(lái)什么價(jià)值?(文末有送書規(guī)則,一定要看)
每個(gè)前端工程師都應(yīng)該了解的圖片知識(shí)(長(zhǎng)文建議收藏)
為什么現(xiàn)在面試總是面試造火箭?
