ナビゲーションをスキップ
部 IV 章 21

リソースヒント

序章

過去10年間で、リソースヒントは、開発者がページのパフォーマンスを向上させ、その結果としてユーザー体験を向上させるために不可欠なプリミティブとなりました。

リソースのプリロードや、ブラウザによるインテリジェントな優先順位付けは、実は2009年にIE8がプリローダーと呼ばれるものを使って始めたことでした。IE8には、HTMLパーサーに加えて、ネットワーク リクエストを開始する可能性のあるタグ (<script><link><img>) をスキャンする軽量のルックアヘッド プリローダーが搭載されていました。

その後の数年間、ブラウザのベンダーがより多くの作業を行い、それぞれがリソースの優先順位の付け方について独自の特別なソースを追加しました。しかし、ブラウザだけでは限界があることを理解することが大切です。開発者である私たちはリソースヒントをうまく利用してリソースの優先順位を決定したり、ページのパフォーマンスをさらに向上させるためにどのリソースをフェッチしたり、前処理したりするべきかを判断することでこの限界を克服できます。

とくに、昨年達成したリソースのヒントをいくつか挙げます。

  • CSS-Tricks Webフォントが3Gの初回レンダリングでより速く表示されるようになりました。
  • リソースヒントを使用したWix.comでは、FCPで10%の改善が見られました。
  • Ironmongerydirect.co.ukは、preconnectを使用して、製品画像の読み込みを中央値で400ms、95パーセンタイルで1秒以上改善しました。
  • Facebook.comは、ナビゲーションを高速化するためにpreloadを使用していました。

今日、ほとんどのブラウザでサポートされている主なリソースヒントを見てみましょう。dns-prefetchpreconnectpreloadprefetch、そしてネイティブの遅延ローディングです。

個々のヒントに取り組む際には、WebVitalsPerfume.jsなどのライブラリや、Web Vitalsのメトリクスをサポートするその他のユーティリティを使用して、常に現場での前後の影響を測定することをオススメします。

dns-prefetch

dns-prefetch は、指定されたドメインのIPアドレスを事前解決するのに役立ちます。利用可能なもっとも古いリソースヒントとして、preconnectと比較して最小限のCPUとネットワークリソースを使用し、ブラウザがDNS解決のための 1秒以上の「最悪のケース」の遅延を経験しないことに役立ちます。

<link rel="dns-prefetch" href="https://www.googletagmanager.com/">

dns-prefetchを使用する際には注意が必要です。軽量であっても、ブラウザが許容する同時進行のDNSリクエスト数の制限を簡単に超えてしまうからです(Chromeにはまだ6の制限があります)。

preconnect

preconnectは、指定されたドメインのIPアドレスを事前に解決し、TCP/TLS接続を開くのに役立ちます。dns-prefetchと同様に、クロスオリジンのドメインに使用され、最初のページ読み込み時に使用されるリソースをブラウザがウォームアップするのに役立ちます。

<link rel="preconnect" href="https://www.googletagmanager.com/">

preconnectを使用する際には注意が必要です。

  • もっとも頻度の高い、重要なリソースのみを温めます。
  • 最初の負荷をかける際に、使用したオリジンのウォームアップが遅すぎないようにする。
  • CPUやバッテリーのコストが、かかる場合があるので、3つ以下のoriginで使用してください。

最後に、preconnectInternet ExplorerやFirefoxでは利用できませんので、予備としてdns-prefetchを利用することを強くオススメします。

preload

preload ヒントは、早期のリクエストを開始します。これはパーサーが、発見するのが遅れるような重要なリソースを読み込むのに便利です。

<link rel="preload" href="style.css" as="style">
<link rel="preload" href="main.js" as="script">

preloadすることを意識します。なぜなら他のリソースのダウンロードを遅らせる可能性があるため、Largest Contentful Paint(LCP)の改善に役立つ、もっとも重要なものにのみ使用してください。 また、Chromeで使用した場合、preloadリソースを過剰に優先する傾向があり、他の重要なリソースよりもpreloadを優先的に処理する可能性があります。

最後に、HTTPレスポンスヘッダーで使用された場合、一部のCDNはpreloadを自動的にHTTP/2 pushに変えてしまい、キャッシュされたリソースを過剰にプッシュしてしまうことがあります。

prefetch

prefetchヒントを使用すると、次のナビゲーションで使用されると予想される低優先度のリクエストを開始できます。このヒントは、リソースをダウンロードして、あとで使用するためHTTPキャッシュにドロップします。重要なのは、prefetchはリソースの実行やその他の処理を行わず、実行するにはページが<script>タグでリソースを呼び出す必要があるということです。

