Front-End Performance Checklist 2021[1]
https://www.smashingmagazine....css前端性能優化(一):準備工做[2]html
Google在2015年推出了Brotli,這是一種全新的開源無損數據格式,並被全部現代瀏覽器支持。Brotli有11個預設的編碼質量級別,更高的質量級別要求更多的CPU以換取更好的壓縮比。較慢的壓縮速度最終會致使更高的壓縮率,但Brotli解壓速度仍然很快。4級壓縮的Brotli比Gzip更小,壓縮速度也更快。瀏覽器只有在用戶經過HTTPS訪問網站時纔會接受Brotli。它被普遍支持,許多cdn也支持它。你甚至能夠在尚不支持BCD的CDN上啓用Brotli(與Service Worker一塊兒使用)。前端
問題在於,因爲以高壓縮級別使用Brotli壓縮全部資產的成本很高,所以許多託管服務提供商不能僅僅由於其產生的鉅額成本開銷而在短期內使用它。實際上,在最高壓縮級別下,Brotli是如此之慢,以致於服務器等待動態壓縮資產時,服務器開始發送響應所花費的時間會抵消文件大小中的任何潛在收益。(可是,若是在構建期間有時間進行靜態壓縮,則最好使用更高的壓縮設置。)git
Brotli文件格式包括一個內置的靜態字典,除了包含多種語言的各類字符串外,它還支持對這些單詞進行多種轉換的選項,從而增長了其多功能性。在Felix Hanau研究中,他發現了一種方法可提升5-9級的壓縮[3]---使用「比默認值更專業的字典子集」,加上Content-Type頭告訴壓縮器它是否應該對HTML、JavaScript或CSS使用子集。結果是「當使用有限的字典使用方法在高壓縮級別壓縮web內容時,對性能的影響能夠忽略不計(與一般的增長12%相比,CPU只增長了1%到3%)。」github
經過Elena Kirilenko的研究[4],咱們可使用之前的壓縮產物來實現快速高效的Brotli再壓縮。根據Elena的說法,「一旦咱們擁有經過Brotli壓縮的資產,而且咱們嘗試動態壓縮動態內容(其中的內容相似於咱們能夠提早使用的內容),咱們就能夠大大縮短壓縮時間」。例如,提供JavaScript包子集(如部分代碼已在客戶端上緩存或經過WebBundles提供動態包)或者使用基於事前已知模板的動態HTML或動態子集的WOFF2字體。根據Elena的說法,刪除10%的內容時,壓縮率提升了5.3%,壓縮速度提升了39%;刪除50%的內容時,壓縮率提升了3.2%,壓縮率提升了26%。web
策略:使用最高壓縮比配置的Brotli+Gzip 預壓縮靜態資源,並使用 Brotli 配置 4~6 級壓縮比來快速壓縮(動態)HTML。確保服務器正確處理 Brotli 或 gzip 的內容協商頭。算法
設備像素越多,屏幕上顯示內容的細節就越細。api
高分辨率屏幕:圖像資產須要更多的細節。對於位圖來講,它的圖像編碼數據是基於每個像素的,所以,圖像像素越多,文件越大。當咱們將物理屏幕的分辨率增長一倍時,像素的總數增長了四倍:水平像素的兩倍,垂直像素的兩倍。一個「2倍」的屏幕不只僅是雙倍,而是四倍所需的像素數!promise
所以,儘量選擇矢量圖像,由於它們與分辨率無關,老是提供清晰的結果。若是須要位圖,提供響應圖像。瀏覽器
針對圖片的無損壓縮,從高到低:JPEG XL > AVIF >> WebP > JPEG
另外一種由谷歌和Cloudinary開發的自由開放格式。目前未標準化,暫沒有瀏覽器支持。
二、AVIF
一種開放的,免版權法的格式,支持有損和無損壓縮,動畫,有損alpha通道,能夠處理尖銳的線條和純色(這是JPEG的一個問題),同時提供更好的結果。在相同的DSSIM(使用近似人類視覺的算法在兩個或多個圖像之間的類似性(差別))下,能夠節省高達50%的文件大小。與WebP不一樣,AVIF在很大程度上一直優於JPEG。
AVIF甚至比大型svg表現得更好,儘管它固然不該該被視爲svg的替代品。它也是第一個支持HDR顏色支持的圖像格式之一;提供更高的亮度,色位深度和色域。惟一的缺點是,目前AVIF不支持漸進圖像解碼,相似於Brotli,高壓縮率編碼目前至關慢,儘管解碼是快速的。
蘋果公司在Safari 14中添加了對WebP的支持,到今天爲止,全部現代瀏覽器都支持WebP。WebP也不是沒有缺點的,它不支持像JPEG那樣的漸進式渲染,這就是爲何用戶使用好的 JPEG 可能會更快地看到實際圖像,儘管 WebP 圖像的網絡加載速度可能會更快。使用 JPEG,咱們能夠用一半甚至四分之一的時間就提供給「像樣的」用戶體驗,並在稍後加載其他的數據,而不是像 WebP 那樣只有半空的圖像。是否使用WebP取決於你想要的是什麼:使用 WebP,你將減小圖像大小,而使用 JPEG,你將提升圖像的可感知性。另外,WebP並不老是生成比JPEG更小的圖像。
如何選擇?咱們可使用漸進式加強的方式:
固然,若是是背景圖片,咱們可使用image-set作相同的處理
除了圖片格式的問題,針對不一樣的網絡狀況,咱們也應該作相應的優化:爲慢速網絡和低內存設備提供輕體驗,爲快速網絡和高內存設備提供全體驗。
爲此,咱們可使用Client Hints與服務器協商選擇適當的資源填充在頁面上。Client Hints是HTTP請求頭字段,例如DPR, Viewport-Width, Width, Save-Data, Accept(指定圖像格式首選項)等。
咱們還能夠將其與Service Worker結合,Service Worker能夠在請求中添加新的Client Hints Hearders values,重寫URL並將圖像請求指向CDN,根據連通性和用戶偏好調整響應,等等。它不只適用於圖像資產,並且適用於幾乎全部其餘請求。
● 針對JPEG
mozJPEG:可經過控制掃描級別來縮短開始渲染時間
Guetzli:谷歌的開源編碼器,專一於感知性能,並利用Zopfli和WebP的學習成果,惟一的缺點是:處理時間慢(每百萬像素一分鐘的CPU)
● 針對PNG
可使用Pingo
● 針對SVG
可使用SVGO、SVGOMG,若是你須要從網站快速預覽和複製或下載全部SVG資產,可使用svg-grabber
始終值得一提的是保持矢量資產整潔。確保清理未使用的資產,刪除沒必要要的元數據,並減小圖稿中路徑點的數量(從而減小SVG代碼)。
● 其餘工具
Squoosh:以最佳壓縮級別(有損或無損)壓縮,調整大小和處理圖像
使用響應式圖像斷點生成器或Cloudinary或Imgix等服務來自動執行圖像優化。一樣,在許多狀況下,僅使用srcset和size將會得到顯着的好處。
要檢查響應式標記的效率,可使用Imaging-heap,這是一種命令行工具,能夠測量視口大小和設備像素比率之間的效率。
能夠將自動圖像壓縮添加到你的GitHub工做流程中,所以任何圖像都不會影響未壓縮的生產。可對PNG和JPG一塊兒使用mozjpeg和libvips。
Lepton是一種工具和文件格式,可平均無損壓縮JPEG 22%。
若是你想盡早顯示佔位符圖像,可以使用BlurHash。BlurHash將圖像轉換表明該圖像佔位符的短字符串(僅20-30個字符!)。該字符串足夠短,能夠輕鬆地將其添加爲JSON對象中的字段。固然,簡單點,你也可使用純色、漸變色或小圖;若是想要佔位圖更接近於原圖,除了BlurHash,你也可使用SVG。後面咱們會介紹,想先了解的能夠看一下:
LQIP(Low Quality Image Placeholders)[7]
SQIP(a pluggable image converter with vector support)[8]
svg-placeholders[9]
Gradient Image Placeholders[10]
最可靠的方法是混合惰性加載,使用Native Lazy-loading和支持懶加載第三方庫(檢測任何經過用戶交互觸發的可見性變化(使用IntersectionObserver))
● 圖像優化指南[5] ● Maximally optimizing image loading for the web in 2021[6]
是時候該拋棄GIF了,具備昂貴動畫效果的GIF加載會影響渲染性能和帶寬,不如改用動畫 WebP(將 GIF 用做兜底),或將其所有替換爲循環的 HTML5 視頻;與圖像不一樣,瀏覽器不會預加載 <video> 內容,但 HTML5 視頻每每比 GIF 更輕,更小。
若是沒有選擇的狀況下,也可使用有損 GIF,gifsicle或giflossy對 gif 進行有損壓縮以減少圖像大小。
Colin Bendell的測試顯示,在Safari技術預覽中,img標籤內的內聯視頻比GIF標籤至少快20倍,解碼速度快7倍,並且文件大小也只有一小部分。可是,其餘瀏覽器不支持它。
有不少方式能夠將GIF轉化爲MP4,好比:使用FFmpeg[11],你能夠在控制執行下面命令便可:
ffmpeg -i my-animation.gif -b:v 0 -crf 25 -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4
WebM是一種相對較新的文件格式,最初發佈於2010年。它比MP4格式的視頻要小不少,可是瀏覽器支持不是很好,並非全部的瀏覽器都支持。咱們也可使用FFmpeg將GIF轉爲WebM格式:
ffmpeg -i my-animation.gif -c vp9 -b:v 0 -crf 41 my-animation.webm
咱們在使用過程當中,能夠同時提供WebM和MP4,這樣若是瀏覽器不支持WebM,它能夠退回到MP4。
<!-- By Houssein Djirdeh. https://web.dev/replace-gifs-with-videos/ --> <!-- A common scenartio: MP4 with a WEBM fallback. --> <video autoplay loop muted playsinline> <source src="my-animation.webm" type="video/webm"> <source src="my-animation.mp4" type="video/mp4"> </video>
2018 年,開源媒體聯盟發佈了一種新的有前途的視頻格式,稱爲 AV1。AV1 的壓縮與 H.265 編解碼器(H.264 的演進)類似,但與後者不一樣,AV1 是免費的。H.265 許可證的價格迫使瀏覽器供應商改成使用性能相同的 AV1:(就像 H.265 同樣)AV1 壓縮的效果是 WebM 的兩倍。
事實上,蘋果目前使用HEIF格式和HEVC (H.265),最新iOS上的全部照片和視頻都以這些格式保存,而不是JPEG格式。雖然HEIF和HEVC (H.265)尚未適當地暴露在web,AV1是-它正在得到瀏覽器支持。所以,能夠在<video>的source中添加AV1格式的視頻。
若是視頻文件太大,但又想要快速渲染圖片,好比在你的啓動頁面又一個比較大的背景視頻,一種經常使用的技術是首先以靜止圖像的形式顯示第一幀,或者顯示一個通過大量優化的、能夠被解釋爲視頻一部分的短循環片斷,而後,當視頻緩衝足夠時,就開始播放實際的視頻。
若是你想提供響應式的海報圖片,你也能夠藉助第三方庫responsive-video-poster去實現它。
研究代表視頻流的質量會影響觀看者的行爲。事實上,若是啓動延遲超過2秒,觀衆就會開始放棄視頻。超過這一點,1秒的延遲將致使約5.8%的放棄率增長。
一般小屏幕設備沒法處理咱們提供的在電腦上播放的720p和1080p。根據Doug Sillars的說法,咱們能夠建立更小的視頻版本,並使用Javascript爲更小的屏幕檢測源代碼,以確保在這些設備上快速流暢地播放。或者,咱們可使用流媒體視頻。HLS視頻流將向設備發送適當大小的視頻-抽象出爲不一樣屏幕建立不一樣視頻的需求。它還將協商網絡速度,並適應視頻比特率的速度,您正在使用的網絡。
爲了不帶寬上的浪費,咱們只能爲真正可以播放視頻的設備添加視頻源。或者,咱們能夠從視頻標籤中刪除autoplay屬性,並使用JavaScript爲更大的屏幕插入自動播放。此外,咱們須要在視頻中添加preload="none"來告訴瀏覽器不要下載任何視頻文件,直到它真正須要該文件:
<!-- Based on Doug Sillars's post. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ --> <video id="hero-video" preload="none" playsinline muted loop width="1920" height="1080" poster="poster.jpg"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video>
而後咱們能夠針對實際支持AV1的瀏覽器:
<source src="video.av1.mp4" type="video/mp4; codecs=av01.0.05M.08"> <source src="video.hevc.mp4" type="video/mp4; codecs=hevc"> <source src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4">
而後咱們能夠在特定的閾值(例如1000px)上從新添加自動播放:
/* By Doug Sillars. https://dougsillars.com/2020/01/06/hiding-videos-on-the-mbile-web/ */ <script> window.onload = addAutoplay(); var videoLocation = document.getElementById("hero-video"); function addAutoplay() { if(window.innerWidth > 1000){ videoLocation.setAttribute("autoplay",""); }; } </script>
WOFF2 的瀏覽器支持很是好,能夠將 WOFF 做爲不支持 WOFF2 的瀏覽器的兜底字體 - 也能夠用系統字體兜底。
在瞭解若是優化字體以前,有幾個基本的概念你須要掌握:
在font-display未出來以前,大多數瀏覽器都實現了一個超時時間,若是字體下載太慢,超過這段時間後將使用備用字體。這是一種有用的技術,但不幸的是,瀏覽器的實際實現是不一樣的。
Browser | Timeout | Fallback | Swap |
---|---|---|---|
Chrome 35+ | 3 seconds | Yes | Yes |
Opera | 3 seconds | Yes | Yes |
Firefox | 3 seconds | Yes | Yes |
Internet Explorer | 0 seconds | Yes | Yes |
Safari | No timeout | N/A | N/A |
font-display,它是一個css屬性,它決定了一個@font-face 在不一樣的下載時間和可用時間下是如何展現的。
字體顯示時間軸:字體顯示時間線基於一個計時器,該計時器在用戶代理嘗試使用給定下載字體的那一刻開始。時間線分爲三個時間段,在這三個時間段中指定使用字體的元素的渲染行爲。
● 字體阻塞週期:若是未加載字體,任何試圖使用它的元素都必須渲染不可見的後備字體。若是在此期間字體已成功加載,則正常使用它。 ● 字體交換週期:在阻塞週期後當即發生,若是未加載字體,任未嘗試使用它的元素都必須渲染後備字體。若是在此期間字體已成功加載,則正常使用它。 ● 字體失敗週期:在交換週期後當即發生,若是在此週期開始時字體還未加載,則標記爲加載失敗,使用正常的後備字體。不然,字體就會正常使用。
font-display有幾個取值:
● auto:默認,字體顯示策略由用戶代理定義(絕大多數瀏覽器默認使用相似block的方式) ● block:爲字體提供一個短暫的阻塞週期(絕大多少狀況推薦爲3s)和無限的交換週期。換句話說就是,若是字體沒有加載,瀏覽器首先會繪製「不可見」的文本,但一旦加載,就會替換字體面。 ● swap:爲字體提供一個很是小的阻塞週期(一般爲0s)和無限的交換週期。(後備文本當即顯示直到自定義字體加載完成後再使用自定義字體渲染文本)。一般用於比較重要的文案,好比Logo 文案。 ● fallback:爲字體提供一個很是小的阻塞週期和短暫的交換週期(這個能夠說是auto和swap的一種折中方式。須要使用自定義字體渲染的文本會在較短的時間(100ms或更少 according to Google )不可見,若是自定義字體尚未加載結束,那麼就先加載無樣式的文本。一旦自定義字體加載結束,那麼文本就會被正確賦予樣式)。一般用於正文。 ● optional:爲字體提供一個很是小的阻塞週期(一般100ms或更少),而且沒有交換週期(效果和fallback幾乎同樣,都是先在極短的時間內文本不可見,而後再加載無樣式的文本。不過optional選項可讓瀏覽器自由決定是否使用自定義字體,而這個決定很大程度上取決於瀏覽器的鏈接速度。若是速度很慢,那你的自定義字體可能就不會被使用)。
在加載web字體時,瀏覽器默認渲染文字不可見,在現代瀏覽器中,FOIT最多持續3s,當人們說web字體阻塞了資源時,他們極可能是指FOIT。
在加載web字體後,默認使用系統字體做爲渲染文字的備用方案,一般在FOIT超時(3s)後使用。IE與Edge瀏覽器並不會等待,會直接使用備用方案渲染文字。FOUT 比 FOIT更可取,但需注意儘可能減小其迴流影響。
它是一種字體加載策略,首先渲染常規 web字體,當粗體與斜體正在加載時,使用字體合成來渲染粗體與斜體變體。
尤爲是對於中文來講,一個完整的中文字體包至少幾M,但咱們的項目僅使用了其中一部分而已,不必全加載。咱們能夠用字體代工廠將 Web 字體轉換成較小的子集,或者若是您使用的是開源字體,則可使用Glyphhanger或Fontsquirrel對它們進行子集化。您甚至可使用 PeterMüller 的subfont來自動完成整個字體子集化的工做流程,subfont 是一個命令行工具,能夠靜態分析您的頁面以生成最佳的 Web 字體子集,而後將其注入到您的頁面中。
目前可使用的更好的選擇是:預加載關鍵 FOFT[11]and 「compromise」技術[12]。他們兩個都分兩階段渲染來逐步交付 Web 字體-首先須要一個小的超級子集,以便使用 Web 字體快速準確地渲染頁面,而後加載異步家族的其他部分。所不一樣的是,只有在不支持字體加載事件的場景中,「compromise」技術纔會異步加載 polyfill,所以默認狀況下您無需加載 polyfill。
除了這兩種方式,還有其餘的,咱們統一對比一下:
使用preload儘量早的獲取字體資源,但predload 字體須要放在關鍵 CSS 和 JavaScript 的連接以後。
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
注意:它的優缺點很大程序上取決與你如何結合@font-face和font-display使用。
優勢:
● 很是容易實現,一個<link>就能夠了。 ● 比@font-face塊有更好的渲染性能。在加載流中,Web字體被要求更高的優先級。 ● 使用type屬性指定字體格式,對將來友好。在這一點上,仍然有可能(雖然看起來不太可能)web瀏覽器將在WOFF2以前實現預加載,若是沒有這個屬性,您可能會看到一個浪費的請求。因此,確保包含type。 ● 不要包含修改過的字體(使用子集或其餘方式)。
缺點:
● 可伸縮性:預加載的越多,就越阻塞初始渲染。儘可能只使用最重要的一到兩種字體。 ● 靈活性:沒有辦法分組重繪/迴流。 ● 在第三方服務器上可能無法使用。在你請求web字體以前就須要知道標記渲染的URL。例如,Google Fonts,在你向他們的CDN發出的CSS請求中生成這些。
結論:單憑這一點是不夠的。
雖然這不是web字體加載策略,但不得不說它比錯誤的使用web字體好。
優勢:
● 不肯定是否能夠更簡單:只使用font-family沒有@font-face。 ● 接近即時渲染性能:不擔憂FOUT或FOIT。
缺點:
● 可用性有限。不多有系統字體能夠跨平臺使用。檢查fontfamily.io查看系統字體是否爲你的需求提供了可接受的瀏覽器支持。
結論:好,可是也沒什麼值得興奮的。
有2種典型的方式:內聯進<link rel="stylesheet">中或放進<style>中。
優勢:
● 看起來很好的渲染性能:沒有FOUT或FOIT。這是一個很是好的點。 ● 靈活性:沒有FOUT或FOIT,就不須要擔憂重繪/迴流。 ● 健壯性:內聯將全部雞蛋放入初始服務器請求籃子中。
缺點:
● 渲染性能問題:雖然它沒有FOUT,但它顯然延遲了初始渲染時間。另外,單一的一個WOFF2文件可能只有10-15KB左右,內聯它可能會讓你超過HTTP/1的建議14KB或更少。 ● 瀏覽器支持:不利用@font-face塊中逗號分隔的格式列表,這種方法只嵌入了一種格式類型。一般狀況下,這意味着WOFF,所以使用這種方法迫使您在廣泛性(WOFF)和更窄的用戶代理支持、更小的文件大小(WOFF2)之間進行選擇。 ● 糟糕的可伸縮性:請求不會並行發生,連續加載。 ● 自託管:固然是必需的。
結論:只有當你真的不喜歡FOUT時才使用這種方法——不推薦。
使用像loadCSS的工具將全部的字體轉化爲Data URI。
優勢:
● 渲染性能:基本消除了FOIT。 ● 靈活性:易於將請求分組到單個重繪(將多個Data uri放在一個樣式表中)。 ● 輕鬆:不須要任何額外的CSS更改使用。這是一個很大的好處,但不是萬能的。 ● 健壯:若是異步請求失敗,將繼續顯示回退文本。
缺點:
● 渲染性能:在解析樣式表和Data uri時,具備很是明顯但很短的FOIT。 ● 靈活性和可伸縮性:分組請求和重繪是耦合在一塊兒的。若是將多個Data uri組合在一塊兒(這將致使串行加載而不是並行加載),它們將一塊兒從新繪製。使用此方法,不能並行加載並重繪。 ● 維護不友好:要求你有本身的方法來肯定字體格式支持,在獲取Data URI樣式表以前,你的JavaScript加載器須要肯定支持哪一種字體格式(WOFF2或WOFF)。這意味着若是出現了一種新的字體格式,你須要爲它開發一個功能測試。 ● 瀏覽器支持:你能夠繞過對加載器步驟的維護和對WOFF2或WOFF的硬代碼,但這將致使沒必要要的請求或潛在的丟棄請求(這與咱們討論內聯數據uri的缺點相同)。 ● 自我託管:必需的。
結論:還好,但咱們能夠作得更好。
使用帶有polyfill的css字體加載API來檢測特定的字體什麼時候已經加載,而且只有在它成功加載後才應用該web字體在你的CSS中。一般這意味着在元素上切換一個類。使用SASS或LESS mixins更容易維護。
// demo:https://www.zachleat.com/web-fonts/demos/fout-with-class-polyfill.html <style> @font-face { font-family: Lato; src: url('font-lato/lato-regular-webfont.woff2') format('woff2'), url('font-lato/lato-regular-webfont.woff') format('woff'); } @font-face { font-family: LatoBold; src: url('font-lato/lato-bold-webfont.woff2') format('woff2'), url('font-lato/lato-bold-webfont.woff') format('woff'); font-weight: 700; } body { font-family: sans-serif; } .fonts-loaded body { font-family: Lato, sans-serif; } .fonts-loaded h1, .fonts-loaded strong { font-family: LatoBold, sans-serif; font-weight: 700; } </style> <script> (function() { // Optimization for Repeat Views if( sessionStorage.fontsLoadedFoutWithClassPolyfill ) { document.documentElement.className += " fonts-loaded"; return; } /* Font Face Observer v2.0.13 - © Bram Stein. License: BSD-3-Clause */ // 此處省略 var fontA = new FontFaceObserver('Lato'); var fontB = new FontFaceObserver('LatoBold', { weight: 700 }); Promise.all([ fontA.load(null, 10000), fontB.load(null, 10000), ]).then(function () { document.documentElement.className += " fonts-loaded"; // Optimization for Repeat Views sessionStorage.fontsLoadedFoutWithClassPolyfill = true; }); })(); </script>
優勢:
● 渲染性能:消除了FOIT。這種方法通過了試驗和測試,是TypeKit推薦的方法之一。 ● 靈活性:很容易將請求分組到一個從新繪製(使用一個類用於多個web字體加載)。 ● 可伸縮性:請求是並行發生的。 ● 健壯:若是請求失敗,回退文本仍然顯示。 ● 託管:獨立於字體加載器的工做(很容易經過第三方主機或現有的@font-face塊實現)。 ● 強大的瀏覽器支持,polyfill一般能夠在任何支持web字體的地方工做。 ● 將來友好:polyfill不耦合到字體格式,應該與現有的@font-face塊工做。這意味着當新格式出現時,你能夠像日常同樣改變你的@font-face。 ● 不須要修改字體(經過子設置或其餘方式)。
缺點:
● 須要嚴格維護/控制CSS。在CSS中單一使用web字體font-family而不使用Loaded類可能會觸發FOIT。 ● 一般須要你硬編碼哪些web字體你想在頁面上加載。這可能意味着你最終會加載比頁面須要的更多的web字體內容。記住,若是使用@font-face,更新的瀏覽器只下載在你的頁面上實際使用的web字體。這是免費給你的。這就是爲何《紐約時報》能夠在其主頁上避開100種不一樣的@font-face字體阻塞——瀏覽器只下載其中的一小部分。使用這種方法,您必須告訴瀏覽器下載哪些字體,而不依賴於使用。
結論:這是基線標準。適用於大多數用例。
該方法是基於上一種方法作了些許改變,當你加載同一個字體的多維度或多樣式的時候這很是有用,好比:常規、加粗、傾斜、加粗+傾斜等等。該方法主要是將這些web字體分爲兩個階段加載,先加載常規體,而後渲染假粗體和假斜體內容(使用字體合成),而真正的web字體的權重和替代樣式正在加載。
// demo: https://www.zachleat.com/web-fonts/demos/foft.html // 基於上一個方式,修改了部份內容,下面僅修改的部分 <style> body { font-family: sans-serif; } .fonts-loaded-1 body { font-family: LatoInitial; } .fonts-loaded-2 body { font-family: Lato; } </style> <script> (function() { if( "fonts" in document ) { // Optimization for Repeat Views if( sessionStorage.fontsLoadedFoft ) { document.documentElement.className += " fonts-loaded-2"; return; } document.fonts.load("1em LatoInitial").then(function () { document.documentElement.className += " fonts-loaded-1"; Promise.all([ document.fonts.load("400 1em Lato"), document.fonts.load("700 1em Lato"), document.fonts.load("italic 1em Lato"), document.fonts.load("italic 700 1em Lato") ]).then(function () { document.documentElement.className += " fonts-loaded-2"; // Optimization for Repeat Views sessionStorage.fontsLoadedFoft = true; }); }); } })(); </script>
優勢:
● 擁有上一種方式的全部優勢。 ● 渲染性能:極大地減小了網頁字體加載時發生的內容跳躍量。考慮到咱們將網頁字體加載分爲兩個階段,這使得第一個階段(常規字體,這將致使最多的迴流)比咱們將全部字體組合在一塊兒進行一次重繪要快得多。
缺點:
● 擁有上一種方式的全部缺點。 ● 有些設計師對字體合成很是敏感。客觀地說,合成的變體不如真正的變體有用,但這不是一個公平的比較。請記住,合成版本只是一個臨時佔位符,咱們須要問的問題是:它們比後退字體更有用仍是更沒用?更有用。
結論:適合那些對額外性能感興趣的,但不能與關鍵FOFT相比。
這與標準的FOFT的區別就是它不像標準FOFT那樣在第一階段加載所有的常規字體,它僅加載其子集(一般只包含A-Z和可選的0-9和/或標點)。完整的常規web字體會在第二階段與其餘權重和樣式一塊兒加載。
// demo: https://www.zachleat.com/web-fonts/demos/critical-foft-polyfill.html
優勢:
● 有FOFT的全部優勢。 ● 渲染性能:第一階段的加載速度更快(在較慢的鏈接上更明顯),進一步減小了第一階段網頁字體重繪的時間,使你最經常使用的網頁字體迴流發生得更快而不是更晚。
缺點:
● 有FOFT的全部缺點。 ● 第一階段加載的常規字體子集與第二階段加載整個常規字體重複加載了,引入了少許的開銷,這是咱們爲減小回流而付出的代價。 ● 許可限制:須要子集。
結論:使用下面的一個改進的關鍵FOFT變體。
第一階段加載子集的方式改成轉成data url 的形式進行加載。雖然這會阻塞初始渲染時間,可是咱們僅植入了很小的子集,與消除了大部分的FOUT相比這個代價很小。
// demo:https://www.zachleat.com/web-fonts/demos/critical-foft-preload-polyfill.html
優勢:
● 有關鍵FOFT的全部優勢。 ● 爲常規字體消除FOIT和大大減小FOUT。當加載其餘權重和樣式時,第二階段加載的其餘字符會出現一個小回流,但影響要小得多。
缺點:
● 有關鍵FOFT的全部缺點。 ● 小的內聯Data URI將略微阻塞初始渲染時間,咱們用這個來換取高度減小的FOUT。 ● 自我託管:必需的。
結論:在瀏覽器還不徹底支持preload時,這是黃金標準。
第一階段的常規字體子集使用Preload的方式進行加載。
優勢:
● 有關鍵FOFT的全部優勢。 ● 渲染性能:與以前的方式相比下載的優先級更高,它比上一種方式以Data URI的方式內嵌更好,由於它能夠利用請求緩存,而不是每次請求都要去獲取相同的web字體數據。
缺點:
● 有關鍵FOFT的全部缺點。 ● 只使用單一的web字體格式。 ● preload會略微延遲初始渲染時間。 ● 自託管:可能須要。
結論:目前的黃金標準。
@font-face { font-family: Open Sans; src: local('Open Sans Regular'), local('OpenSans-Regular'), url('opensans.woff2') format ('woff2'), url('opensans.woff') format('woff'); }
就算本地字體名稱能夠匹配web字體名字,但不能保證它兩是同一個字體,事實上,大多數狀況不是。由於手機上的字體可能只是字體的一個子集,用戶能夠修改字體如line-height等,表現會有所不一樣,有些字體可能仍是以其餘字體代替,還有可能字體由於版本的問題而不一樣,因此不推薦使用local字體。除了Android請求Roboto,Google字體對全部用戶禁止使用local()。
自從Chrome v86(發佈於2020年10月),跨站點的資源,如字體不能共享在同一個CDN -因爲分區瀏覽器緩存,這是Safari多年來的默認行爲。沒有了跨站點資源共享緩存的優點。
當全部的請求都來自同一個域,而且鏈接在同一個HTTP/2上時,它們能夠相互調度。關鍵資源(如CSS和字體)能夠在隊列中向前推,並在低優先級資源(如圖像)以前交付。
因爲谷歌字體(以及大多數第三方資源)是從與主頁資源不一樣的領域提供的,所以不能對它們進行優先排序,並最終相互競爭下載帶寬。這可能致使實際獲取時間比最佳狀況下的8次往返要長得多。
若是作不到自託管,也可使用代理的方式將其代理到你的域名下:將字體請求url的域名改成html的域名,利用Service worker攔截,請求真正的連接。
要測量 Web 字體加載性能,請考慮全部文本可見時間(全部字體均已加載且全部內容均以 Web 字體顯示的時刻)、變爲真實斜體的時間以及首次渲染後的Web字體迴流數。
總的來講,(安全)的網絡字體加載策略就是:將字體子集化並在第二階段渲染作好準備,使用 font-display 描述符聲明它們,使用字體加載 API 對重繪進行分組,並將字體存儲在持久的 service worker 緩存中。第一次訪問時,在阻塞的外部腳本以前插入腳本預加載字體。
參考資料
Front-End Performance Checklist 2021[1]:https://www.smashingmagazine....
前端性能優化(一):準備工做[2]:https://mp.weixin.qq.com/s/QD...
Brotli compression using a reduced dictionary[3]:https://blog.cloudflare.com/b...
Fast and efficient recompression using previous compression artifacts[4]:https://dev.to/riknelix/fast-...
圖像優化指南[5]:https://images.guide/
Maximally optimizing image loading for the web in 2021[6]:https://www.industrialempathy...
LQIP(Low Quality Image Placeholders)[7]:https://www.guypo.com/introdu...
SQIP(a pluggable image converter with vector support)[8]:https://github.com/axe312ger/...
svg-placeholders[9]:https://jmperezperez.com/svg-...
Gradient Image Placeholders[10]:https://calendar.perfplanet.c...
exact instructions for FFmpeg[11]:https://medium.com/@borisscha...
Critical FOFT with preload[12]:https://www.zachleat.com/web/...
"The Compromise" method:https://www.zachleat.com/web/...