【Webフォント最適化】pyftsubsetでInterとNoto Sans JPをサブセット化する手順

Webフォント

Webサイトの表示で意外と気になるのが、フォントの重さです。特に日本語フォントはサイズが大きく、初回表示の遅さにつながります。

この記事では、Google Fontsから入手したInterとNoto Sans JPの可変フォントを、pyftsubsetというツールでサブセット化する方法を1から解説します。目的は、WordPress子テーマで使える軽量なWebフォント環境を作ることです。

今回は可変フォントを例にしますが、もし本文で400、見出しで700といった限られたウェイトしか使わないなら、静的フォントを個別にサブセット化したほうがファイルはさらに小さくなります。用途に応じて選んでください。

📌 要点サマリー

  • Interは英数記号のみ(ASCII+主要記号)に限定
  • Noto Sans JPは日本語担当で漢字(U+4E00-9FFF)も既定で含める
  • --no-hinting で両フォントのサイズを大幅削減
  • 出力はWOFF2で、子テーマの fonts に配置
  • ウェイトが少ないなら静的フォントのほうが効率的

💡 基本の考え方

サブセット化とは、使う文字だけを残してフォントを小さくする方法です。英字はInter、和文はNoto Sans JPと役割を分けると、見た目の安定と軽さを両立できます。

目指すのは、子テーマでのローカル読み込みです。CDNに頼らず、preloadやfont-displayを組み合わせて体感を改善します。

🛠 実装手順

手順は準備→導入→Inter→Noto→組み込み→検証の流れで進めます。作業前にフォルダ構成を決めておくとスムーズです。

🔎 前提環境

作業用のフォルダを用意します。テーマを自作する人は少ないので、WordPress子テーマを前提に説明します。

  • ダウンロード元: Google Fonts
  • フォルダ例: project/fonts/source に元フォント、project/fonts/subset に出力
  • WordPress子テーマ: 子テーマ直下にfontsフォルダを作成
  • ダウンロードするファイル
    • Inter-VariableFont_opsz,wght.ttf
    • NotoSansJP-VariableFont_wght.ttf

Interは英数記号だけを使い、Noto Sans JPは日本語(仮名+漢字)を担当します。paltを残して自然な字間にします。

ウェイトが限られる場合は可変ではなく、400や700の静的フォントを個別にサブセット化したほうが小さくなることがあります。

⚙️ Step0: フォントの取得と配置

やること

  1. Google Fontsから上記2ファイルをダウンロード
  2. project/fonts/source に置く
  3. 子テーマにはまだ置かない(サブセット化後に配置)

ポイント

  • ファイル名はそのままにすると後で迷わない
  • 可変フォントは1ファイルで幅広い表現を扱える

⚙️ Step1: pyftsubsetの準備

pyftsubsetはfonttoolsに含まれているサブセット化ツールです。環境を壊さずに導入できるpipxを使う方法がもっとも安全で一般的です。WindowsとmacOSで手順が少し異なります。

🪟 Windowsの場合(PowerShell)

  1. Python 3が入っているか確認
py --version

未導入ならインストールします。

  1. pipxをインストール
py -m pip install --user pipx
py -m pipx ensurepath
  1. fonttoolsを導入
pipx install fonttools
  1. 動作確認
pyftsubset --version
where pyftsubset

バージョンが表示され、実行ファイルのパスが出れば準備完了です。

🍎 macOSの場合(Terminal, zsh)

  1. Python 3が入っているか確認
python3 --version

未導入なら公式インストーラーかHomebrewでPython3を入れます。

  1. pipxをインストール
brew install pipx
pipx ensurepath
  1. fonttoolsを導入
pipx install fonttools
  1. 動作確認
pyftsubset --version
which pyftsubset

バージョンが表示され、実行ファイルのパスが出れば準備完了です。

よくある失敗と対処

  • pyftsubsetが見つからない → 新しいターミナルを開いて再度確認
  • command not found: pipx → Homebrewのインストールを確認、または python3 -m pip install --user pipx を利用
  • PATHが通っていない → pipx ensurepath 後に再ログイン

🧪 Step2: Interをサブセット化(英数記号のみ)

Interは英数記号だけを残して最小化します。一般的にはUnicode範囲を指定する方法がシンプルです。必要な記号も最初から含めると差し戻しが減ります。

やること

cd project/fonts/source
pyftsubset "Inter-VariableFont_opsz,wght.ttf" \
  --output-file="../subset/Inter-Subset.woff2" \
  --flavor=woff2 \
  --no-hinting \
  --unicodes=U+0020-007E,U+00A0,U+2013,U+2014,U+2018,U+2019,U+201C,U+201D,U+2026

補足

  • 必要な記号があれば、U+コードをカンマで追加します。
  • --no-hinting でヒンティング情報を削除し、サイズを大幅に削減できます(WOFF2 では視認性への影響が小さいことが多い)。

内訳(InterのUnicodeレンジ)

  • U+0020–007E: 基本ラテン(ASCII)。半角英数と基本記号
  • U+00A0: ノーブレークスペース(改行しない空白)
  • U+2013: エンダッシュ(短いダッシュ)
  • U+2014: エムダッシュ(長いダッシュ)
  • U+2018 / U+2019: 左右のシングルクォート
  • U+201C / U+201D: 左右のダブルクォート
  • U+2026: 省略記号(三点リーダー)

確認方法

  • 出力が生成され、英数字が正しく表示される

🧪 Step3: Noto Sans JPをサブセット化(日本語+漢字+palt)

日本語は文字数が多いため、仮名・記号に加えて漢字(U+4E00-9FFF)も既定で含めます。必要に応じて拡張Aなどを追加してください。paltは保持します。

やること

cd project/fonts/source
pyftsubset "NotoSansJP-VariableFont_wght.ttf" \
  --output-file="../subset/NotoSansJP-Subset.woff2" \
  --flavor=woff2 \
  --no-hinting \
  --unicodes=U+3000-303F,U+3040-309F,U+30A0-30FF,U+31F0-31FF,U+4E00-9FFF \
  --layout-features=ccmp,locl,kern,palt

補足

  • 文字が欠けたら、その漢字のコードポイントを足して再出力します。
  • 半角カナや全角形を使う場合は U+FF61-FF9F(半角カナ)、U+FF00-FFEF(全角形)も追加します。

内訳(Noto Sans JPのUnicodeレンジ)

  • U+3000–303F: 句読点・括弧・全角スペースなど
  • U+3040–309F: ひらがな
  • U+30A0–30FF: カタカナ
  • U+31F0–31FF: カタカナ音声拡張
  • U+4E00–9FFF: CJK統合漢字(一般的な漢字の大部分)
    (任意で追加: U+FF61–FF9F 半角カナ, U+FF00–FFEF 半角/全角形)