<link rel="prefetch" as="script" href="next-page.bundle.js">

リソースの予測ロジックを実装する方法はさまざまで、ユーザーのマウスの動きや一般的なユーザーフロー/ジャーニーなどの信号に基づいたり、機械学習の上に両者を組み合わせたりすることもできます。

使用しているCDNのHTTP/2の優先順位付けの品質によっては、prefetchの優先順位付けがパフォーマンスを向上させることもあれば、prefetchのリクエストを過剰に優先させ、最初のロードのために重要な帯域を奪い、パフォーマンスを低下させることもあることに注意してください。使用しているCDNを再確認し、Andy Davies氏の記事で紹介されているベストプラクティスを考慮に入れてください。

ネイティブの遅延読み込み

ネイティブの遅延読み込みのヒントは、画面外の画像やiframeの読み込みを延期するためのネイティブブラウザAPIです。これを使用することで、最初のページロード時に必要のないアセットはネットワークリクエストを開始しないため、データ消費量が削減され、ページパフォーマンスが向上します。

<img src="image.png" loading="lazy" alt="" width="200" height="200">

留意点:Chromiumの遅延読み込みのしきい値ロジックの実装は、これまで保守的で、画面外の制限を3000pxに保っていました。昨年この制限は積極的にテストされ、開発者の期待に沿うように改善され、最終的にしきい値を1250pxに変更しました。また、ブラウザ間の標準はなく、ウェブ開発者がブラウザの提供するデフォルトしきい値を上書きする機能はまだありません。

リソースのヒント

HTTP Archiveをもとに、2020年のトレンド分析に飛び込み、前回の2019年のデータセットと比較してみましょう。

ヒントの採用

ますます多くのウェブページがメインリソースのヒントを使用しており、2020年にはデスクトップとモバイルの間で一貫した採用が行われると見られています。

図21.1. リソースヒントの採用

dns-prefetchの採用率が33%と他のリソースヒントに比べて相対的に高いのは、2009年にはじめて登場し主要なリソースヒントの中でもっとも広くサポートされていることから、当然のことと言えるでしょう。

2019と比較すると、dns-prefetchはDesktopの採用率が4%増加していました。また、preconnectでも同様の増加が見られました。すべてのヒントの中でもっとも大きな伸びを示した理由の1つは、Lighthouse auditがこの問題に関して明確で有益なアドバイスをしていることです。今年のレポートからは、最新のデータセットがLighthouseの推奨事項に対してどのようなパフォーマンスを示すかについても紹介しています。

図21.2. リソースヒントの採用2019年対2020年

preloadの使用率は2019年から2%の増加にとどまり、伸び悩んでいます。これは、もう少し多くの指定を必要とすることが一因と考えられます。dns-prefetchpreconnectを使用するにはドメインが必要なだけですが、preloadを使用するにはリソースを指定する必要があります。dns-prefetchpreconnectは悪用される可能性があるものの、それなりにリスクが低いのに対し、preloadは間違った使い方をすると、実際パフォーマンスにダメージを与える可能性がはるかに大きいのです。

prefetchはデスクトップの3%のサイトで使用されており、リソースヒントの中でもっとも使用されていないものです。この使用率の低さは、prefetchが現在のページロードではなく、その後のページロードを改善するために有用であるという事実から説明できるかもしれません。そのため、サイトがランディングページや最初に表示されるページのパフォーマンスを向上させることだけに注力している場合には、見落とされてしまいます。今後数年間で、後続のページのエクスペリエンスを向上させるために何を測定すべきかがより明確に定義されれば、チームが到達すべき明確なパフォーマンス品質目標を持ってprefetchの採用を優先するのに役立つでしょう。

ページあたりのヒント

全体的に開発者はリソースヒントの上手な使い方を学んでおり、2019と比較すると、preloadprefetchpreconnectの使用率が向上していることがわかります。preloadやpreconnectなどの高価な操作では、デスクトップでの使用量の中央値が2から1に減少しました。一方、prefetchで優先度の低い将来のリソースをロードする場合は、ページあたりの中央値が1から2に増加しました。

図21.3. 1ページあたりのヒント数の中央値

リソースヒントは、選択的に使用されるときにもっとも効果的です(「すべてが重要なとき、何も重要ではない」)。どのリソースが重要なレンダリングの改善に役立つのか将来のナビゲーションの最適化に役立つのかをより明確に定義することで、リソースの優先順位付けの一部を変更し、最初ユーザーにもっとも役立つもののために帯域幅を解放することで、preconnectの使用からprefetchへと焦点を移すことができます。

