Catalina 為 macOS 帶來全新的統一可變字型系統。
CSS 字型模組第 4 級規格的「system-ui」部分定義了 system-ui
字型關鍵字,開發人員可直接在網站和應用程式中使用內建、經過渦輪最佳化、本地化、超高品質、不需下載的預設作業系統字型。
body {
font-family: system-ui;
}
這項字體選擇等同於「使用這位使用者目前所在地區的預設系統字型」。
在 macOS 上,system-ui
字型是 San Francisco,這是設計團隊經過審查、測試,且最近升級的字型!首先,我們會介紹 Catalina 中令人期待的全新可變字型功能,接著說明幾個 錯誤,以及 Chromium 工程師如何解決這些問題。
本文假設您已熟悉可變字型。如果不是,請參閱網頁上的可變字型簡介和下方影片。
瀏覽器相容性
撰寫本文時,Chromium (自 56 版起)、Edge (自 79 版起)、Safari (自 11 版起) 和 Firefox (自 43 版起) 都支援 system-ui
,但 Firefox 使用的是 -apple-system
關鍵字。如需最新消息,請參閱「可以使用可變字型嗎?」一文。
全新功能
自 Chromium 83 起,網頁開發人員可使用 Catalina 為系統字型帶來的新功能。system-ui
字型現在提供更多變數設定:光學大小和 2 種獨特的粗細調整方式:
h1 { font-family: system-ui; font-weight: 700; font-variation-settings: 'wght' 750 ; }
h1 { font-family: system-ui; font-weight: 700; font-variation-settings: 'wght' 750, 'opsz' 20, 'GRAD' 400, 'YAXS' 400 ; }
在 Mojave 中,system-ui
是只有 wght
設定的可變字型。Catalina 的 system-ui
是變數字型,具有 wght
、opsz
、GRAD
和 YAXS
設定。
在我看來,這似乎是個絕佳的漸進式強化設計機會!如果想深入瞭解系統字型,可以盡情探索。
wght
接受介於 0
和 900
之間的字型粗細,並平均套用至所有字元。
/* 0-900 */
font-variation-settings: 'wght' 750;
opsz
光學尺寸與字元間距或字母間距類似,但間距是由人眼而非數學計算決定。19
以下的值適用於文字和內文副本間距,20
以上的值則適用於顯示標題和標題的間距。
/* 19 or 20 */
font-variation-settings: 'opsz' 20;
GRAD
與權重類似,但不會影響水平間距。可接受的值介於 400
和 1000
之間。
/* 400-1000 */
font-variation-settings: 'GRAD' 500;
YAXS
垂直延展字形。可接受的值介於 400
和 1000
之間。
/* 400-1000 */
font-variation-settings: 'YAXS' 500;
合併選項
只要幾行 CSS,我們就能將字型設定調整為所選的粗體,或是嘗試其他有趣的組合:
font-weight: 700;
font-weight: bold;
font-variation-settings: 'wght' 750, 'YAXS' 600, 'GRAD' 500, 'opsz' 20;
就這樣,macOS 上的 Chromium 使用者就能看到升級後的自訂 750 權重,以及其他一些有趣的調整內容 👍
macOS 10.15 在系統字型中新增了功能,並在 Chromium 錯誤追蹤器中記錄了 macOS 10.15 的棘手 system-ui
錯誤。不知道兩者是否有關聯!
附錄:system-ui
迴歸
這個故事的開端是另一個錯誤:#1005969。macOS 10.15 曾回報此問題,因為 system-ui
字型間距看起來很窄且擁擠。

背景
您是否曾注意到,在 macOS 10.14 中,段落或標題在大小增加或減少時,會「貼齊」到不同外觀的字型?
在 Mojave (macOS 10.14) 中,system-ui
字型會根據目標字型大小在兩種字型之間切換。如果文字位於 20px
下方,macOS 會使用「舊金山文字」。如果文字為 20px
或以上,macOS 會使用「舊金山顯示器」。光學尺寸是靜態建構在兩個不同的字型中。
Catalina (macOS 10.15) 推出新的 San Francisco 統一可變字型。不必再管理「文字」和「多媒體」廣告活動。此外,這個函式也新增了先前所述的變異設定 opsz
。
h1 {
font-variation-settings: 'opsz' 20;
}
很抱歉,新版 Catalina 字型的預設 opsz
值為 20
,而 Chromium 工程師尚未準備好將 opsz
套用至系統字型。導致較小的尺寸顯示過窄。
為修正這個問題,Chromium 必須將 opsz
正確套用至系統字型。因此我們修正了問題 #1005969。獲勝!還是…?
尚未完成
這時問題就來了:Chromium 套用了 opsz
,但看起來還是不太對勁。Mac 上的系統字型還有一個名為 trak
的額外字型表格,可調整水平間距。在修正問題時,Chromium 工程師發現,在 macOS 上,從 CTFontRef
物件擷取水平指標時,trak
指標已納入指標結果。Chromium 的成形程式庫 HarfBuzz
需要的指標尚未計入 trak
值。