保持しているOpenType機能(--layout-features=ccmp,locl,kern,palt

  • ccmp: 合成/分解の正規化で字形崩れ防止
  • locl: 言語別のローカライズ字形を選択
  • kern: ペアカーニングで間隔を微調整
  • palt: プロポーショナル代替で約物やカナの字間を整える

※ 既定で漢字(U+4E00-9FFF)も含めています。レア漢字や拡張Aなどが必要な場合は --unicodes にレンジを追加してください。

確認方法

  • サンプルHTMLで自然な字間と欠け文字がないこと

📦 Step4: 子テーマに配置し、@font-faceで読み込む

出力したWOFF2を子テーマに置き、CSSで読み込みます。Interは英数字、Notoは日本語の役割です。

やること

  1. subsetフォルダの Inter-Subset.woff2 と NotoSansJP-Subset.woff2 を 子テーマ/fonts にコピー
  2. 子テーマのstyle.cssやSCSSにフォント定義を記述

例(可変フォント)

@font-face {
  font-family: 'Inter';
  src: url('./fonts/Inter-Subset.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Noto Sans JP';
  src: url('./fonts/NotoSansJP-Subset.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: optional;
}
html { font-family: 'Inter', 'Noto Sans JP', system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; }
body { font-feature-settings: 'palt' 1; }

上記は style.css が子テーマ直下、フォントが 子テーマ/fonts にある想定です。自分の環境に合わせて url() のパスを書き換えてください。

静的ウェイト例(400と700だけを使うなら静的ファイルをサブセット化したほうが効率的)

@font-face {
  font-family: 'Inter';
  src: url('./fonts/Inter-Subset-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('./fonts/Inter-Subset-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Noto Sans JP';
  src: url('./fonts/NotoSansJP-Subset-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: optional;
}
@font-face {
  font-family: 'Noto Sans JP';
  src: url('./fonts/NotoSansJP-Subset-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: optional;
}

上記は style.css が子テーマ直下、フォントが 子テーマ/fonts にある想定です。自分の環境に合わせて url() のパスを書き換えてください。

ポイント

  • 可変フォントは柔軟だが、ウェイトが少ないなら静的のほうが軽い
  • Interは英数字、Noto Sans JPは日本語
  • local() は省略(デバッグを容易にするため)
  • font-displayはInterにswap、Notoは用途でswap/optional
  • preloadはLCPに関わるフォントだけ

確認方法

  • 英数はInter、和文はNotoで出る
  • ページ全体で文字化けがない

🚀 Step5: preloadとfetchpriorityの設定

体感をもっと良くしたいときは、LCPに関わるフォントだけを先に読ませます。

例(functions.php)

function child_preload_fonts() {
  $fonts = array(
    get_stylesheet_directory_uri() . '/fonts/NotoSansJP-Subset.woff2',
    get_stylesheet_directory_uri() . '/fonts/Inter-Subset.woff2',
  );
  foreach ($fonts as $url) {
    echo '<link rel="preload" href="' . esc_url($url) . '" as="font" type="font/woff2" crossorigin>' . "\n";
  }
}
add_action('wp_head', 'child_preload_fonts', 1);

ポイント

  • すべてをpreloadせず、LCP要素に必要なものだけにする

📊 計測と検証

作業が終わったら効果を測ります。感覚ではなく、ツールと実機で確かめます。

📈 確認方法

  • PageSpeed InsightsでLCPとCLSを比較
  • Chrome DevToolsでフォント取得の順序と所要時間を確認
  • 実機で日本語の字間や英数字の表示をチェック

⚠️ よくある失敗

  • サブセットが小さすぎて必要文字が不足する
  • paltを外して字間が不自然になる
  • preloadの入れすぎで他リソースが遅くなる

✅ まとめ

  • Interは英数記号、Noto Sans JPは日本語という役割分担で軽量化
  • pyftsubsetで必要文字だけを残し、WOFF2で出力
  • paltを残して字間を自然にする
  • 子テーマに配置して読み込み、必要に応じてpreloadで前倒し
  • ウェイトが限られるなら静的フォントのほうが軽い
  • 計測と実機確認で効果を見てから本番適用

✨ あなたのサイトの“困った”を一緒に解決します

記事を読んで「自分でも試したいけど少し不安…」「専門的なアドバイスがあると助かる」と感じた方へ。
ココナラでは、WordPressカスタマイズやWebサイト改善の個別サポートを行っています。

デザインのちょっとした修正から、日々のサイト運営の相談、SEOや集客の見直しまで。
アフィリエイターさんや個人事業主、中小企業の方まで、幅広くご相談いただいています。
まずはお気軽にお問い合わせください。

👉 ココナラで相談してみる

yuu8x

ちょっと便利なChrome拡張を、月2本ペースでコツコツ開発しています ⚒️
個人開発は2025年の秋からスタート。右も左もわからない中、GPTと二人三脚で試行錯誤中です。
同じように個人開発をしている方、先輩の皆さん、どうぞよろしくお願いします 🤝

お得・便利・ライフハックが大好物。
アイデア・感想・バグ報告など、Xで気軽に声をかけてもらえると励みになります 🌱

ふだんはフリーで企業のWeb担当をしながら、妻娘たちと田舎で静かに暮らしています。
心穏やかに、健康に過ごすのが目標です。

Follow Me
Webフォント
タイトルとURLをコピーしました