あるページでは、ヒントを動的に追加し、20k以上の新しいプリロードを作成する無限ループを引き起こしていることが判明しました。これはpreloadヒントの誤用を阻止していません。

図21.4. 1つのページでもっとも多くのプリロードヒントを提供しています。

リソースヒントを使った自動化がますます進む中、プリロードヒントやその他の要素を動的に注入する際には注意が必要です。

as属性

preloadprefetchでは、as属性を使用して、ブラウザがリソースの優先順位をより正確に判断できるようにすることが重要です。そうすることで将来のリクエストに備えてキャッシュに適切に保存し、正しいコンテンツセキュリティポリシー(CSP)を適用し、正しいAcceptリクエストヘッダーを設定できます。

preloadでは、さまざまなコンテンツタイプをプリロードできます。完全なリストは、Fetch specで推奨されているものにしたがっています。もっとも人気があるのは、64%の使用率を誇る script タイプです。これはシングルページアプリとして構築されたサイトの大部分が、残りのJS依存ファイルのダウンロードを開始するために、できるだけ早くメインバンドルを必要としていることに関連していると考えられます。その後の使用率は、fontが8%、styleが5%、imageが1%、fetchが1%となっています。

図21.5. モバイルのas属性の値を年ごとに表示します。

2019の傾向と比較すると、as属性でのフォントやスタイルの使用が急激に増加しています。これは、開発者が重要なCSSの優先度を上げていることや、改善のためにpreloadフォントをdisplay:optionalと組み合わせて、Cumulative Layout Shift(CLS)を実現していることに関連していると考えられます。

as属性が省略されていたり無効な値が設定されていると、ブラウザが正しい優先順位を判断することが難しくなりスクリプトなどの場合には、リソースが2回取得されることもあるので注意が必要です。

crossorigin属性

フォントなどのCORSが有効になっているpreloadpreconnectのリソースでは、そのリソースを適切に使用するためにcrossorigin属性を含めることが重要です。crossorigin属性がない場合、リクエストはシングルオリジンのポリシーに従いますので、preloadの使用は無意味になります。

16.96%
図21.6. preloadを持つ要素のうち、crossoriginを使用する割合です。

最近の傾向としては、preloadを行う要素のうち、crossoriginを設定し、anonymous(またはそれに準ずる)モードで読み込むものが16.96%、use-credentialsを利用するものは0.02%にとどまっています。前述のフォントプリロードの増加に伴い、この割合も増加しています。

<link rel="preload" href="ComicSans.woff2" as="font" type="font/woff2" crossorigin>

crossorigin属性を持たずにプリロードされたフォントは、2回取得されてしまうことに注意してください。

media属性

異なるスクリーンサイズで使用するリソースを選択する際には、media属性と preloadを使用して、メディアクエリを最適化してください。

<link rel="preload" href="a.css" as="style" media="only screen and (min-width: 768px)">
<link rel="preload" href="b.css" as="style" media="screen and (max-width: 430px)">

2020年のデータセットでは、メディアクエリの組み合わせが2,100通り以上あることから、レスポンシブデザインのコンセプトと実装の間にサイトごとの差異がどれだけあるかを考えてみました。データには、Bootstrapなどでおなじみのブレークポイント767px/768pxも含まれています。

ベストプラクティス

リソースヒントの使い方は、時に混乱を招くので、Lighthouseの自動監査に基づいて従うべき簡単なベストプラクティスを説明します。

dns-prefetchpreconnectを安全に実装するには、それらを別々のリンクタグにしてください。

<link rel="preconnect" href="http://example.com">
<link rel="dns-prefetch" href="http://example.com">

同じ<link>タグ内にdns-prefetchフォールバックを実装すると、Safariでバグが発生し、preconnectリクエストがキャンセルされてしまいます。2%近いページ(~40k)で、1つのリソースにpreconnectdns-prefetchの両方が存在するという問題が報告されました。

Preconnect to required origins“の監査の場合、テストに合格したページはわずか19.67%で、何千ものウェブサイトがpreconnectdns-prefetchを使用して重要なサードパーティオリジンへの早期接続を確立し始める大きな機会を生み出していました。

19.67%
図21.7. Lighthouseのpreconnect監査に合格したページの割合。

最後に、Lighthouseの”Preload key requests“の監査を実行した結果、84.6%のページがテストに合格しました。はじめてpreloadを使おうとしている人は、フォントやクリティカルスクリプトを覚えておくといいでしょう。

