字型的最佳做法

根據網站體驗核心指標,最佳化網站字型。

Katie Hempenius
Katie Hempenius

本文將探討字型的效能最佳做法。網頁字型會透過多種方式影響效能:

本文將細分為三個部分:字型載入字型提供字型轉譯。每個部分都會說明字型生命週期的特定部分運作方式,並提供對應的最佳做法。

正在載入字型

字型通常是重要的資源,因為如果沒有字型,使用者可能無法檢視網頁內容。因此,載入字型的最佳做法通常都集中在盡可能及早載入字型。請特別留意從第三方網站載入的字型,因為下載這些字型檔案需要單獨設定。

如果不確定頁面字型是否即時要求,請查看 Chrome 開發人員工具「網路」面板中的「時間」分頁,取得更多資訊。

開發人員工具中的「時間」分頁螢幕截圖

瞭解 @font-face

在深入探討字型載入的最佳做法之前,請務必先瞭解 @font-face 的運作方式,以及這會對字型載入造成哪些影響。

@font-face 宣告是任何網站字型不可或缺的一環。該程式至少會宣告用於參照字型的名稱,並指出對應字型檔案的位置。

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
}

常見的誤解是,在遇到 @font-face 宣告時會要求字型,但這並非如此。@font-face 宣告本身不會觸發字型下載。而是只有在網頁使用樣式參照字型時,才會下載該字型。範例如下:

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
}

h1 {
  font-family: "Open Sans"
}

也就是說,在上述範例中,只有在網頁包含 <h1> 元素時,系統才會下載 Open Sans

因此,考慮最佳化字型時,請務必根據字型檔案本身一樣的考量因素來進行樣式表。變更樣式表的內容或提供方式可能會對字型抵達時間產生重大影響。同樣地,移除未使用的 CSS 和分割樣式表也可以減少網頁載入的字型數量。

內嵌字型宣告

大多數網站都能在主要文件的 <head> 中內嵌字型宣告和其他重要樣式,而不必將樣式放入外部樣式表。如此一來,瀏覽器不需要等待外部樣式表完成下載,瀏覽器就能更快找到字型宣告。

<head>
  <style>
    @font-face {
        font-family: "Open Sans";
        src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
    }

    body {
        font-family: "Open Sans";
    }

    ...etc.

  </style>
</head>

內嵌重要的 CSS 是一種更先進的技術,並非所有網站都能達成。這麼做的優點顯而易見,但需要額外的程序和建構工具,確保必要的 CSS (尤其是關鍵的 CSS) 能正確內嵌,且任何其他 CSS 都能以非算繪的方式放送。

預先連線至重要的第三方來源

如果你的網站會載入第三方網站的字型,我們強烈建議你使用 preconnect 資源提示,提早與第三方來源建立連線。資源提示應放在文件的 <head> 中。以下的資源提示會設定連線,以便載入字型樣式表。

<head>
  <link rel="preconnect" href="https://fonts.com">
</head>

如要預先連結用於下載字型檔案的連線,請另外新增使用 crossorigin 屬性的 preconnect 資源提示。與樣式表不同,字型檔案必須透過 CORS 連線傳送。

<head>
  <link rel="preconnect" href="https://fonts.com">
  <link rel="preconnect" href="https://fonts.com" crossorigin>
</head>

使用 preconnect 資源提示時,請記得字型供應程式可能會從不同來源提供樣式表和字型。例如,這是 Google Fonts 使用 preconnect 資源提示的方式。

<head>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
</head>

使用 preload 載入字型時請小心謹慎

雖然 preload 非常有效讓使用者在頁面載入程序的早期發現字型很有效,但這卻會導致瀏覽器資源載入其他資源的代價。

內嵌字型宣告和調整樣式表可能是更有效率的做法。之所以做出這些調整,是為瞭解決日後發現字型的根本原因,而不只是提供解決方法。

此外,使用 preload 做為字型載入策略時,也請謹慎使用,因為這個策略略過瀏覽器內建的某些內容協商策略。舉例來說,preload 會忽略 unicode-range 宣告,而如果以謹慎的方式使用,只應用於載入單一字型格式。

不過,使用外部樣式表時,由於瀏覽器要等到稍後才會判斷是否需要字型,因此預先載入最重要的字型會非常有效。