在內部,Skia (圖形程式庫,而非同名字體) 會使用 CoreGraphics
中的 CGFontRef
類別和 CoreText
中的 CTFontRef
類別。由於這些物件之間需要進行內部轉換 (用於維持回溯相容性,並存取這兩個類別中所需的 API),Skia 在特定情況下會遺失權重資訊,粗體字型也會停止運作。這項問題已在問題 #1057654 中追蹤。
由於 Chromium 仍支援 macOS 10.11,Skia 仍需支援該版本。在 10.11 版中,「San Francisco Text」和「San Francisco Display」字型甚至不是可變字型。而是為每個可用的粗細建立個別的字型系列。在某個時間點,兩者的字元 ID 開始不同步。因此,如果 Skia 使用「San Francisco Text」進行文字成形 (將文字轉換為可繪製的字形),則使用「San Francisco Display」繪製時會變成亂碼,反之亦然。即使 Skia 只是要求不同大小,macOS 也可能會切換到其他大小。應該可以一律使用其中一種字型並進行縮放 (使用矩陣放大,而不是要求較大的尺寸),但 CoreText
有個問題,就是不會放大 sbix (彩色表情符號) 字元 (只會縮小)。實際情況比這複雜一點。CoreText
似乎會在套用矩陣後限制垂直範圍,這似乎與無法以 45 度角繪製表情符號有關。無論如何,如要顯示大型表情符號,您必須複製字型才能取得大型版本。
因此,為了在內部建立不同大小的 CTFont
物件副本,同時確保使用相同的基礎字型資料,Chromium 會從 CTFont
中提取 CGFont
,然後從 CGFont
建立新的 CTFont
(CGFont
物件與大小無關,切換魔法會在 CoreText
層級發生)。在 10.154 之前,這項功能運作正常。在 10.15 中,這個來回行程最終會遺失過多資訊,導致權重問題。Flutter 發現權重問題,並針對大小調整作業提供替代修正方式,直接從原始 CTFont
建立新的 CTFont
,同時使用 CoreText
中舊版但未記錄的屬性直接控制光學大小。這樣可確保 10.11 正常運作,並修正其他問題 (例如將光學尺寸明確設為預設值)。
不過,這樣做可以保留更多字型的「魔法」CoreText
。其中一個問題似乎是,除了 trak
表格之外,這個屬性仍會以某種方式調整字元間距 (Chromium 已經嘗試透過另一個未記錄的屬性抑制這種情況)。
CGFont
不會執行任何「魔法」,因此 Chromium 或許可以擺脫 CGFont
,CTFont
並使用 CGFont
取得進展?很抱歉,這無法運作,因為 CoreText
也會以其他方式干擾字型。舉例來說,系統會將小型表情符號放大一點,CGFont
不知道這點,因此您會以某個大小測量,但 CoreText
會將表情符號繪製得更大,導致以 sbix 為基礎的表情符號彼此太靠近。Chromium 確實需要 CTFont
進展,但希望不要有追蹤功能,最好也不要有任何其他干擾。
由於修正間距問題需要一系列相互關聯的 Blink 和 Skia 修正,Chromium 工程師無法「只是還原」來解決問題。Chromium 工程師也嘗試使用其他建構標記,變更 Skia 中與字型相關的程式碼路徑,雖然修正了粗體字型問題,但卻導致間距問題。
修正方式
最後,Chromium 當然希望修正這兩項問題。Chromium 現在會使用 HarfBuzz 內建的字型 OpenType 字型指標函式,直接從系統字型字型表格中的二進位資料擷取水平指標。這樣一來,當字型有 trak
表格時,Chromium 就能略過 CoreText
和 Skia (表情符號字型除外)。

同時,我們仍在追蹤 Skia 問題 #10123,以便在 Skia 中完全修正這個問題,並改用 Skia 擷取系統字型指標,而非目前透過 HarfBuzz
進行的修正。