ネイティブの遅延ローディング

今回は、Native Lazy Loading APIの1周年をお祝いしましょう。このAPIは、公開時点ですでに72%のブラウザをサポートしています。この新しいAPIを利用することで、ページ内の折り返し以下のiframeや画像の読み込みを、ユーザーがその近くでスクロールするまで延期できます。これにより、データ使用量やメモリ使用量を削減し、折り返し部分のコンテンツを高速化できます。遅延ロードを有効にするには、<iframe><img>要素にloading=lazyを追加するだけです。

図21.8. ネイティブの遅延ローディングを使用しているページの割合。

とくに、今年初めに発表された公式基準値は保守的すぎ、最近ようやく開発者の期待に応えられる状況です。約72%のブラウザがネイティブ画像/ソースの遅延ローディングをサポートしていることから、とくにローエンドデバイスでのデータ使用量やパフォーマンスを改善したいページにとっては、この分野もチャンスとなります。

Lighthouseの「Defer offscreen images」監査を実行した結果、68.65%のページがテストに合格しました。これらのページでは、すべての重要なリソースのロードが完了した後に、画像を遅延ロードできます。

ビューポートが変わると画像が画面外に出てしまうことがあるので、デスクトップとモバイルの両方で監査を行うように注意してください。

予測型プリフェッチ

prefetchと機械学習を組み合わせることで、後続のページのパフォーマンスを向上させることができます。このソリューションの1つに、Guess.jsがあります。予測型プリフェッチの最初のブレークスルーとなり、すでに10以上のウェブサイトが本番で使用しています。

予測型プリフェッチは、データ分析や機械学習の手法を用いて、データに基づいたプリフェッチのアプローチを提供する手法です。Guess.jsは、一般的なフレームワーク(Angular、Nuxt.js、Gatsby、Next.js)で予測型プリフェッチをサポートしているライブラリで、今日からでも利用できます。Guess.jsは、ページから可能なナビゲーションをランク付けし、次必要になりそうなJavaScriptのみをプリフェッチします。

学習セットにもよりますが、Guess.jsのプリフェッチは90%以上の精度で行われています。

全体的に見ると予測型プリフェッチはまだ未知の領域ですが、マウスオーバー時のプリフェッチやサービスワーカーのプリフェッチと組み合わせることで、ウェブサイトを利用するすべてのユーザーにデータを節約しながら瞬時に体験を提供できる大きな可能性を秘めています。

HTTP/2プッシュ

HTTP/2には「サーバープッシュ」と呼ばれる機能があり、製品のラウンドトリップタイム(RTTs)やサーバーの処理が長い場合に、ページのパフォーマンスを改善できる可能性があります。簡単に説明すると、クライアントがリクエストを送信するのを待つのではなく、クライアントがすぐにリクエストするだろうと予測したリソースをサーバーが先取りしてプッシュするのです。

75.36%
図21.9. preload/nopushを使用したHTTP/2 Pushページの割合です。

HTTP/2 Pushは多くの場合、preloadリンクヘッダーを通して開始されます。2020年のデータセットでは、1%のモバイルページがHTTP/2プッシュを使用しており、そのうち75%のプリロードヘッダーリンクがページリクエストでnopushオプションを使用していました。これはウェブサイトがpreloadリソースヒントを使用していても、大多数はこれだけを使用し、そのリソースのHTTP/2プッシュを無効にすることを好むということです。

HTTP/2 Pushは、正しく使用しないとパフォーマンスを損なう可能性があることを言及しておくことが重要で、これがしばしば無効にされる理由となっています。

このパターンは、重要なリソースをプッシュ(またはプリロード)し、最初のルートをできるだけ早くレンダリングし、残りのアセットをプリキャッシュし、他のルートや重要でないアセットを遅延ロードするというものです。これは、WebサイトがProgressive Web Appであり、キャッシング戦略を改善するためにService Workerを使用している場合にのみ可能です。このようにすることで、それ以降のすべてのリクエストがネットワークに出ることはないので、常にプッシュする必要はなく両方の利点を得ることができます。

サービス・ワーカー

preloadprefetchの両方において、ページがService Workerによって制御されている場合に採用が増えています。これはService Workerがまだアクティブでないときにプリロードすることでリソースの優先順位を向上させたり、将来のリソースをインテリジェントにプリフェッチしてユーザーが必要とする前に、Service Workerにキャッシュできる可能性があるためです。

図21.10. サービスワーカーページでのリソースヒント採用。