字型放送

字型傳送速度越快,文字算繪速度就越快。此外,如果字型提前顯示時間夠早,就能避免因切換字型而造成版面配置位移。

使用自行託管的字型

以紙上來說,使用自行管理的字型應該能省去第三方連線設定程序,進而提高成效。然而,實務上,這兩種選項的成效差異比較不明顯:舉例來說,Web Almanac 發現使用第三方字型的網站顯示速度比使用第一方字型的字型更快。

如果你考慮使用自行代管的字型,請確認網站使用的是內容傳遞網路 (CDN)HTTP/2。如果沒有使用這些技術,自行代管的字型就不太可能獲得更好的效能。詳情請參閱內容傳遞網路

如果您使用自行管理的字型,建議您一併套用第三方字型提供者一般提供的部分字型檔案最佳化作業,例如字型子設定和 WOFF2 壓縮功能。套用這些最佳化措施所需的時間,取決於網站支援的語言。請特別注意,針對 CJK 語言最佳化字型並不容易。

使用 WOFF2

在最先進的字型字型中,WOFF2 是最新的字型、支援最廣泛的瀏覽器,並提供最佳壓縮效果。因為使用 Brotli,WOFF2 的壓縮比 WOFF 好 30%,使得下載的數據量減少,從而提升效能。

在瀏覽器支援的情況下,專家現在建議僅使用 WOFF2:

事實上,我們認為就是這樣一個時候,只使用 WOFF2,就可以忘記所有事情。

這樣做可以大幅簡化 CSS 和工作流程,同時避免使用者意外下載重複或錯誤的字型。現在所有地方都支援 WOFF2。因此,除非需要支援非常舊的瀏覽器,否則只要使用 WOFF2。如果無法找到,請考慮不要向這些舊版瀏覽器提供任何網路字型。如果您具備完善的備用策略,則不需要擔心。使用舊版瀏覽器的訪客只會看到備用字型。

Bram Stein,2022 年出品《Web Almanac》

部分字型

字型檔案通常會包含大量字符,供支援的各種字元使用。不過,您可能不需要網頁的所有字元,且可透過子設定字型縮減字型檔案的大小。

@font-face 宣告中的 unicode-range 描述元可向瀏覽器指出字型可使用哪些字元。

@font-face {
    font-family: "Open Sans";
    src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
    unicode-range: U+0025-00FF;
}

如果網頁含有一或多個符合萬國碼 (Unicode) 範圍的字元,系統就會下載字型檔案。unicode-range 常用於根據網頁內容所使用的語言提供不同的字型檔案。

unicode-range 通常與子設定技術搭配使用。部分字型包含原始字型檔案中的一小部分字符,舉例來說,網站可能只針對拉丁和斯拉夫字元分別產生部分字型,而不是向所有使用者提供所有字元。每個字型的字符數量幾乎不一:拉丁字型通常佔字型 100 到 1000 字符的規模;CJK 字型則可超過 10,000 個字元。移除未使用的字符可大幅縮減字型的檔案大小。

部分字型供應程式可能會自動提供具有不同子集的不同字型檔案版本。舉例來說,Google Fonts 預設會執行以下操作:

/* devanagari */
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJbecnFHGPezSQ.woff2) format('woff2');
  unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJnecnFHGPezSQ.woff2) format('woff2');
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJfecnFHGPc.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

遷移至自行代管時,這項最佳化功能很容易遭到忽略,且本機會產生較大的字型檔案。

如果字型供應程式允許的話,您也可以透過 API (Google Fonts 支援這項字型,提供 text 參數) 或手動編輯字型檔案,再自行代管,也可以手動進行字型子集。產生字型子集的工具包含 subfontglyphanger。不過,請務必檢查您允許子設定使用的字型授權和自我代管。

減少使用的網頁字型

用於提供最快字型的字型,在一開始沒有請求。系統字型和可變字型有兩種方法,可能會減少網站使用的網頁字型數量。

系統字型是使用者裝置使用者介面使用的預設字型。系統字型通常會依作業系統和版本而有所不同。由於已經安裝此字型,所以無需下載此字型。系統字型特別適合用於內文使用。

