by MintJams

サーバーの思考を先に読め!103 Early HintsとfetchpriorityでLCPを爆速化する

サーバーの「思考時間」を有効活用する103 Early Hintsと、リソースの取得優先度を制御するfetchpriorityを組み合わせ、LCPを劇的に改善する具体的な実装方法を解説します。

ウェブサイトの表示速度は、ユーザー体験とSEOの双方に大きな影響を与えます。特にLCP(Largest Contentful Paint)、つまりページのメインコンテンツが描画されるまでの時間は、サイトの第一印象を決めると言っても過言ではありません。

LCPを改善する上で最大の課題の一つが、「サーバー側の思考時間」です。サーバーがコンテンツを生成するまでの間、ブラウザは何もできず待機するしかありませんでした。しかし、この無駄な時間を有効活用する仕組みが103 Early Hintsです。

本記事では、この103 Early Hintsと、リソースの取得優先度をコントロールするfetchpriorityを組み合わせ、LCPを劇的に改善するための実践的な方法を解説します。


この記事でわかること

  • 103 Early Hintsがウェブページの表示速度を改善する仕組み
  • CDNや最新のサーバー(Node.js, Nginx)での具体的な有効化方法
  • fetchpriorityを使ってLCP画像の読み込みを最優先にする方法
  • 実装時の注意点、ブラウザ対応状況、そしてデバッグ方法

1. サーバーの「思考時間」を有効活用する103 Early Hints

ウェブページをリクエストすると、サーバーはHTMLを生成し、200 OKというステータスコードと共にレスポンスを返します。しかし、複雑な処理が必要なページでは、このHTML生成に数秒かかることがあります。

103 Early Hintsは、サーバーが200 OKを返す前に、103 Early Hintsというステータスコードと共にLinkヘッダーだけを先行して送信する仕組みです。

これにより、ブラウザは最終的なレスポンスを待つことなく、Linkヘッダーで指定されたCSS、JavaScript、画像、フォントなどの重要リソースの読み込みをすぐに開始できます。サーバーの「思考時間」が長ければ長いほど、この効果は大きくなります。

Early Hintsの対象と制限

103 Early Hintsは、以下の点に注意して利用しましょう。

  • 対象: トップレベルのナビゲーション(ブラウザのアドレスバーにURLを入力したり、リンクをクリックしたりする操作)への応答のみで有効です。
  • 利用可能なヘッダー: 103 Early Hintsで指定できるのは、主にrel=preloadrel=preconnectです。prefetchなどはサポートされていません。
  • リダイレクト: クロスオリジンへのリダイレクトが最終応答で発生した場合、ブラウザはEarly Hintsで取得したリソースを破棄します。

CDNでの有効化が最も手軽

多くの主要CDN(Cloudflare, Fastly, Akamaiなど)がEarly Hintsをサポートしています。最も手軽なのは、これらのCDNの設定画面からEarly Hintsを有効化することです。

例えばCloudflareでは、公式ドキュメントに従って設定するだけで有効化できます。


2. 実装パターン:最新のサーバー環境で103を送る

Node.js(Express.js)の場合

Node.js v18.11以降では、response.writeEarlyHints()という専用APIが用意されています。複数のLinkヘッダーは配列で渡すのが推奨される方法です。

// Node.js (v18.11+) Express.jsのミドルウェア
app.use((req, res, next) => {
  const links = [
    '</styles.css>; rel=preload; as=style',
    '</images/lcp-hero.jpg>; rel=preload; as=image'
  ];
  // 103 Early Hints を送信
  res.writeEarlyHints({ link: links });
  next();
});

注意: linkキーは小文字で記述し、値は文字列または配列で渡します。

Nginxの場合

Nginx 1.29.0以降では、early_hintsという専用ディレクティブが追加され、バックエンドからのEarly Hintsをプロキシできるようになりました。

HTTP/1.1クライアントではプロトコルエラーが発生する可能性があるため、HTTP/2 / HTTP/3クライアントにのみ送信するのがベストプラクティスです。

# nginx.conf の http, server, locationブロック内で設定
# HTTP/2/3クライアントにのみEarly Hintsを許可
map $http_sec_fetch_mode $send_early_hints {
    default 0;
    navigate 1;  # トップレベルナビゲーションのみを対象
}

server {
    listen 443 ssl http2;
    # http3 も有効にする場合はlisten 443 quic; 等を追加

    location / {
        early_hints $send_early_hints;
        proxy_pass http://backend;
    }
}

キャッシュ前提の注意

Early Hintsで指定するリソースは、ブラウザのHTTPキャッシュに保存されます。このキャッシュが最終レスポンスで再利用されるため、Cache-Controlヘッダーを適切に設定し、二重取得を避けるようにしましょう。


3. リソースの優先度を制御するfetchpriority

103 Early Hintsでリソースの読み込みを早く開始しても、ブラウザはリソースの「取り合い」をします。CSSやJavaScript、画像が同時に読み込まれる際、LCP画像などの本当に重要なリソースに優先度を与えるのがfetchpriorityです。

fetchpriorityは、<img>, <link>, <script>タグに設定できる属性で、high, low, autoの3つの値を持ちます。

説明
high LCP画像など、重要なリソースに設定。ブラウザのデフォルト優先度よりも高くして、いち早く読み込ませます。
low ページの表示に必須ではないリソース(非同期のスクリプトなど)に設定。
auto デフォルト値。ブラウザの判断に任せます。

fetchpriorityの実装例

<img src="/images/hero.jpg" width="1200" height="800" fetchpriority="high" alt="ヒーロー画像">

<img src="/images/gallery-item.jpg" width="600" height="400" loading="lazy" fetchpriority="low" alt="ギャラリー画像">

<link rel="preload" as="image" href="/images/background.jpg" fetchpriority="high">

<script src="/js/analytics.js" async fetchpriority="low"></script>

Next.jsでの注意点 Next.jsの<Image>コンポーネントのpriorityプロパティは、プリロードを指示するもので、fetchpriority="high"を付与するかはバージョンに依存します。確実に制御したい英雄画像は、<img fetchpriority="high"><link rel="preload">を明示的に記述するのが最も確実です。React/Nextでは属性名を小文字のfetchpriorityにしましょう。

fetchpriorityの落とし穴

  • ヒントであって規則ではない: fetchpriorityはあくまでブラウザへのヒントです。最終的な優先度はブラウザのヒューリスティクスで決定されます。
  • やりすぎ注意: fetchpriority="high"を多用すると、ブラウザのリソース競合が悪化し、かえってLCPが悪化する可能性があります。本当に必要な1~2点に絞りましょう。
  • ブラウザ対応: 主要ブラウザはfetchpriorityをサポートしていますが、Safariは現状rel=preconnectのみの対応です。

4. 計測とデバッグ:効果を可視化する

設定が正しく機能しているかを確認するには、ブラウザのDevToolsが不可欠です。

  • Chrome DevTools -> Networkタブ:

    • 103 Early Hintsで読み込まれたリソースには、Initiator列にearly-hintsと表示されます。また、リクエストの詳細でEarly Hints Headersを確認できます。
    • fetchpriorityで変更された優先度は、Priority列で確認できます。
  • cURLでの確認: 103レスポンスが正しく送信されているかは、cURLコマンドで簡単に確認できます。

    curl -L -s -o /dev/null -D - https://example.com

    実行結果の先頭に、"HTTP/2 103 Early Hints"Linkヘッダーが表示されていれば成功です。


まとめ:103 Early Hintsfetchpriorityのチェックリスト

この記事で解説した内容を、以下のチェックリストで確認しましょう。

  • サーバー(またはCDN)が103 Early Hintsを送信する設定になっている。
  • HTTP/2/3クライアントにのみEarly Hintsを送る設定を入れている。
  • Early HintsのLinkヘッダーには、LCPに影響する最重要リソース(CSS、フォント、画像)を含めている。
  • Early Hintsで指定するリソースに、適切なCache-Controlを設定している。
  • LCP画像にはfetchpriority="high"を指定し、優先度を上げている。
  • DevToolsを使って、103 Early Hintsfetchpriorityが正しく機能しているか検証する。

この記事が、あなたのウェブサイトのLCP改善の一助となれば幸いです。ご覧いただきありがとうございました。