デスクトップのpreloadでは47%、prefetchでは10%という優れた採用率となっています。いずれの場合も、Service Workerを使用しない場合の平均的な採用率と比較して、非常に高いデータとなっています。

先に述べたように、リソースヒントとサービスワーカーのキャッシュ戦略をどのように組み合わせるかについては、PRPLパターンが今後重要な役割を果たすことになるでしょう。

未来

ここでは、実験的なヒントをいくつか紹介します。リリースに非常に近いところではPriority Hintsがあり、これはWebコミュニティで積極的に実験されています。また、HTTP/2の103 Early Hintsもありますが、これはまだ初期段階にあり、ChromeやFastlyのような数人のプレイヤーが今後のテストトライアルに向けて協力しています

優先順位のヒント

優先度のヒントはリソースのフェッチの優先度を表現するためのAPIです:高、低、または自動。画像の優先順位を下げたり(カルーセルの中など)、スクリプトの優先順位を変えたり、さらにはフェッチの優先順位を下げたりするのにも使用できます。

この新しいヒントは、HTMLタグとして、またはHTML属性と同じ値を取るimportanceオプションを使ってフェッチリクエストの優先順位を変更することで使用できます。

<!-- リソースの早期取得を開始したいが、同時に優先順位を下げたい -->
<link rel="preload" href="/js/script.js" as="script" importance="low">

<!-- ブラウザが「高」の優先順位をつけている画像ですが、実際にはそれを望んでいません。 -->
<img src="/img/in_view_but_not_important.svg" importance="low" alt="I'm not important!">

preloadprefetchでは、リソースの種類に応じてブラウザが優先順位を設定します。優先度のヒントを使うことで、ブラウザにデフォルトのオプションを変更させることができます。

図21.11. モバイルでのプライオリティ・ヒントの採用率。

Chromeはまだ積極的に実験を行っているため、今のところ0.77%のウェブサイトしかこの新しいヒントを採用しておらず、この記事のリリース時点ではこの機能は保留されています。

もっとも多く使用されているのはscript要素で、これはJSのプライマリファイルやサードパーティファイルの数が増え続けていることからも当然のことです。

図21.12. ヒントのあるモバイルリソースのうち、の優先度を使っている割合です。

データによると、優先度ヒントを使用しているリソースの83%がモバイルで「高い」優先度を使用していますが、さらに注目すべきは「低い」優先度のリソースが16%あることです。

優先度ヒントは「高い」優先度でリソースをより早く読み込ませようとする戦術ではなく、ブラウザが何を優先度から外すべきかを判断し重要なリクエストを先に完了させるため重要なCPUや帯域を返すことで、「低い」優先度によるムダな読み込みを防ぐツールとして明らかな優位性を持っています。

HTTP/2の103 Early Hints

前回、HTTP/2プッシュは、プッシュされるアセットがすでにブラウザのキャッシュにある場合、実際にリグレッションを引き起こす可能性があると述べました。103 Early Hintsの提案は、HTTP/2プッシュで約束された同様の利点を提供することを目的としています。潜在的に10倍シンプルなアーキテクチャで、サーバープッシュによる不必要なラウンドトリップという既知のワーストケースの問題に悩まされることなく、長いRTTやサーバー処理に対処します。

現在のところ、Chromiumでは67131010936931096414の問題で会話を追うことができます。

結論

昨年、リソースヒントの採用が増加し、開発者がリソースの優先順位付けや最終的なユーザー体験の多くの側面をより詳細にコントロールするために不可欠なAPIとなりました。しかし、これらは指示ではなくヒントであり、残念ながら最終的な決定権は常にブラウザとネットワークにあることを忘れてはなりません。

確かに、たくさんの要素にそれらを適用すれば、ブラウザはあなたの要求通りに動くかもしれません。あるいは、ヒントを無視して、デフォルトの優先順位が状況に応じて最適な選択であると判断するかもしれません。いずれにしても、これらのヒントをどのように使うのがベストなのか、プレイブックを用意しておきましょう。

  • ユーザー体験のための重要なページを特定する。
  • 最適化すべきもっとも重要なリソースを分析します。
  • 可能な限り、PRPLパターンを採用する。
  • それぞれの導入前と導入後のパフォーマンス体験を測定する。

最後になりましたが、ウェブはすべての人のためにあることを忘れないでください。私たちは、ウェブを守り続け、簡単で摩擦のない体験を構築することに集中しなければなりません。

私たちはすべての人に優れたウェブ体験を提供するために必要なすべてのAPIの提供に、年々少しずつ近づいていることを嬉しく思っていますし、次に何が来るのかを楽しみにしています。

著者