完整的 WebFont 包含所有風格變化 (您可能不需要),以及所有可能未使用的字形,因此很容易導致下載檔案大小達到數 MB。本文將說明如何最佳化 Web Fonts 的載入作業,讓訪客只下載所需的字型。
為解決包含所有變體的大檔案問題,@font-face
CSS 規則是專門設計用來將字型系列拆分為資源集合。例如:萬國碼子集和不同的樣式變體。
有了這些宣告,瀏覽器就能找出所需的子集和變體,並下載轉譯文字所需的最小集合,非常方便。不過,如果您不小心,也會在關鍵算繪路徑中造成效能瓶頸,並延遲文字算繪作業。
預設行為
延後載入字型會帶來一個重要的隱含影響,可能會延遲文字算繪作業。瀏覽器必須先建構轉譯樹狀結構 (取決於 DOM 和 CSSOM 樹狀結構),才能知道需要哪些字型資源來轉譯文字。因此,字型要求會在其他重要資源之後延遲,瀏覽器可能會在擷取資源前,就停止轉譯文字。
- 瀏覽器要求 HTML 文件。
- 瀏覽器開始剖析 HTML 回應並建構 DOM。
- 瀏覽器會找出 CSS、JS 和其他資源,並調度要求。
- 瀏覽器會在收到所有 CSS 內容後建構 CSSOM,並將其與 DOM 樹狀結構結合,以建構算繪樹狀結構。
- 轉譯樹狀結構指出需要哪些字型變化才能在網頁上轉譯指定文字後,系統就會調度字型要求。
- 瀏覽器會執行版面配置,並將內容繪製至螢幕。
- 如果尚未提供字型,瀏覽器可能不會轉譯任何文字像素。
- 字型可供使用後,瀏覽器就會繪製文字像素。
網頁內容的首次著色作業之間的「競爭」,可在轉譯樹建構後不久完成,而字型資源的要求會造成「空白文字問題」,在這種情況下,瀏覽器可能會轉譯網頁版面配置,但省略任何文字。
預先載入 Web 字型,並使用 font-display
控制瀏覽器在無法使用的字型下如何運作,即可避免因字型載入而導致空白頁面和版面配置位移。
預先載入 WebFont 資源
如果您的網頁很可能需要在您事先知道的網址中代管特定 WebFont,您可以利用資源優先順序。使用 <link rel="preload">
會在關鍵算繪路徑的早期觸發對 WebFont 的請求,不必等待 CSSOM 建立。
自訂文字轉譯延遲時間
雖然預先載入可讓網頁內容顯示時更有可能使用 WebFont,但無法保證一定可行。您仍需考量瀏覽器在轉譯使用尚未提供的 font-family
的文字時的行為。
在「避免在字型載入期間顯示不可見的文字」一文中,您可以看到預設瀏覽器的行為不一致。不過,您可以使用 font-display
,告知新式瀏覽器您希望的行為。
與部分瀏覽器實作的現有字型逾時行為類似,font-display
將字型下載的生命週期分為三個主要期間:
- 第一個逗號是字型區塊的逗號。在此期間,如果未載入字型面,則任何嘗試使用該字型的元素,都必須以不可見的備用字型面顯示。如果字型面在封鎖期間成功載入,系統就會正常使用字型面。
- 字型換換期會在字型封鎖期結束後立即開始。在此期間,如果未載入字型面,則任何嘗試使用該字型的元素都必須改為使用備用字型面進行轉譯。如果字型在切換期間成功載入,系統就會正常使用該字型。
- 字型換換期間結束後,系統會立即進入字型失敗期間。如果字型面在這個期間開始時尚未載入,系統會將其標示為載入失敗,導致正常的字型備用機制。否則,系統會正常使用字型。
瞭解這些時間長度後,您就可以使用 font-display
決定字型應如何顯示,這取決於字型是否已下載,以及下載時間。
如要使用 font-display
屬性,請將其新增至 @font-face
規則:
@font-face {
font-family: 'Awesome Font';
font-style: normal;
font-weight: 400;
font-display: auto; /* or block, swap, fallback, optional */
src: local('Awesome Font'),
url('/fonts/awesome-l.woff2') format('woff2'), /* will be preloaded */
url('/fonts/awesome-l.woff') format('woff'),
url('/fonts/awesome-l.ttf') format('truetype'),
url('/fonts/awesome-l.eot') format('embedded-opentype');
unicode-range: U+000-5FF; /* Latin glyphs */
}
font-display
目前支援下列值範圍:
auto
block
swap
fallback
optional
如要進一步瞭解如何預先載入字型和 font-display
屬性,請參閱下列文章:
字型載入 API
<link rel="preload">
和 CSS font-display
搭配使用時,可讓您大幅控管字型載入和算繪作業,且不會增加太多額外負擔。不過,如果您需要額外自訂功能,且願意承擔執行 JavaScript 所帶來的額外負擔,還有另一個選項。
字型載入 API 提供指令碼介面,可定義及操作 CSS 字型面,追蹤下載進度,並覆寫預設的延遲載入行為。舉例來說,如果您確定需要特定字型變化版本,可以定義該版本,並告知瀏覽器立即擷取字型資源:
var font = new FontFace("Awesome Font", "url(/fonts/awesome.woff2)", {
style: 'normal', unicodeRange: 'U+000-5FF', weight: '400'
});
// don't wait for the render tree, initiate an immediate fetch!
font.load().then(function() {
// apply the font (which may re-render text and cause a page reflow)
// after the font has finished downloading
document.fonts.add(font);
document.body.style.fontFamily = "Awesome Font, serif";
// OR... by default the content is hidden,
// and it's rendered after the font is available
var content = document.getElementById("content");
content.style.visibility = "visible";
// OR... apply your own render strategy here...
});
此外,由於您可以透過 check()
方法查看字型狀態並追蹤下載進度,因此也可以定義在網頁上顯示文字的自訂策略:
- 您可以暫停所有文字轉譯作業,直到字型可供使用為止。
- 您可以為每個字型實作自訂逾時時間。
- 您可以使用備用字型來解除封鎖的轉譯作業,並在字型可用後插入使用所需字型的新樣式。
更棒的是,您還可以根據網頁上的不同內容,搭配使用上述策略。舉例來說,您可以延遲部分區段的文字算繪作業,直到字型可用為止,然後使用備用字型,並在字型下載完成後重新算繪。
必須妥善快取
字型資源通常是不會經常更新的靜態資源。因此,這些資源非常適合用於長時間到期。請務必為所有字型資源指定條件式 ETag 標頭和最佳 Cache-Control 政策。
如果您的網頁應用程式使用服務工作者,則在大多數用途下,使用快取優先策略提供字型資源都相當合適。
請勿使用 localStorage
或 IndexedDB 儲存字型,因為這兩者都存在各自的效能問題。瀏覽器的 HTTP 快取提供最佳且最可靠的機制,可將字型資源提供給瀏覽器。
WebFont 載入檢查清單
- 使用
<link rel="preload">
、font-display
或字型載入 API 自訂字型載入和轉譯:預設的延遲載入行為可能會導致文字轉譯延遲。這些網路平台功能可讓您針對特定字型覆寫這項行為,並為網頁上的不同內容指定自訂轉譯和逾時策略。 - 指定重新驗證和最佳快取政策:字型是靜態資源,更新頻率不高。請確認您的伺服器提供長效的最大年齡時間戳記和重新驗證權杖,以便在不同網頁之間有效重複使用字型。如果使用服務工作站,則適合採用快取優先策略。
使用 Lighthouse 自動測試 WebFont 載入行為
Lighthouse 可協助自動化這項程序,確保您遵循網路字型最佳化最佳做法。
您可以透過下列稽核作業,確保網頁持續遵循網路字型最佳化最佳做法: