改善備用字型

凱蒂漢普尼斯
Katie Hempenius

摘要

本文將深入介紹字型備用廣告,以及 size-adjustascent-overridedescent-overrideline-gap-override API。這些 API 可讓您使用本機字型建立備用字型,且字型與網頁字型的大小高度相符或完全一致。這樣可以減少或排除字型替換造成的版面配置位移。

若您不想閱讀本文,可以利用以下工具立即開始使用這些 API:

架構工具:

  • @next/font:自 Next 13 起,next/font 會自動使用字型指標覆寫設定和 size-adjust 以提供相符的字型備用項。
  • @nuxtjs/fontaine:從 Nuxt 3 開始,您可以使用 nuxt/fontaine 自動產生相符的字型備用項,然後插入 Nuxt 應用程式使用的樣式表。

非架構工具:

  • Fontaine:Fontaine 是一種程式庫,會自動產生並插入使用字型指標覆寫的字型備用內容。
  • 這個存放區包含 Google Fonts 代管所有字型的字型指標覆寫值。您可以將這些值複製並貼到樣式表中。

背景

備用字型是指尚未載入主要字型,或缺少轉譯網頁內容所需的字符時,所使用的字型。舉例來說,以下 CSS 表示應使用 sans-serif 字型系列做為 "Roboto" 的字型備用。

font-family: "Roboto" , sans-serif;

備用字型可用來加快顯示文字的速度 (也就是使用 font-display: swap)。因此,網頁內容在容易理解且更加實用,但過去,這會造成版面配置不穩定,導致版面配置位移,通常是因為網站字型替換掉備用字型時發生。但以下所討論的新 API 可以減少或消除此問題,方法是建立備用字型,而該錶面佔用與網頁字型對應空間相同的空間。

改良的字型備用廣告功能

產生「改良版」字型備用廣告的方法有兩種。更簡單的做法只會使用字型指標覆寫 API。較複雜 (但更強大) 的做法同時使用字型指標覆寫 API 和 size-adjust。本文將說明這兩種方法。

字型指標覆寫的運作方式

引言

字型指標覆寫功能可覆寫字型的氣味、下降和行距:

  • Ascent:計算字型字符超過基準線的最遠距離。
  • 「離子」是指測量字型字符下方與基準線最下方的距離。
  • 行距 (又稱為「導引線」) 可用於測量連續行文字之間的距離。

顯示字型往上、下降和線條間距的圖表。

字型指標覆寫功能可用來覆寫備用廣告字型的風速、下降和行距間距,以便與網路字型的上升、下降和行距相等。因此,網站字型和調整後的備用字型一律會具有相同的垂直尺寸。

字型指標覆寫功能用於樣式表中,如下所示:

body {
    font-family: Poppins, "fallback for poppins";
}

@font-face {
    font-family: "fallback for poppins";
    src: local("Times New Roman");
    ascent-override: 105%;
    descent-override: 35%;
    line-gap-override: 10%;
}

本文開頭列出的工具可產生正確的字型指標覆寫值。不過,您也可以自行計算這些值。

正在計算字型指標覆寫值

以下方程式會產生指定網路字型的字型指標覆寫。字型指標覆寫的值應以百分比 (例如 105%) 寫入,而非小數。

ascent-override = ascent/unitsPerEm
descent-override = descent/unitsPerEm
line-gap-override = line-gap/unitsPerEm

以下為 Poppins 字型的字型指標覆寫範例:

/*
Poppins font metrics:
ascent = 1050
descent = 350
line-gap = 100
UPM: 1000
*/

ascent-override: 105%;  /* = 1050/1000 */
descent-override: 35%;  /* = 350/1000 */
line-gap-override: 10%; /* = 100/1000 */

ascentdescentline-gapunitsPerEm 的值都來自網路字型的中繼資料。本文下一節將說明如何取得這些值。

讀取字型表

字型的中繼資料 (特別是「字型表」) 包含計算字型指標覆寫值所需的所有資訊。

