従来のタイミング測定から、Core Web Vitalsのような最新のユーザー中心の指標まで、WebパフォーマンスAPIを深く掘り下げ、パフォーマンスの全体像を把握する方法を解説します。
時計の向こうへ:WebパフォーマンスAPIを実際のユーザーエクスペリエンスに結びつける
デジタル経済において、速度は単なる機能ではありません。それはユーザーエクスペリエンスの基盤です。ウェブサイトが遅いと、ユーザーは不満を感じ、離脱率が高くなり、収益に直接的な影響を与えます。長年、開発者はwindow.onload
のようなタイミング指標に頼ってパフォーマンスを評価してきました。しかし、ロード時間が速いことは、本当にユーザーが満足していることを意味するのでしょうか?答えはしばしばノーです。
ページは1秒以内にすべての技術的なリソースのロードを完了できますが、実際に操作しようとしている人にとっては、動作が遅く、使い物にならないと感じることがあります。このずれは、ウェブ開発における重要な進化、つまり技術的なタイミングの測定から、人間の体験の定量化への移行を浮き彫りにしています。現代のウェブパフォーマンスは、Web Performance APIが提供する詳細な低レベルデータと、GoogleのCore Web Vitalsのような高レベルのユーザー中心の指標という、2つの視点の話です。
この包括的なガイドでは、そのギャップを埋めます。診断ツールとして機能する強力なWeb Performance APIスイートを探求します。次に、パフォーマンスが*どのように感じられるか*を教えてくれる、最新のユーザーエクスペリエンス指標を詳しく調べます。最も重要なことは、点と点を結び付け、低レベルのタイミングデータを使用して、グローバルなオーディエンスの貧弱なユーザーエクスペリエンスの根本原因を診断して修正する方法を示すことです。
基盤:WebパフォーマンスAPIを理解する
Web Performance APIは、ウェブページのナビゲーションとレンダリングに関連する非常に詳細で正確なタイミングデータへのアクセスを開発者に提供する、一連の標準化されたブラウザインターフェースです。これらはパフォーマンス測定の基盤であり、単純なストップウォッチを超えて、ネットワークリクエスト、解析、レンダリングの複雑なダンスを理解することができます。
Navigation Timing API:ページの旅
Navigation Timing APIは、メインドキュメントのロードにかかる時間の詳細な内訳を提供します。ユーザーがナビゲーションを開始した瞬間(リンクをクリックするなど)から、ページが完全にロードされる瞬間までのマイルストーンをキャプチャします。これは、ページロードプロセスへの最初で最も基本的なビューです。
このデータには、簡単なJavaScript呼び出しでアクセスできます。
const navigationEntry = performance.getEntriesByType('navigation')[0];
console.log(navigationEntry.toJSON());
これは、タイムスタンプで満たされたオブジェクトを返します。主なプロパティには次のものがあります。
- fetchStart:ブラウザがドキュメントのフェッチを開始したとき。
- responseStart:ブラウザがサーバーから応答の最初のバイトを受信したとき。
fetchStart
とresponseStart
の間の時間は、Time to First Byte(TTFB)と呼ばれることがよくあります。 - domContentLoadedEventEnd:スタイルシート、画像、およびサブフレームのロードが完了するのを待たずに、初期HTMLドキュメントが完全にロードおよび解析されたとき。
- loadEventEnd:ページ(画像、CSSなどを含む)のすべてのリソースが完全にロードされたとき。
長い間、loadEventEnd
がゴールドスタンダードでした。ただし、その制限は深刻です。ユーザーが意味のあるコンテンツを*いつ*見るか、またはページを*操作*できるかについては何も述べていません。それは技術的なマイルストーンであり、人間的なマイルストーンではありません。
Resource Timing API:コンポーネントの分解
ウェブページは、単一のファイルであることはめったにありません。HTML、CSS、JavaScript、画像、フォント、API呼び出しのアセンブリです。Resource Timing APIを使用すると、これらの個々のリソースのそれぞれのネットワークタイミングを検査できます。
これは、ボトルネックを特定するのに非常に強力です。別の大陸にあるコンテンツデリバリーネットワーク(CDN)からの大きく、最適化されていないヒーロー画像が最初のレンダリングを遅くしていますか?サードパーティの分析スクリプトがメインスレッドをブロックしていますか?Resource Timingは、これらの質問に答えるのに役立ちます。
次のように、すべてのリソースのリストを取得できます。
const resourceEntries = performance.getEntriesByType('resource');
resourceEntries.forEach(resource => {
if (resource.duration > 200) { // Find resources that took longer than 200ms
console.log(`Slow resource: ${resource.name}, Duration: ${resource.duration}ms`);
}
});
主なプロパティには、name
(リソースのURL)、initiatorType
(リソースのロードの原因となったもの、たとえば、「img」、「script」)、およびduration
(フェッチにかかった合計時間)が含まれます。
User Timing API:アプリケーションのロジックの測定
場合によっては、パフォーマンスのボトルネックはアセットのロードではなく、クライアント側のコード自体にあります。シングルページアプリケーション(SPA)が、APIからデータを受信した後に複雑なコンポーネントをレンダリングするのにどれくらいの時間がかかりますか?User Timing APIを使用すると、カスタムのアプリケーション固有の測定を作成できます。
これは、主に次の2つのメソッドで動作します。
- performance.mark(name):パフォーマンスバッファーに名前付きのタイムスタンプを作成します。
- performance.measure(name, startMark, endMark):2つのマーク間の期間を計算し、名前付きの測定を作成します。
例:製品リストコンポーネントのレンダリング時間の測定。
// When you start fetching data
performance.mark('product-list-fetch-start');
fetch('/api/products')
.then(response => response.json())
.then(data => {
// After fetching, before rendering
performance.mark('product-list-render-start');
renderProductList(data);
// Immediately after rendering is complete
performance.mark('product-list-render-end');
// Create a measure
performance.measure(
'Product List Render Time',
'product-list-render-start',
'product-list-render-end'
);
});
これにより、ユーザーのワークフローにとって最も重要なアプリケーションの部分を測定するための正確な制御が可能になります。
PerformanceObserver:最新の効率的なアプローチ
performance.getEntriesByType()
を常にポーリングするのは非効率的です。`PerformanceObserver` APIは、パフォーマンスエントリをリッスンするはるかに優れた方法を提供します。特定のエントリタイプをサブスクライブすると、ブラウザは記録されたときにコールバック関数に非同期的に通知します。これは、アプリケーションにオーバーヘッドを追加せずにパフォーマンスデータを収集するための推奨される方法です。
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`Entry Type: ${entry.entryType}, Name: ${entry.name}`);
}
});
observer.observe({ entryTypes: ['resource', 'navigation', 'mark', 'measure'] });
このオブザーバーは、上記の従来の指標だけでなく、次に説明する最新のユーザー中心の指標を収集するための鍵となります。
ユーザー中心への移行:Core Web Vitals
ページが2秒でロードされたことを知ることは役に立ちますが、重要な質問には答えられません。ユーザーはそれらの2秒間、空白の画面を見つめていたのでしょうか?ページを操作できましたか、それともフリーズしていましたか?読もうとしたときに、コンテンツが予期せず飛び回っていましたか?
これに対処するために、GoogleはCore Web Vitals(CWV)を導入しました。これは、3つの主要な次元(ロード、インタラクティビティ、および視覚的な安定性)にわたって、ページの実際のユーザーエクスペリエンスを測定するように設計された一連の指標です。
Largest Contentful Paint(LCP):認識されるロードの測定
LCPは、ビューポート内に表示される最大の画像またはテキストブロックのレンダリング時間を測定します。これは、ユーザーがページのメインコンテンツがロードされたと感じるタイミングの優れたプロキシです。これは、ユーザーの質問に直接答えます:「このページはもう役に立ちますか?」
- 良好:2.5秒未満
- 改善が必要:2.5秒〜4.0秒
- 不良:4.0秒以上
loadEventEnd
とは異なり、LCPはユーザーが最初に見たものに焦点を当てているため、認識されるロード速度をより正確に反映しています。
Interaction to Next Paint(INP):応答性の測定
INPはFirst Input Delay(FID)の後継であり、2024年3月に公式のCore Web Vitalになりました。FIDは*最初の*インタラクションの遅延のみを測定しましたが、INPはページライフサイクル全体を通じて*すべての*ユーザーインタラクション(クリック、タップ、キープレス)のレイテンシを測定します。最も長いインタラクションを報告し、ユーザーが経験する最悪のケースの応答性を効果的に特定します。
INPは、ユーザーの入力から次のフレームがペイントされるまでの全時間を測定し、視覚的なフィードバックを反映します。これは、ユーザーの質問に答えます:「このボタンをクリックすると、ページはすぐに応答しますか?」
- 良好:200ミリ秒未満
- 改善が必要:200ms〜500ms
- 不良:500ms以上
高いINPは通常、ビジー状態のメインスレッドが原因で発生します。長時間実行されるJavaScriptタスクにより、ブラウザがユーザー入力に応答できなくなります。
Cumulative Layout Shift(CLS):視覚的な安定性の測定
CLSは、ページの視覚的な安定性を測定します。ロードプロセス中に画面上でコンテンツが予期せず移動する量を定量化します。高いCLSスコアは、ユーザーの不満の一般的な原因です。たとえば、ボタンをクリックしようとしたときに、広告がその上にロードされ、ボタンが下に移動し、代わりに広告をクリックしてしまうなどです。
CLSは、ユーザーの質問に答えます:「要素がいたるところに飛び回ることなく、このページを使用できますか?」
- 良好:0.1未満
- 改善が必要:0.1〜0.25
- 不良:0.25以上
高いCLSの一般的な原因には、寸法のない画像またはiframe、Webフォントの遅延ロード、またはスペースを予約せずにコンテンツが動的にページに挿入されることなどが含まれます。
ギャップを埋める:APIを使用して貧弱なユーザーエクスペリエンスを診断する
これは、すべてがまとまる場所です。Core Web Vitalsは、ユーザーが*何を*経験したか(たとえば、遅いLCP)を教えてくれます。Web Performance APIは、*なぜ*それが起こったのかを教えてくれます。これらを組み合わせることで、パフォーマンスを単に観察することから、積極的に診断および修正することに変わります。
遅いLCPの診断
Real User Monitoring(RUM)ツールが、特定の地域のユーザーに対して4.5秒の悪いLCPを報告するとします。どのように修正しますか?LCP時間を構成要素に分解する必要があります。
- Time to First Byte(TTFB):サーバーの応答が遅いですか?Navigation Timing APIを使用します。
responseStart - requestStart
の期間は、正確なTTFBを提供します。これが高い場合、問題はフロントエンドではなく、バックエンド、サーバー構成、またはデータベースにあります。 - リソースロードの遅延と時間:LCP要素自体のロードが遅いですか?まず、LCP要素(たとえば、ヒーロー画像)を特定します。
'largest-contentful-paint'
の`PerformanceObserver`を使用して、要素自体を取得できます。次に、Resource Timing APIを使用して、その要素のURLのエントリを見つけます。そのタイムラインを分析します:`connectStart`から`connectEnd`までが長い(ネットワークが遅い)ですか?`responseStart`から`responseEnd`までが長い(ファイルサイズが大きい)ですか?CSSやJavaScriptなどの他のレンダリングをブロックするリソースによって、`fetchStart`が遅延しましたか? - 要素レンダリングの遅延:これは、リソースのロードが完了してから実際に画面にペイントされるまでの時間です。これは、メインスレッドが大きなJavaScriptバンドルの実行など、他のタスクでビジーになっていることが原因である可能性があります。
Navigation TimingとResource Timingを使用することにより、遅いLCPが遅いサーバー、レンダリングをブロックするスクリプト、または巨大で最適化されていない画像が原因であるかどうかを特定できます。
貧弱なINPの調査
ユーザーは、「カートに追加」ボタンをクリックするとラグがあるように感じると不満を訴えています。INPメトリックは「不良」範囲にあります。これはほとんどの場合、メインスレッドの問題です。
- Long Tasksの特定:Long Tasks APIは、ここでの主要なツールです。50msを超えるメインスレッド上のタスクを報告します。それより長いタスクは、ユーザーにとって顕著な遅延のリスクがあります。`'longtask'`エントリをリッスンするように`PerformanceObserver`を設定します。
- ユーザーアクションとの関連付け:ユーザーが操作しようとしているときに発生した場合にのみ、長いタスクが問題になります。`'event'`タイプで`PerformanceObserver`を介して観察されたINPイベントの`startTime`を、ほぼ同時期に発生した長いタスクのタイミングと関連付けることができます。これにより、ユーザーのインタラクションをブロックしたJavaScript関数が正確にわかります。
- 特定のハンドラーの測定:User Timing APIを使用して、さらに詳細に分析します。クリティカルなイベントハンドラー(「カートに追加」の「クリック」ハンドラーなど)を`performance.mark()`および`performance.measure()`でラップします。これにより、独自のコードの実行にどれくらいの時間がかかっているか、そしてそれが長いタスクの原因であるかどうかが正確にわかります。
高いCLSへの取り組み
ユーザーは、モバイルデバイスで記事を読んでいるときにテキストが飛び回ると報告しています。CLSスコアは0.3です。
- レイアウトシフトの観察:`PerformanceObserver`を使用して、`'layout-shift'`エントリをリッスンします。各エントリには、`value`(CLSスコアへの貢献)と、移動したDOM要素である`sources`のリストがあります。これにより、*何が*移動したかがわかります。
- 犯人のリソースの検索:次の質問は、*なぜ*移動したかです。一般的な理由の1つは、リソースが遅れてロードされ、他のコンテンツを下に移動させることです。Resource Timing APIからのエントリの`startTime`と`responseEnd`時間を`layout-shift`エントリの`startTime`と関連付けることができます。広告スクリプトまたは大きな画像がロードを完了した直後にレイアウトシフトが発生した場合、犯人が見つかった可能性があります。
- 事前対応的なソリューション:修正には、画像と広告の寸法を提供すること(`<img width="1000" height="600">`)や、動的コンテンツがロードされる前にページ上にスペースを予約することがよくあります。Resource Timingは、事前対応する必要があるリソースを特定するのに役立ちます。
実践的な実装:グローバルモニタリングシステムの構築
これらのAPIを理解することは1つのことであり、グローバルユーザーベースのエクスペリエンスを監視するためにそれらをデプロイすることが次のステップです。これは、Real User Monitoring(RUM)の領域です。
`PerformanceObserver`を使用したすべてをまとめる
この重要なデータをすべて収集するために、単一の強力なスクリプトを作成できます。目標は、測定しようとしているパフォーマンスに影響を与えることなく、メトリックとそのコンテキストを収集することです。
堅牢なオブザーバー設定の概念的なスニペットを次に示します。
const collectedMetrics = {};
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'largest-contentful-paint') {
collectedMetrics.lcp = entry.startTime;
} else if (entry.entryType === 'layout-shift') {
collectedMetrics.cls = (collectedMetrics.cls || 0) + entry.value;
} else if (entry.entryType === 'event') {
// This is a simplified view of INP calculation
const duration = entry.duration;
if (duration > (collectedMetrics.inp || 0)) {
collectedMetrics.inp = duration;
}
}
// ... and so on for other entry types like 'longtask'
}
});
observer.observe({ entryTypes: ['largest-contentful-paint', 'layout-shift', 'event', 'longtask'] });
データを確実に送信する
データを収集したら、ストレージと分析のために分析バックエンドに送信する必要があります。ページアンロードを遅らせたり、タブをすばやく閉じるユーザーからのデータを失ったりすることなく、これを行うことが重要です。
`navigator.sendBeacon()` APIは、これに最適です。ページがアンロードされている場合でも、少量のデータをサーバーに送信するための信頼性の高い非同期の方法を提供します。応答を予期しないため、軽量で非ブロッキングです。
window.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
const payload = JSON.stringify(collectedMetrics);
navigator.sendBeacon('/api/performance-analytics', payload);
}
});
グローバルビューの重要性
Lighthouseのようなラボテストツールは非常に貴重ですが、制御された環境で実行されます。これらのAPIから収集されたRUMデータは、さまざまな国、ネットワーク条件、およびデバイス全体でユーザーが経験する真実を教えてくれます。
データを分析するときは、常にセグメント化してください。次のことがわかるかもしれません。
- LCPは北米のユーザーにとっては優れていますが、主な画像サーバーが米国にあるため、オーストラリアのユーザーにとっては貧弱です。
- INPは、新興市場で人気のあるミッドレンジのAndroidデバイスでは高くなっています。これは、JavaScriptがそれらに対してCPUを過剰に使用しているためです。
- CLSは、CSSメディアクエリによって広告のサイズが不適切に変更される特定の画面サイズでのみ問題になります。
このレベルのセグメント化された洞察により、実際のユーザーベースに最も大きな影響を与える最適化を優先順位付けできます(どこにいても)。
結論:測定から習得へ
ウェブパフォーマンスの世界は成熟しました。私たちは、単純な技術的なタイミングから、ユーザーの認識されるエクスペリエンスの洗練された理解へと移行しました。この道のりには、次の3つの主要なステップが含まれます。
- エクスペリエンスの測定:`PerformanceObserver`を使用して、Core Web Vitals(LCP、INP、CLS)を収集します。これは、*何*が起こっているのか、*それが*ユーザーに*どのように感じられるか*を教えてくれます。
- 原因の診断:基礎となるタイミングAPI(Navigation、Resource、User、Long Tasks)を使用して、より深く掘り下げます。これは、エクスペリエンスが*なぜ*貧弱なのかを教えてくれます。
- 正確に行動する:組み合わされたデータを使用して、特定の問題を特定し、特定のユーザーセグメントの問題の根本原因に対処する、情報に基づいたターゲットを絞った最適化を行います。
高レベルのユーザーメトリックと低レベルの診断APIの両方を習得することで、全体的なパフォーマンス戦略を構築できます。推測をやめて、技術的に高速であるだけでなく、あらゆるデバイス、世界のあらゆる場所のすべてのユーザーにとって高速で応答性が高く、楽しいと感じられるウェブエクスペリエンスを設計し始めます。