🖼️

JavaScriptでGoogle Fontsを動的に読み込む

2022/09/05に公開

Canvas APIを利用して文字を描画する際、Canvas内でのみ使うフォントを動的に読み込むのに少々躓いたのでメモしておきます。

フォントをJavaScriptで動的に読み込む

WebフォントをHTML/CSSではなくJavaScriptのみで動的に読み込みたい場合、FontFace APIを利用して次のように書くことが出来ます。

const font = new FontFace("フォント名", "WebフォントのURL or バイナリフォントデータ");  // FontFaceオブジェクトを作成
await font.load(); // フォントがロードされるまで待つ
document.fonts.add(font); // FontFaceSetにFontFaceを追加

GoogleフォントをJavaScriptで動的に読み込む

Google Fonts APIのベースURLはhttps://fonts.googleapis.com/cssですが、ここにフォントをリクエストしても、返ってくるのは次のようなCSS用の@font-faceデータです。

/* [0] */
@font-face {
  font-family: 'Noto Serif JP';
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/notoserifjp/v21/xn7mYHs72GKoTvER4Gn3b5eMXNvMckQlPa61uNKcCqOfbtLXoH3502Rk.0.woff2) format('woff2');
  unicode-range: U+25ee8,(以下略)

なので、Google Fonts APIを経由して動的にフォントを読み込む場合は、これをパースして、url(hoge)の部分だけFontFaceコンストラクタに渡してやる必要があります。

const exampleFontFamilyName = "Noto Serif JP"; // 取得したいGoogleフォント名
const urlFamilyName = exampleFontFamilyName.replace(/ /g, "+"); // URLでは空白を+に置き換える
const googleApiUrl = `https://fonts.googleapis.com/css?family=${urlFamilyName}`; // Google Fonts APIのURL

const response = await fetch(googleApiUrl);
if (response.ok) {
  // url()の中身のURLだけ抽出
  const cssFontFace = await response.text();
  const matchUrls = css.match(/url\(.+?\)/g);
  if (!matchUrls) throw new Error("フォントが見つかりませんでした");
  
  for (const url of matchUrls) {
    // 後は普通にFontFaceを追加
    const font = new FontFace(exampleFontFamilyName, url);
    await font.load();
    document.fonts.add(font);
  }
}

Canvasで使う場合、あとはいつも通りctx.font = "(フォントサイズ) (フォント名)"でフォント指定してやるだけです。この時、フォント名はFontFaceオブジェクト作成時に指定したものになることに気をつけてください。

(おまけ)必要な文字種のみダウンロード

必要な文字種が予め分かっている場合、Google Fonts APIではその文字種のみ収録されたフォントファイルのURLを教えてくれます。
https://developers.google.com/fonts/docs/getting_started#optimizing_your_font_requests

以下のように、Google Fonts APIのURLのパラメータにtextを追加し、URLエンコードした文字列を値として入れます。

const exampleFontFamilyName = "Noto Serif JP";
const urlFamilyName = exampleFontFamilyName.replace(/ /g, "+");
const googleApiUrl = `https://fonts.googleapis.com/css?family=${urlFamilyName}&text=${encodeURIComponent("フォントファイルに収録したい文字列")}`; // Google Fonts APIのURL

Discussion