已下載的字型可能因 CSS 選取了其他字體、文字超出其涵蓋範圍、或其顯示視窗已過而保持未使用狀態。在 Mac 上,首先檢查實際渲染某標籤的字型,然後回溯選取與載入過程。
本指南針對維護網頁、能看到字型請求成功但仍見到備用文字的人員。檢查步驟請使用 macOS 上的 Chrome。下方的合成標籤 Panel 204 與字體家族名稱 Sample Sans 僅說明診斷流程;不代表特定網站。
成功的下載究竟證明了什麼?
將診斷視為四個獨立問題:資源是否已抓取?可用的字體是否已註冊?CSS 是否為這些字元選取了該字體?渲染器是否繪製了它?字型預載會啟動提前抓取;其存在並不代表哪個字型提供了可見文字。 MDN: rel="preload"
字型匹配作用於文字,而非單純作用於下載的檔案。瀏覽器會考慮請求的家族與字型屬性,再檢查字元支援。因此,一個標籤可能使用多種字體,而頁面另一處可能觸發字型下載,卻無法說明你的目標標籤情況。 W3C: CSS Fonts Module Level 4, font matching
使用此決策表選擇下一項檢查。它是基於文件化的載入與匹配邊界衍生出的診斷輔助,而非瀏覽器實測結果的記錄。
| 觀察結果 | 下一項檢查 | 有助區分的問題 |
|---|---|---|
| 計算出的家族與預期家族不同 | 追蹤勝出的 CSS 宣告 | 級聯或目標選取問題 |
| 計算出的家族正確,但渲染字體不同 | 檢查字體描述符與字元涵蓋 | 選取或備用字體問題 |
| JavaScript 回報已載入字體,但文件字體集中找不到 | 檢查註冊程式碼 | 載入但未註冊 |
| 重新載入後字體出現,但首次造訪缺失 | 檢查 font-display 與載入時機 |
顯示視窗行為 |
| 普通文字正常,Canvas 文字保持不變 | 檢查繪製順序與 Canvas 字型設定 | 獨立繪製操作 |
實際繪製目標標籤的是哪個字體?
在受影響頁面上,按下 Command + Shift + C 並選取文字。在 Elements 中,選取包含受影響標籤的最小元素。開啟 Computed,然後捲動至 Rendered Fonts。Chrome 將此視圖文件化為檢查提供渲染文字之字體的位置。 Chrome DevTools: CSS features reference, Chrome DevTools: Apply other effects
記錄渲染出的字體及其來源為本地還是網路資源。同時記錄計算出的 font-family、font-weight 與 font-style。計算出的家族是請求堆疊;渲染字體結果識別出提供字形的來源。僅憑熟悉的外觀屬於薄弱證據,因為兩種字體可能外觀相似。 Chrome DevTools: What font is that?
如果預期字體出現在受影響文字上,將調查方向移向具體外觀差異——如字重或特性。如果缺失,繼續下方步驟。測試時保持原始文字與視口不變,使各觀察結果可比較。
生效的 CSS 是否請求了預期字體?
在 Computed 中檢查生效的字型屬性,然後用 Styles 找到其宣告。Chrome 區分這兩個視圖:Styles 包含被覆寫的宣告,而 Computed 顯示實際套用的值。當卡片包含多個標籤時,請檢查承載文字的子元素;父元素的字型宣告不足以作為子元素的證據。 Chrome DevTools: CSS features reference
檢查任何勝出的 font 簡寫屬性以及個別屬性。例如,font: 16px sans-serif 會選取通用家族並重設省略的簡寫組件,包含字重與樣式。它也會重設 font-feature-settings 與 font-variation-settings 等屬性。修正導致非預期值的宣告,然後再次檢查。 MDN: font
接著,將請求的家族與相關 @font-face 規則中的 font-family 描述符比對。該描述符定義用於參考字體的 CSS 家族名稱;檔案名稱並非你必須放入元素字體堆疊的名稱。檢查傳遞給瀏覽器的規則,包含其 src、字重、樣式與任何宣告的範圍。 MDN: @font-face
可變字型支援的字重範圍可用兩個值表示,而靜態字體只能宣告一個字重。讓這些描述符準確描述所提供資源。不匹配值得調查,但不自動解釋備用字體:當精確樣式不可用時,字型匹配包含替代方案。 MDN: @font-face, W3C: Matching font styles
本地字體是否搶先佔用?
檢查 src 是否有 local() 替代方案。在安裝該字體的 Mac 上,瀏覽器可能使用本地副本,而單獨預載的 webfont 卻保持未使用。要在 Chrome 中隔離此狀況,開啟 Rendering 面板,啟用 Disable local fonts,然後重新載入。比較啟用前後的 Rendered Fonts,再還原設定。此測試針對 @font-face 規則中的 local() 來源。 Chrome DevTools: Apply other effects
字體是否已在正確文件中載入並註冊?
使用 new FontFace() 建立的字體,可能在加入字體集之前就完成載入。為了文件渲染,它必須加入 document.fonts。檢查應用程式的載入路徑是否執行了這兩項操作;單獨解析字體的載入 Promise 並不完成註冊。 MDN: CSS Font Loading API
以下完整的主控台診斷列出目前文件中已註冊的字體。在受影響頁面的主控台上下文中執行。它讀取字體集而不發起載入或變更樣式;不識別已渲染字形。其瀏覽器相依行為未在這裡執行。
(() => {
const faces = Array.from(document.fonts, face => ({
family: face.family,
weight: face.weight,
style: face.style,
stretch: face.stretch,
unicodeRange: face.unicodeRange,
status: face.status
}));
console.table(faces);
console.log("Registered face count:", faces.length);
})();
使用此清單區分「缺少註冊」與「已註冊但未使用的字體」。對於狀態為 error 的項目,先調查載入失敗,再調整排版。loaded 項目確立載入狀態,而字體選取仍取決於元素與文字。 MDN: CSS Font Loading API
切勿將 document.fonts.check() 視為渲染證明。即使家族不存在,它也可能回傳 true。其選用文字參數僅依宣告的 Unicode 範圍縮小匹配,不測試個別字形涵蓋。同理,document.fonts.ready 在已使用字體載入與版面配置後才解析;它不證明每個宣告的字體都已渲染。 MDN: FontFaceSet.check(), MDN: Document.fonts
字型是否涵蓋你測試的字元?
同時檢查 CSS unicode-range 與實際字型資源。描述符控制哪些字元可使用該字體。擴充描述符無法製造檔案中缺失的字形:字型的字元對照表仍是匹配的一部分。 MDN: unicode-range, W3C: Matching font styles
考慮一個限制為 U+0030-0039 的說明性規則。在 Panel 204 中,只有 2、0 與 4 落在該範圍內。字母與空白則不在。由數字觸發的下載,並不代表該字型能渲染整個標籤。MDN 文件說明:遇到符合條件的字元可能導致整個字型資源下載。 MDN: unicode-range
此獨立 JavaScript 範例揭示該區別。它可在瀏覽器主控台或 Node.js 中無設定執行。確定性範圍計算已針對所示樣本執行。
const text = "Panel 204";
const rows = Array.from(text, character => {
const value = character.codePointAt(0);
return {
character,
codePoint: "U+" + value.toString(16).toUpperCase().padStart(4, "0"),
inDeclaredRange: value >= 0x30 && value <= 0x39
};
});
console.table(rows);
如果範圍排除了所需字元,修正不準確的描述符或提供包含它們的子集。檢查結果時保持原始失敗文字。不要假設字串迭代即為成形測試:結合序列需要叢集處理,標準在需要時會考慮成形資訊。比較渲染輸出時保持序列完整。 W3C: Font matching and cluster matching
字型是否錯過顯示視窗?
當家族與涵蓋範圍看起來正確時,檢查 font-display。optional 有極短的封鎖期且無交換期。fallback 有短暫交換期。因此,資源在適用視窗後到達,可能導致該頁面載入時備用文字保持可見。swap 允許初始封鎖期後無限期交換。 MDN: font-display
為了受控診斷,在提供的樣式表中暫時將受影響規則改為 font-display: swap,並重現初始載入條件。如果字體在載入後出現,時機即為支持的解釋。決定該較晚的視覺變化是否適合頁面,再決定是否保留設定。同時重複初始載入與快取重載;單獨的快取結果無法重現原始到達時機。
當函式庫或 Canvas 繪製文字時會有何變化?
如果頁面已使用 Font Face Observer,檢查觀察的家族及其 weight、style、stretch 選項。其文件描述載入器與監視器,需要一般 @font-face 規則,且當字體缺乏預設測試字元時需要自訂測試字串。其預設逾時為三秒。觀察器逾時與瀏覽器的 font-display 視窗是獨立條件。 Font Face Observer documentation
作為診斷推論,觀察器的成功訊息應隨後檢查目標元素。監控某字體的可用性,不代表元素的勝出 CSS 請求了它。當未解的問題是哪個字體渲染時,安裝另一個載入器幫助不大。
Canvas 引入獨立繪製邊界。其繪製內容有自己的 font 設定,初始為 10px sans-serif;無效指派會被忽略。因此,在 canvas 元素上設定 CSS 家族不足以確立內容的字體。檢查指派給繪製內容的值,以及載入與繪製操作的順序。 WHATWG: Canvas text styles
對於 Canvas 文字,等待預期註冊字體載入,設定內容字體,然後使用應用程式正常繪製常式重繪受影響場景。先前繪製的像素不會在字體到達時獲得新字體。Canvas 文字準備也使用假設的無限寬行框,因此成功的 Canvas 測試不代表受限網頁標籤會以相同方式換行。 WHATWG: Text preparation and drawing text
如何確認修復?
回到原始標籤,重複暴露問題的觀察。在原始載入條件下,驗證其計算請求、渲染字體與相關字元。對於 Canvas,比較前先重繪。保留元素、請求屬性、實際渲染字體、資源與成功變更的精簡記錄;這讓診斷可重現。
當你能解釋為何字體未被使用、並在受影響文字上呈現預期結果時結束。修正的家族宣告、準確的子集、已註冊字體、合適的顯示策略、或正確計時的重繪,各自解決不同邊界。選擇觀察結果支持的修復。
來源
CSS Fonts Module Level 4 — W3C
CSS features reference — Chrome for Developers
Apply other effects: enable automatic dark theme, emulate focus, and more — Chrome for Developers
DevTools answers - What font is that? — Chrome for Developers
rel="preload" HTML attribute value — MDN Web Docs
font CSS property — MDN Web Docs
@font-face CSS at-rule — MDN Web Docs
CSS Font Loading API — MDN Web Docs
FontFaceSet: check() method — MDN Web Docs
Document: fonts property — MDN Web Docs
unicode-range CSS at-rule descriptor — MDN Web Docs
font-display CSS at-rule descriptor — MDN Web Docs
Font Face Observer — Bram Stein / Font Face Observer project
HTML Standard: The canvas element — WHATWG