如要在 CSS 中使用系統字型,請將 system-ui 列為字型系列:

font-family: system-ui

變數字型的概念是單一變數字型可用來取代多個字型檔案。變數字型的運作方式是定義「預設」字型樣式,並提供「axes」操控字型。舉例來說,使用 Weight 軸的變數字型就可實作字母,之後需要分別選用淺色、一般、粗體和額外粗體字型。

有些人可能因為改用可變字型而受益。變數字型包含許多樣式,因此檔案大小通常比僅包含一種樣式的個別非變數字型還要大。使用可變字型可大幅改善成效的網站,是指使用 (且需使用) 多種字型樣式和粗細的網站。

字型顯示

當瀏覽器面臨尚未載入的網頁字型時,瀏覽器會出現一個兩難的難關:在網頁字型產生之前,瀏覽器是否應暫停轉譯文字?還是應該在網站字型送達前,以備用字型呈現文字?

不同的瀏覽器處理這種情況的方式不盡相同。根據預設,Chromium 和 Firefox 瀏覽器在未載入相關網路字型時,會封鎖文字轉譯長達 3 秒;Safari 會無限期封鎖文字顯示。

您可以使用 font-display 屬性設定此行為。這個選項可能會有重大影響:font-display 可能會影響 LCP、FCP 和版面配置穩定性。

選擇合適的font-display策略

font-display 會通知瀏覽器在關聯網路字型未載入時,應如何繼續轉譯文字。會依字型介面定義。

@font-face {
  font-family: Roboto, Sans-Serif
  src: url(/fonts/roboto.woff) format('woff'),
  font-display: swap;
}

font-display 有五個可能的值:

封鎖期間 交換週期
自動 因瀏覽器而異 因瀏覽器而異
阻擋 2 到 3 秒 無限
交換 0 毫秒 無限
備用 100 毫秒 3 秒
選用 100 毫秒
  • 封鎖時段:封鎖期從瀏覽器要求網路字型時開始。在這段封鎖期間,如果無法使用網路字型,系統會以「隱藏」備用字型顯示該字型,導致使用者看不到這類文字。如果封鎖期間結束時無法使用字型,則會以備用字型顯示。
  • 替換週期:替換期晚於封鎖期。在替換期間可使用網頁字型時,則會遭到「切換」。

font-display 策略反映了效能和外觀優缺點的不同觀點。因此很難採用建議方法,因為這取決於個人偏好、網頁字型對網頁和品牌的重要性,以及切換時該字型多麼不穩定。

就大多數網站而言,下列三大策略最適合用:

  • 如果效能是首要考量:請使用 font-display: optional。這是最「效能」的做法:文字顯示會延遲最多 100 毫秒,而且可以保證不會有任何與字型切換相關的版面配置位移。不過,如果網頁字型遲到,請不要使用網路字型。

  • 如果快速顯示文字是首要考量,但您仍希望確保使用網站字型:請使用 font-display: swap,但務必要及早提供字型,避免版面配置位移。這個選項的缺點是字型延遲送達時,會出現不流暢的轉折。

  • 如果確保網頁字型顯示文字是首要之務:請使用 font-display: block,但務必要及早提供字型,讓文字延遲時間降到最低。但缺點是初始顯示的文字會延遲顯示。請注意,雖然這種 deplay 功能,但由於實際繪製的文字無法被繪製,因此仍然會造成版面配置位移,因此系統會使用備用字型空間保留空間。網頁字型載入後,可能需要不同空間,因此可以變更。不過,這可能會比 font-display: swap 更不流暢,因為文字本身不會出現偏移。

提醒你,這兩種方法可以合併使用:例如,使用 font-display: swap 傳達品牌宣傳元素和其他搶眼的網頁元素;針對內文中使用的字型,請使用 font-display: optional

減少備用字型與網頁字型之間的轉換

如要降低 CLS 的影響,您可以使用新的 size-adjust 屬性。詳情請參閱 CSS size-adjust 相關文章。這是工具組新增的功能,因此我們目前較先進,還有一些手冊。不過,請務必試用看看,日後工具才能改善這些工具!

結論

網站字型仍然存在效能瓶頸,但我們擁有各式各樣的選項,方便我們盡可能加以最佳化,以減少瓶頸。