改善備用字型

Katie Hempenius
Katie Hempenius

摘要

本文將深入探討字型備用方案,以及 size-adjustascent-overridedescent-overrideline-gap-override API。這些 API 可以使用本機字型建立與網頁字型尺寸密切或完全相符的備用字型。這麼做可減少或消除因字型交換造成的版面配置位移。

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

架構工具:

  • @next/font:自 10 月 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。本文將說明這兩種做法。

字型指標覆寫的運作方式

簡介

字型指標覆寫值可用於覆寫字型的上升、下降和行距:

  • 重音是指字型的字符從基準線所延伸的最遠距離。
  • Descent 會測量字型字符向下延伸至基準線下方的最遠距離。
  • 行間距 (也稱為「行間距") 是指連續兩行文字之間的距離。

圖表顯示字型上升、下降和行距。

字型指標覆寫功能可用來覆寫備用字型的上升、下降和行距,以符合網路字型的上升、下降和行距。因此,網頁字型和調整過的備用字型一律會具有相同的垂直尺寸。

字型指標覆寫值會用於以下樣式的樣式表單中:

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 字體中約 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」的體驗有任何意見,歡迎與我們聯絡。