FontForge「Font Information」對話方塊的螢幕截圖。對話方塊會顯示字型指標,例如「Typo Ascent」、「Typo Descent」和「Typo Line Gap」。
使用 FontForge 查看字型中繼資料

您可以使用以下工具讀取字型中繼資料:

  • fontkit 是專為 Node.js 打造的字型引擎。此程式碼片段說明如何使用 fontkit 計算字型指標覆寫。
  • Capsize 是字型大小和版面配置程式庫。Capsize 提供一個 API,可用於取得各種字型指標的相關資訊。
  • fontdrop.info 網站可讓您從瀏覽器查看字型表格和其他字型相關資訊。
  • Font Forge 是熱門的電腦字型編輯器。查看 ascentdescentline-gap:開啟 Font Info 對話方塊,選取 OS/2 選單,然後選取 Metrics 分頁標籤。查看 UPM:開啟 Font Info 對話方塊,然後選取 General 選單。

瞭解字型表

您可能會注意到,多個指標都指稱「遞增」等概念,例如 hheaAscenttypoAscentwinAscent 指標。這是因為不同作業系統採用不同的字型轉譯方法所致:OSX 裝置上的程式通常會使用 hhea* 字型指標,Windows 裝置上的程式通常會使用 typo* (也稱為 sTypo*) 或 win* 字型指標。

視字型、瀏覽器和作業系統而定,系統會使用 hheatypowin 指標來算繪字型。

Mac Windows
Chromium 使用「hhea」資料表中的指標。 如果已設定「USE_TYPO_METRICS」,請使用「typo」資料表中的指標;否則使用「win」資料表的指標。
Firefox 如果已設定「USE_TYPO_METRICS」,系統就會使用「typo」資料表中的指標,否則使用「hhea」資料表中的指標。 如果已設定「USE_TYPO_METRICS」,請使用「typo」資料表中的指標;否則使用「win」資料表的指標。
Safari 使用「hhea」資料表中的指標。 如果已設定「USE_TYPO_METRICS」,請使用「typo」資料表中的指標;否則使用「win」資料表的指標。

如要進一步瞭解字型指標在不同作業系統中的運作方式,請參閱有關垂直指標的文章

跨裝置相容性

針對絕大多數的字型 (例如 Google Fonts 代管的 90% 代管的字型) 的字型指標覆寫值可安全使用,不必瞭解使用者的作業系統:換句話說,無論 hheatypowin 指標是否適用,這些字型的 ascent-overridedescent-overridelinegap-override 值都完全相同。這個存放區提供了適用及不適用字型的資訊。

如果使用的字型需要分別對 OSX 和 Windows 裝置使用各組字型指標覆寫,除非能夠根據使用者的作業系統來變更樣式表,否則我們不建議使用字型指標覆寫功能。此外,也不建議使用 size-adjust

使用字型指標覆寫設定

字型指標覆寫值是根據網頁字型中繼資料 (而非備用廣告字型) 的測量值計算而得,因此無論用哪個字型做為備用字型,字型指標都會保持不變。例如:

body {
  font-family: "Poppins", "fallback for Poppins", "another fallback for Poppins";
}

@font-face {
  font-family: "fallback for Poppins";
  src: local("Arial");
  ascent-override: 105%;
  descent-override: 35%;
  line-gap-override: 10%;
}

@font-face {
  font-family: "another fallback for Poppins";
  src: local("Roboto");
  ascent-override: 105%;
  descent-override: 35%;
  line-gap-override: 10%;
}

大小調整的運作方式

引言

size-adjust CSS 描述元會按比例縮放字型字符的寬度和高度。舉例來說,size-adjust: 200% 會將字型字符調整為原始大小的兩倍,size-adjust: 50% 會將字型字符縮放為原始大小的一半。

這張圖表顯示使用「size-Adjust: 50%」和「size-Adjust: 200%」的結果。

size-adjust 本身也有限,用於改善字型備用項。在大多數情況下,備用字型需縮小或稍微放大 (而非按比例調整),以便與網路字型相符。不過,將 size-adjust 與字型指標覆寫結合,便可讓任一字型在水平和垂直方向上互相吻合。

