Webフォントを正しく読み込む方法:font-familyの書き方から表示速度対策まで
Webフォントを使うには、フォントを読み込む設定と、読み込んだフォントを要素へ適用する設定の両方が必要です。
外部サービスならHTMLの<link>、自分で配信するならCSSの@font-faceで読み込み、最後にfont-familyで使用するフォントを指定します。ただし、フォントファイルを増やしすぎると表示が遅れ、読み込み後の文字幅の変化でレイアウトが動くこともあります。
この記事では、2026年7月時点の主要なモダンブラウザを対象に、次の内容を実際のコードで整理します。
font-familyと@font-faceの役割の違い- Google Fontsを使う最小構成
- WOFF2ファイルを自分のサーバーから配信する方法
font-display、preconnect、preloadの使い分け- フォントが反映されないときの確認手順
- 表示速度とレイアウトずれを抑える設計
最初に理解したい2つの役割
font-familyだけでは、手元にないフォントを自動取得できません。 Webフォントでは「どこから取得するか」と「どこに使うか」を分けて考えます。
font-familyは使用候補を指定する
font-familyは、ブラウザにフォントの優先順位を伝えるCSSプロパティです。
body {
font-family: "Noto Sans JP", "Hiragino Kaku Gothic ProN", "Yu Gothic", sans-serif;
}
ブラウザは左から順番に使用できるフォントを探します。最初の候補が利用できなければ次へ進み、最後はsans-serifのような総称フォントへ切り替えます。
MDNのfont-familyリファレンスによると、フォントの選択は文字単位でも行われます。先頭のフォントに日本語の字形がなければ、その文字だけ後続のフォントで表示される場合があります。
フォント指定では、次の2点を守るとトラブルを減らせます。
- 空白を含む固有のフォント名は引用符で囲む
- リストの最後に
serif、sans-serif、monospaceなどの総称フォントを置く
/* 推奨 */
.page-title {
font-family: "Example Sans", sans-serif;
}
/* 非推奨:代替候補がない */
.page-title {
font-family: "Example Sans";
}
総称フォントは引用符で囲みません。"sans-serif"とすると、総称キーワードではなく、その名前を持つ固有フォントとして解釈されます。
linkや@font-faceはフォントを利用可能にする
閲覧者の端末にないフォントを使うには、ブラウザが取得できる場所を指定します。主な方法は次の2つです。
- Google Fontsなどが配信するCSSを
<link>で読み込む - 自分のサーバーに置いたフォントを
@font-faceで登録する
ここがポイント: 読み込み設定だけでは画面に適用されず、
font-familyだけではフォントファイルを取得できません。Webフォントには両方の設定が必要です。
Google Fontsをlinkで読み込む
初心者がまず試すなら、提供された<link>をHTMLへ追加する方法が簡単です。 フォントファイルの変換や配信設定を自分で行う必要がありません。
ここでは例として、本文に「Noto Sans JP」を使用します。
HTMLに読み込み用のlinkを書く
<head>内へ次のコードを追加します。
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap"
rel="stylesheet"
>
<link rel="stylesheet" href="style.css">
</head>
preconnectは、フォントを取得する外部サーバーとの接続を早めに始めるための指定です。Google FontsではCSSとフォントファイルの配信元が異なるため、2つの接続先が登場します。
crossoriginは、別オリジンにあるフォントをCORSモードで取得するために必要です。値を省略したcrossoriginはcrossorigin="anonymous"と同じ扱いになります。
CSSでフォントを適用する
読み込み後は、通常のCSSと同じように指定できます。
body {
margin: 0;
font-family: "Noto Sans JP", sans-serif;
font-weight: 400;
line-height: 1.8;
}
h1,
h2,
h3 {
font-weight: 700;
}
この例で要求している太さは400と700だけです。使わない太さまで読み込むと転送量が増えるため、最初は本文用と見出し用に絞るのが実務的です。
Google Fonts CSS APIの公式ガイドでは、familyでフォントと太さを指定し、displayパラメーターで読み込み中の表示方法を設定できます。
入力と表示結果
次のHTMLを表示してみます。
<h1>サービスのお知らせ</h1>
<p>メンテナンスは7月30日の午前2時から実施します。</p>
期待される結果は次のとおりです。
- 見出しはNoto Sans JPの太字
700 - 本文は同フォントの標準ウェイト
400 - 読み込みに失敗した場合は
sans-serif系の代替フォント
フォント名の指定だけでなく、実際に読み込んだウェイトとCSSのfont-weightが対応している点が重要です。
フォントファイルを自分のサーバーから配信する
配信元、キャッシュ方針、利用するファイルを管理したい場合は、@font-faceによるセルフホスティングが向いています。 外部フォントサービスへの接続を避けたいサイトでも選択肢になります。
最小のディレクトリ構成
project/
├── index.html
├── style.css
└── fonts/
├── example-sans-regular.woff2
└── example-sans-bold.woff2
フォントをサーバーへ置く前に、ライセンスがWeb配信やファイル変換を認めているか確認してください。デスクトップ版を購入していても、Webフォントとしての配信権が含まれるとは限りません。
@font-faceで太さごとに登録する
@font-face {
font-family: "Example Sans";
src: url("./fonts/example-sans-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Example Sans";
src: url("./fonts/example-sans-bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: "Example Sans", sans-serif;
font-weight: 400;
}
h1 {
font-weight: 700;
}
@font-face内のfont-familyは、以後のCSSから参照するための名前です。同じ名前を通常のfont-familyで使います。
font-weightとfont-styleには、そのファイルが実際に収録している値を指定します。通常のファイルを700として登録すると、ブラウザは中身を太字として扱うため、ファイルと設定の対応を崩さないでください。
MDNのWebフォント解説でも、同じファミリー名を使いながら、ウェイトやスタイルごとに@font-faceを定義する方法が説明されています。
WOFF2を優先する理由
モダンブラウザ向けの新規実装では、通常は圧縮効率のよいWOFF2を第一候補にできます。MDNのWOFF解説によると、WOFFとWOFF2の主な違いは圧縮アルゴリズムです。
古い環境まで対応する必要がある場合は、アクセス解析やプロジェクトの対応ブラウザ方針を確認してから、WOFFなどの追加形式を検討します。念のため全形式を読み込むのではなく、対象環境から判断するのが基本です。
font-displayで「文字が見えない時間」を制御する
本文では、まずswapかoptionalを検討すると判断しやすくなります。 どちらが適切かは、必ずWebフォントを見せたいのか、表示の安定を優先するのかで変わります。
font-displayは、フォントの取得が終わっていない間にブラウザが文字をどう表示するかを指定する@font-faceの記述子です。MDNのfont-displayリファレンスでは、auto、block、swap、fallback、optionalの5値が定義されています。
swap:文字を早く見せたい
@font-face {
font-family: "Example Sans";
src: url("./fonts/example-sans-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
swapでは、Webフォントが届くまで代替フォントで文字を表示し、取得後に切り替えます。本文が見えない時間を抑えられる一方、2つのフォントで文字幅が違うと、改行位置や要素の高さが変わる可能性があります。
optional:安定した表示を優先したい
optionalでは、Webフォントが短時間で利用できなければ、そのページでは代替フォントの表示を維持する場合があります。フォントの切り替えによるレイアウトずれを避けやすい反面、通信状況によっては指定したWebフォントが表示されません。
@font-face {
font-family: "Example Sans";
src: url("./fonts/example-sans-regular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: optional;
}
web.devのフォント最適化ガイドは、表示速度、Webフォントの確実な適用、レイアウトの安定性にトレードオフがあると説明しています。
使い分けの目安は次のとおりです。
- ニュース、ヘルプ、業務画面など、文章をすぐ読ませたい:
swap - 本文の安定表示を優先し、環境によって代替フォントでもよい:
optional - ロゴに近い見出しなど、書体そのものが重要:専用画像やSVGも含めて検討
- アイコン:アイコンフォントだけに頼らず、意味が崩れにくいSVGを検討
読み込み速度を落とさない設計
効果が大きいのは、読み込むフォントファイルそのものを減らすことです。 最適化用タグを増やす前に、ファミリー、ウェイト、スタイルを絞ります。
読み込む太さを必要最小限にする
本文で400、見出しで700しか使わないなら、300、500、600、900まで一括で要求する必要はありません。
たとえば、次の設計から始めます。
- 本文:400
- 見出し:700
- 斜体:実際に使う場合だけ追加
- 別ファミリー:ロゴや特定箇所に必要な場合だけ追加
日本語フォントは収録する文字数が多いため、ファイル数を増やす判断は慎重に行います。
preloadは重要なファイルだけに使う
ファーストビューで確実に使うセルフホストのフォントは、HTMLから先読みできます。
<link
rel="preload"
href="/fonts/example-sans-regular.woff2"
as="font"
type="font/woff2"
crossorigin
>
MDNのpreloadリファレンスでは、フォントの先読みにはas="font"とcrossoriginが必要と説明されています。これは同一オリジンに置いたフォントでも付けるのが基本です。
ただし、preloadは「すべてのフォントを高速化する指定」ではありません。ブラウザがほかの重要なリソースへ使える帯域を消費するため、通常は本文の標準ウェイトなど、最初の画面で確実に使うファイルへ限定します。
次のような使い方は避けます。
<!-- 使うか分からない全ウェイトを先読みしている -->
<link rel="preload" href="/fonts/example-300.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/example-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/example-500.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/example-700.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/example-900.woff2" as="font" type="font/woff2" crossorigin>
外部配信ではpreconnectを使いすぎない
preconnectは、第三者配信元とのDNS検索や接続確立を前倒しできます。しかし、接続先を大量に指定すると、その準備自体が負担になります。
Google Fontsのように実際に初期表示で使う接続先へ絞り、ページの下部でしか使わないサービスまで一律に指定しないようにします。
@importよりlinkを優先する
Google FontsはCSSの@importでも読み込めます。
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap");
動作はしますが、ブラウザはCSSを取得して解析した後で、さらに外部CSSを見つけることになります。HTMLの<head>から<link rel="stylesheet">で直接知らせるほうが、一般に早く発見できます。
よくある失敗と直し方
反映されないときは、CSSを何度も書き換える前に、フォントの通信と適用結果を分けて確認します。 ChromeやEdge、Firefoxの開発者ツールが役立ちます。
フォント名が一致していない
@font-face {
font-family: "Example Sans";
src: url("./fonts/example.woff2") format("woff2");
}
/* NG:登録名と異なる */
body {
font-family: "ExampleSans", sans-serif;
}
空白の有無を含め、@font-faceで登録した名前と使用側を一致させます。
body {
font-family: "Example Sans", sans-serif;
}
相対パスの基準を間違えている
CSS内のurl()は、通常、そのCSSファイルが置かれている場所を基準に解決されます。
assets/
├── css/
│ └── style.css
└── fonts/
└── example.woff2
この構成なら、style.cssからの指定は次のようになります。
src: url("../fonts/example.woff2") format("woff2");
開発者ツールのNetworkパネルで、フォントのリクエストが404になっていないか確認してください。
読み込んでいないウェイトを指定している
400のファイルしか登録していないのにfont-weight: 700を指定すると、ブラウザが疑似的に太く見せる場合があります。見た目が意図と違うだけでなく、環境による差も生まれます。
太字を使うなら、対応するファイルを登録します。
@font-face {
font-family: "Example Sans";
src: url("./fonts/example-bold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
crossoriginやサーバー設定に問題がある
別ドメインからフォントを配信する場合、配信サーバー側が適切なCORSレスポンスヘッダーを返す必要があります。ブラウザのコンソールにCORSエラーが出ていれば、CSS側だけでは解決できません。
確認する項目は次のとおりです。
- フォントURLを直接開けるか
- Networkパネルのステータスが
200か - レスポンスのContent-Typeがフォントに適しているか
- 別オリジンなら許可されたCORSヘッダーが返るか
- preloadのURLとCSSの
srcが完全に一致しているか
CSSの優先順位で上書きされている
フォントが正常に取得できても、より強いセレクターや後から読み込まれたCSSに上書きされることがあります。
body {
font-family: "Example Sans", sans-serif;
}
.article p {
font-family: serif;
}
この場合、.article内の段落にはserifが適用されます。開発者ツールのComputedパネルで、最終的なfont-familyと、どのCSSルールが採用されたかを確認します。
システムフォントとの使い分け
ブランド固有の書体が不要なら、Webフォントを読み込まない設計も有力です。 通信が発生せず、文字をすぐ表示できます。
body {
font-family: system-ui, sans-serif;
}
主な使い分けは次のようになります。
Webフォントが向く場面
- ブランドの書体を複数のOSで統一したい
- 見出しやキャンペーンページで書体の個性が重要
- 特定の字形やウェイトを確実に利用したい
システムフォントが向く場面
- 管理画面や業務ツールで表示速度を優先したい
- OSになじむUIを作りたい
- フォント配信やライセンス管理を増やしたくない
ただし、system-uiで実際に使われる書体はOSによって変わります。長文記事では、環境差を確認したうえでsans-serifや特定のローカルフォントを含むスタックと比較してください。
実装前後のチェックリスト
公開前には「表示されたか」だけでなく、失敗時と低速時も確認します。 Webフォントは通信に依存するため、開発環境で一度表示できただけでは十分ではありません。
- フォントの利用ライセンスを確認した
font-familyの最後に総称フォントを指定した- 使用するウェイトとスタイルだけを読み込んだ
font-displayを目的に合わせて選んだ- フォントURLが
200で応答している - 別オリジン配信のCORSエラーがない
- preloadを初期表示に必要なファイルへ限定した
- 低速通信でも本文が読める
- Webフォントへの切り替えでボタンや見出しが大きく動かない
- 日本語、英数字、記号、太字を実データで確認した
最初の実装では、本文用の1ファミリーと2ウェイト程度に絞り、font-display: swapと代替フォントを設定するのが試しやすい構成です。そのうえで開発者ツールのNetworkパネルを低速通信に切り替え、文字の表示開始とレイアウトの動きを確認します。
フォントを追加する判断は、その後です。新しいウェイトを1つ増やすたびに通信量も増えるため、デザイン上の違いが実際の読みやすさやブランド表現に必要かを確かめてください。
