CSS Font Loading API

Baseline 廣泛可用 *

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2020 年 1 月⁩ 起,所有主流瀏覽器均已支援。

* 此特性的某些部分可能存在不同級別的支援。

注意:此功能在 Web Workers 中可用。

CSS 字型載入 API 提供用於動態載入字型資源的事件和介面。

概念與用法

CSS 樣式表允許作者使用自定義字型;透過 @font-face 規則指定要下載的字型,並透過 font-family 屬性將其應用於元素。使用者代理控制字型下載的時間點。大多數代理僅在首次需要字型時才獲取和載入字型,這可能導致明顯的延遲。

CSS 字型載入 API 透過讓作者控制和跟蹤字體面(font face)何時被獲取和載入,以及何時被新增到文件或工作程式擁有的字體面集合中,來解決此問題。將字體面新增到文件或工作程式的字體面集合中,允許使用者代理在需要時自動獲取和載入關聯的字型資源。字體面可以在新增到著色集之前或之後載入,但必須先新增到著色集中才能用於繪製。

字體面在 FontFace 物件中定義,該物件指定一個二進位制或 URL 字型源以及字型的其他屬性,這與 CSS @font-face 規則非常相似。FontFace 物件分別使用 Document.fontsWorkerGlobalScope.fonts 新增到文件或工作程式的 FontFaceSet 中。作者可以使用 FontFaceFontFaceSet 觸發字型下載,並監視載入完成情況。FontFaceSet 還可以用來確定頁面所需的所有字型何時載入完成以及文件佈局何時完成。

FontFace.status 屬性指示字體面的載入狀態:unloadedloadingloadedfailed。此狀態最初為 unloaded。當檔案正在下載或字型資料正在處理時,它被設定為 loading,如果字型定義無效或字型資料無法載入,則設定為 failed。當字體面的資料已成功獲取(如果需要)並載入後,狀態被設定為 loaded

定義字體面

字體面使用 FontFace 建構函式 建立,該建構函式接受以下引數:字體系列、字型源以及可選的描述符。這些引數的格式和語法與等效的 @font-face 定義相同。

字型源可以是 ArrayBuffer 中的二進位制資料,也可以是 URL 處的字型資源。使用 URL 源的典型字體面定義如下所示。請注意,URL 字型源需要 url() 函式。

js
const font = new FontFace("my-font", 'url("my-font.woff")', {
  style: "italic",
  weight: "400",
  stretch: "condensed",
});

注意:@font-face 一樣,一些描述符代表字型資料中的預期資料,並用於字型匹配,而另一些描述符則實際設定/定義生成的字體面的屬性。例如,將 style 設定為“italic”表示檔案包含斜體字型;作者有責任指定一個檔案,其中該值為真。

具有二進位制源的字體面將在字型定義有效且字型資料可載入時自動載入 — 成功時 FontFace.status 設定為 loaded,否則設定為 failed。具有 URL 源的字體面會被驗證但不會自動載入 — 如果字體面定義有效,FontFace.status 被設定為 unloaded,否則設定為 failed

將字型新增到文件或工作程式

字體面通常會新增到文件或工作程式的 FontFaceSet 中,以便使用者代理在需要時自動載入字型,並且必須新增字型才能用於渲染文字。

下面的程式碼顯示了一個字體面被新增到文件中。

js
// Define a FontFace
const font = new FontFace("my-font", 'url("my-font.woff")', {
  style: "italic",
  weight: "400",
  stretch: "condensed",
});

// Add to the document.fonts (FontFaceSet)
document.fonts.add(font);

載入字型

可以透過呼叫 FontFace.load() 來手動載入字體面,或者如果字體面已新增到 FontFaceSet 中,則可以透過呼叫 FontFaceSet.load() 來載入。請注意,嘗試載入已載入的字型無效。

下面的程式碼演示瞭如何定義一個字體面,將其新增到文件字型中,然後啟動字型載入。

js
// Define a FontFace
const font = new FontFace("my-font", 'url("my-font.woff")');

// Add to the document.fonts (FontFaceSet)
document.fonts.add(font);

// Load the font
font.load();

// Wait until the fonts are all loaded
document.fonts.ready.then(() => {
  // Use the font to render text (for example, in a canvas)
});

請注意,font.load() 返回一個 Promise,因此我們可以透過在後面鏈式呼叫 then 來處理字型載入的完成。在某些情況下,使用 document.fonts.ready 可能更好,因為它僅在文件中的所有字型都已解析且佈局完成後呼叫。

介面

FontFace

表示一個可用的單個字體面。

FontFaceSet

一個載入字體面並檢查其下載狀態的介面。

FontFaceSetLoadEvent

每當 FontFaceSet 載入時觸發。

示例

基本字型載入

這是一個非常簡單的示例,展示瞭如何從 Google Fonts 載入字型並將其用於在 Canvas 上繪製文字。該示例還在建立後和載入後立即記錄 status

HTML

此程式碼定義了一個用於繪製的 Canvas 和一個用於記錄的 textarea。

html
<canvas id="js-canvas"></canvas>
<textarea id="log" rows="3" cols="100"></textarea>