在樣式表中,size-adjust 的使用方式如下:

@font-face {
  font-family: "fallback for poppins";
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

根據 size-adjust 的計算方式 (如下一節所述),size-adjust 的值 (以及對應的字型指標覆寫) 會因使用的備用字型而異:

body {
  font-family: "Poppins", "fallback for Poppins", "another fallback for Poppins";
}

@font-face {
  font-family: poppins-fallback;
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

@font-face {
  font-family: poppins-fallback-android;
  src: local("Roboto");
  size-adjust: 55.5193474%:
  ascent-override: 180.1173909%;
  descent-override: 63.04108683%;
  line-gap-override: 18.01173909%;
}

計算大小調整和字型指標覆寫

以下是計算 size-adjust 和字型指標覆寫值的公式:

size-adjust = avgCharacterWidth of web font / avgCharacterWidth of fallback font
ascent-override = web font ascent / (web font UPM * size-adjust)
descent-override = web font descent / (web font UPM * size-adjust)
line-gap-override = web font line-gap / (web font UPM * size-adjust)

大部分的輸入內容 (包括邊緣、下降和行距) 都可以直接從網路字型的中繼資料讀取。不過,avgCharacterWidth 需要估算。

概略字元寬度

一般而言,平均字元寬度只能取得約略值,但在某些情況下可以準確計算:例如使用等寬字型,或事先得知文字字串內容時。

計算 avgCharacterWidth 的簡單方法之一,就是擷取所有 [a-z\s] 字元的平均寬度。

 比較個別 Roboto [a-zs] 字符寬度的圖表。
Roboto 字符的寬度

不過,將所有字元的權重相等,可能會使常用字母 (例如 e) 的寬度過小,並超重不常用的字母寬度 (例如 z)。

更複雜的方法可以提高準確度,請將字母頻率納入考量,改為計算頻率加權平均寬度為 [a-z\s] 個字元。請參閱這篇文章,瞭解英文文字的字母出現頻率和平均字詞長度的詳細資訊。

圖表顯示英文的字母頻率。
英文字母頻率

選擇方法

本文討論的兩種方法各有優缺點:

  • 如要開始最佳化字型備用項目,建議單獨使用字型指標覆寫功能。雖然這兩種做法比較簡單,但通常十分強大,能夠明顯減少字型相關版面配置的位移程度。

  • 不過,如果您想要更精準,且願意做更多工作和測試,加入 size-adjust 會是不錯的做法。如果正確實作,這個方法可以有效排除與字型相關的版面配置位移。

選擇備用字型

本文所述的技巧仰賴字型指標覆寫和 size-adjust 來轉換廣泛的可用本機字型,而不是嘗試尋找與網頁字型非常接近的本機字型。選擇當地字型時,請特別留意,極少數的字型只能在當地使用,且所有裝置都不含單一字型。

Arial 是 Sans-Serif 字型的建議備用字型,Times New Roman 是 Serif 字型的建議備用字型。不過,這些字型不適用於 Android 裝置 (Roboto 是 Android 唯一的系統字型)。

以下範例使用三種備用字型,確保擴大裝置的涵蓋範圍:指定 Windows/Mac 裝置的備用字型、指定 Android 裝置的備用字型,以及使用一般字型系列的備用字型。

body {
  font-family: "Poppins", poppins-fallback, poppins-fallback-android, sans-serif;
}

/*
Poppins font metrics:
- ascent = 1050
- descent = 350
- line-gap = 100
- UPM: 1000
AvgCharWidth:
- Poppins: 538.0103768
- Arial: 884.1438804
- Roboto: 969.0502537
*/

@font-face {
  font-family: poppins-fallback;
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

@font-face {
  font-family: poppins-fallback-android;
  src: local("Roboto");
  size-adjust: 55.5193474%:
  ascent-override: 180.1173909%;
  descent-override: 63.04108683%;
  line-gap-override: 18.01173909%;
}

意見回饋要求

如果您對使用字型指標覆寫功能和 size-adjust 的體驗有任何意見回饋,請與我們聯絡。