JavaScript

首先,我們獲取將用於記錄的元素以及將用於在下載的字型中渲染文字的 Canvas。

js
const log = document.getElementById("log");

const canvas = document.getElementById("js-canvas");
canvas.width = 650;
canvas.height = 75;

接下來,我們定義一個具有 Google Fonts URL 源的 FontFace,並將其新增到 document.fonts。然後我們記錄字型狀態,這應該是 unloaded

js
const bitterFontFace = new FontFace(
  "FontFamily Bitter",
  'url("https://fonts.gstatic.com/s/bitter/v7/HEpP8tJXlWaYHimsnXgfCOvvDin1pK8aKteLpeZ5c0A.woff2")',
);
document.fonts.add(bitterFontFace);
log.textContent += `Bitter font: ${bitterFontFace.status}\n`; // > Bitter font: unloaded

然後,我們呼叫 FontFace.load() 方法載入字體面,並等待返回的 Promise。Promise 解析後,我們記錄載入的狀態(應為 loaded)並在 Canvas 上用載入的字型繪製文字。

js
bitterFontFace.load().then(
  () => {
    log.textContent += `Bitter font: ${bitterFontFace.status}\n`; // > Bitter font: loaded

    const ctx = canvas.getContext("2d");
    ctx.font = '36px "FontFamily Bitter"';
    ctx.fillText("Bitter font loaded", 20, 50);
  },
  (err) => {
    console.error(err);
  },
);

請注意,我們也可以等待 FontFace.loaded 屬性返回的 Promise,或者等待 FontFaceSet.ready

結果

結果如下所示。它應該顯示在 Canvas 上用下載的字型繪製的字型名稱,以及顯示載入前後載入狀態的日誌。

使用事件載入字型

此示例與上一個示例類似,但它使用 FontFaceSet.load() 載入字型。它還演示瞭如何監聽字型載入事件。

HTML

html
<canvas id="js-canvas"></canvas>
<textarea id="log" rows="25" cols="100"></textarea>

JavaScript

下面的程式碼定義了一個用於繪製文字的 Canvas 上下文,定義了一個字體面,並將其新增到文件字體面集合中。

js
const log = document.getElementById("log");

const canvas = document.getElementById("js-canvas");
canvas.width = 650;
canvas.height = 75;
const ctx = canvas.getContext("2d");

const oxygenFontFace = new FontFace(
  "FontFamily Oxygen",
  'url("https://fonts.gstatic.com/s/oxygen/v5/qBSyz106i5ud7wkBU-FrPevvDin1pK8aKteLpeZ5c0A.woff2")',
);
document.fonts.add(oxygenFontFace);
log.textContent += `Oxygen status: ${oxygenFontFace.status}\n`;

接下來,我們在字體面集合上使用 load() 來載入字型,並指定要載入的字型。該方法返回一個 Promise。如果 Promise 成功解析,我們就使用該字型繪製一些文字。如果 Promise 被拒絕,則記錄錯誤。

js
document.fonts.load("36px FontFamily Oxygen").then(
  (fonts) => {
    log.textContent += `Bitter font: ${fonts}\n`; // > Oxygen font: loaded
    log.textContent += `Bitter font: ${oxygenFontFace.status}\n`; // > Oxygen font: loaded
    ctx.font = '36px "FontFamily Oxygen"';
    ctx.fillText("Oxygen font loaded", 20, 50);
  },
  (err) => {
    console.error(err);
  },
);

與其等待 Promise,我們也可以使用事件來跟蹤字型載入操作。下面的程式碼監聽 loadingloadingerror 事件,並記錄每種情況下的字體面數量。在 loadingdone 事件監聽器中,我們還會遍歷字體面並記錄字體系列的名稱。

js
document.fonts.addEventListener("loading", (event) => {
  log.textContent += `loading_event: ${event.fontfaces.length}\n`;
});
document.fonts.addEventListener("loadingerror", (event) => {
  log.textContent += `loadingerror_event: ${event.fontfaces.length}\n`;
});
document.fonts.addEventListener("loadingdone", (event) => {
  log.textContent += `loadingdone_event: ${event.fontfaces.length}\n`;
  event.fontfaces.forEach((value) => {
    log.textContent += `  fontface: ${value.family}\n`;
  });
});

最後一段程式碼演示瞭如何使用 FontFaceSet.ready 返回的 Promise 來監視字型載入的完成情況。與其他機制不同,這在文件中定義的所有字型都已下載並且佈局已完成時才返回。

當 Promise 解析時,我們遍歷文件字體面中的值。

js
document.fonts.ready.then(() => {
  log.textContent += `\nFontFaces in document: ${document.fonts.size}.\n`;

  for (const fontFace of document.fonts.values()) {
    log.textContent += "FontFace:\n";
    for (const property in fontFace) {
      log.textContent += `  ${property}: ${fontFace[property]}\n`;
    }
  }
});

結果

下面的輸出顯示了用“Oxygen”字型繪製的文字。它還顯示了來自事件和 document.fonts.ready Promise 解析時的日誌。

規範

規範
CSS 字型載入模組等級 3
# fontface-interface

瀏覽器相容性