優れたユーザーエクスペリエンスのためのコアウェブバイタルのマスター
Lukas Schneider
DevOps Engineer · Leapcell

ウェブ開発の絶えず進化する状況において、シームレスで魅力的なユーザーエクスペリエンスを提供することが最優先事項です。今日のユーザーは、超高速の読み込み時間、即時の応答性、安定した視覚レイアウトを期待しています。これらの期待に応えられないと、直帰率の増加、コンバージョンの低下、そして最終的にはブランド評判の低下につながります。ユーザーエクスペリエンスのこれらの重要な側面に対処するために、Googleはコアウェブバイタルを導入しました。これは、ユーザーの実際の体験を定量化する3つの主要な指標のセットです:Largest Contentful Paint (LCP)、Interaction to Next Paint (INP)、Cumulative Layout Shift (CLS)。この記事では、これらの重要な指標を最適化するための包括的な戦略を掘り下げ、開発者に真にユーザーを満足させるウェブサイトを作成するための知識とツールを提供します。
コアウェブバイタルの理解
最適化に入る前に、各コアウェブバイタルを明確に理解しましょう。
- Largest Contentful Paint (LCP): この指標は、ビューポート内で表示される最大の画像またはテキストブロックのレンダリング時間を測定します。本質的には、ウェブページの主要コンテンツがユーザーにどれだけ早く表示されるかを示します。低いLCPスコアは、高速な読み込みと優れたユーザーエクスペリエンスの認識を示します。
- Interaction to Next Paint (INP): INPは、ユーザーが滞在中に発生したすべてのインタラクションのレイテンシを測定することにより、ページの応答性を評価します。これは、ユーザーインタラクションのほとんどすべてが、インタラクションの期間に基づいて、それ以下であった単一の値を示します。これには、クリック、タップ、スクロールが含まれます。低いINPスコアは、ページがユーザー入力に非常に応答的であることを示します。
- Cumulative Layout Shift (CLS): CLSは、ウェブページが表示されている間に発生する予期しない視覚要素の移動を定量化します。画像やテキストブロックが予期せずジャンプして、ユーザーの読み取りまたはクリックフローを中断するのを想像してください。低いCLSスコアは、安定した視覚的に予測可能なページを意味します。
これらの指標を最適化することは、検索エンジンのランキングのためにチェックボックスを埋めることだけではありません。それは、ユーザーがあなたのウェブサイトとどのように対話し、どのように認識するかの根本的な改善です。
コアウェブバイタルの最適化戦略
LCP、INP、CLSの改善には、ウェブパフォーマンスのさまざまな側面をターゲットにした多角的なアプローチが必要です。
Largest Contentful Paint (LCP) の最適化
LCPは主に、主要コンテンツがレンダリングされる速度に焦点を当てています。LCPのパフォーマンス低下の一般的な原因には、サーバー応答時間の遅延、レンダリングをブロックするリソース、最適化されていない画像、クライアントサイドレンダリングなどがあります。
-
サーバー応答時間の改善:
- サーバーサイドキャッシング: HTMLの生成にかかる時間を短縮するために、サーバーレベル(例:Redis、Memcached)で堅牢なキャッシング戦略を実装します。
- データベースクエリの最適化: データベースクエリが効率的で適切にインデックス付けされていることを確認します。
- 高速なホスティングプロバイダーの選択: 強力で適切に構成されたサーバーが基本です。
- コンテンツ配信ネットワーク (CDN): CDNを使用して、静的アセットをユーザーの近くで配信し、レイテンシを削減します。
// シンプルなサーバーサイドキャッシングのデモンストレーション(概念) // 実際のアプリケーションでは、専用のキャッシングライブラリ/サービスを使用します。 const express = require('express'); const app = express(); const cache = {}; // インメモリキャッシュ app.get('/data', (req, res) => { if (cache['data']) { // データがキャッシュにあるか確認 console.log('Serving from cache'); return res.send(cache['data']); } // 時間のかかる操作(例:データベースクエリ)をシミュレート setTimeout(() => { const result = 'This is cached data.'; cache['data'] = result; // キャッシュに保存 console.log('Serving fresh data and caching'); res.send(result); }, 500); }); app.listen(3000, () => console.log('Server running on port 3000'));
-
レンダリングをブロックするリソースの排除:
- JavaScriptの
defer
またはasync
:<script>
タグにdefer
またはasync
を付けて、HTMLパーサーをブロックしないようにします。async
はスクリプトがロードされ次第実行しますが、順序は保証されません。defer
はHTMLが解析された後、DOMContentLoaded
イベントの前にスクリプトを実行し、実行順序を維持します。 - クリティカルCSS: 上記ビューポートコンテンツに必要なクリティカルCSSを抽出してHTMLに直接インライン化し、必須要素を即座にレンダリングします。重要でないCSSは非同期でロードします。
<!-- 重要でないJavaScriptの遅延読み込み --> <script src="non-critical.js" defer></script> <!-- スクリプトの非同期読み込み(順序は保証されません) --> <script src="analytics.js" async></script> <!-- クリティカルCSSのインライン表示 --> <style> /* 上記ビューポートコンテンツのクリティカルなスタイル */ body { margin: 0; font-family: sans-serif; } .hero { background-color: #f0f0f0; padding: 20px; } </style> <!-- 残りのCSSの非同期読み込み --> <link rel="preload" href="full-styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> <noscript><link rel="stylesheet" href="full-styles.css"></noscript>
- JavaScriptの
-
画像の最適化:
- 画像の圧縮: WebPやAVIFのようなモダンな画像フォーマットを使用し、品質を犠牲にすることなくファイルサイズを削減するために適切な圧縮を適用します。ImageOptimやさまざまなオンラインコンプレッサーなどのツールが役立ちます。
- レスポンシブ画像:
srcset
およびsizes
属性を<img>
タグと共に使用して、ユーザーのデバイスやビューポートに基づいて適切なサイズの画像を配信します。 - 遅延読み込み: ビューポートに入りそうになるまで読み込みを遅延させる
loading="lazy"
属性を使用して、ビューポートの下にある画像やiframeの遅延読み込みを実装します。 - LCP画像のプリロード: LCP画像が事前にわかっている場合は、
<link rel="preload">
を使用して早期に取得します。
<img src="hero-small.jpg" srcset="hero-small.jpg 480w, hero-medium.jpg 800w, hero-large.jpg 1200w" sizes="(max-width: 600px) 480px, (max-width: 1000px) 800px, 1200px" alt="Hero image" loading="lazy" > <!-- 重要な画像のプリロード(LCP要素である場合) --> <link rel="preload" as="image" href="path/to/lcp-image.jpg">
Interaction to Next Paint (INP) の強化
INPは、ページがユーザー入力にどれだけ応答するかを重視します。INPのパフォーマンス低下の主な原因は、負荷の高いJavaScript実行、メインスレッドをブロックする長時間タスク、非効率的なイベントハンドラです。
-
JavaScript実行時間の削減:
- コード分割とツリーシェーキング: JavaScriptバンドルを小さく、オンデマンドのチャンクに分割します。未使用のコードを削除します。
- デバウンスとスロットリング: 頻繁にトリガーされるイベント(例:リサイズ、スクロール、入力フィールド)の場合、デバウンスとスロットリングを使用してイベントハンドラが呼び出される頻度を制限します。
// デバウンス関数 const debounce = (func, delay) => { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), delay); }; }; const handleInput = debounce((event) => { console.log('Input changed:', event.target.value); }, 300); // スロットリング関数 const throttle = (func, limit) => { let inThrottle; return function(...args) { const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => (inThrottle = false), limit); } }; }; const handleScroll = throttle(() => { console.log('Scrolling...'); }, 200); // document.getElementById('myInput').addEventListener('input', handleInput); // window.addEventListener('scroll', handleScroll);
- Web Workers: UIの応答性を維持するために、メインスレッドからWeb Workerに負荷の高い計算タスクをオフロードします。
// main.js const myWorker = new Worker('worker.js'); myWorker.postMessage({ operation: 'heavyComputation', data: 1000000 }); myWorker.onmessage = function(e) { console.log('Result from worker:', e.data); }; // worker.js self.onmessage = function(e) { if (e.data.operation === 'heavyComputation') { let sum = 0; for (let i = 0; i < e.data.data; i++) { sum += i; } self.postMessage(sum); } };
- メインスレッドの作業の最小化:
setTimeout
、requestAnimationFrame
、またはisInputPending
(サポートされている場合)を使用して、長時間実行されるJavaScriptタスクを小さく非同期なチャンクに分割します。
-
イベントハンドラの最適化:
- パッシブイベントリスナー: タッチおよびホイールイベントの場合、ハンドラが
preventDefault()
を呼び出さないことを示すためにpassive: true
を使用し、ブラウザにハンドラが完了するのを待たずにネイティブにスクロールできるようにします。document.addEventListener('touchstart', (event) => { // ... }, { passive: true });
- イベント委譲: 多くの個々の要素にイベントリスナーをアタッチする代わりに、共通の親要素に単一のリスナーをアタッチし、イベント委譲を通じてイベントを処理します。
- パッシブイベントリスナー: タッチおよびホイールイベントの場合、ハンドラが
Cumulative Layout Shift (CLS) の最小化
CLSは、ページの視覚的な安定性に対処します。予期しないレイアウトシフトは、多くの場合、寸法のない画像、動的に挿入されるコンテンツ、未スタイルのテキストのフラッシュ(FOUT)または不可視テキストのフラッシュ(FOIT)を伴うWebフォントの読み込み、および非同期に読み込まれる広告または埋め込みによって発生します。
-
常に画像とビデオの寸法を設定する:
- 画像とビデオ要素に
width
およびheight
属性(またはアスペクト比CSS)を指定します。これにより、メディアがロードされる前にブラウザがスペースを確保できるようになります。 - レスポンシブ画像の場合、スペースを確保するためにCSSの
aspect-ratio
プロパティを使用します。
<img src="product.jpg" width="600" height="400" alt="Product image"> <!-- aspect-ratio CSS を使用 --> <style> .responsive-image-container { width: 100%; padding-bottom: 75%; /* 4:3 アスペクト比 (高さ / 幅 * 100) */ position: relative; overflow: hidden; /* 画像からのオーバーフローを隠す */ } .responsive-image { position: absolute; width: 100%; height: 100%; object-fit: cover; } </style> <div class="responsive-image-container"> <img src="responsive-img.jpg" class="responsive-image" alt="Responsive image"> </div>
- 画像とビデオ要素に
-
動的に挿入されるコンテンツを慎重に処理する:
- スペースを予約する: 動的にコンテンツ(例:広告、ポップアップ、埋め込み)を挿入する場合は、CSSの
min-height
/min-width
またはプレースホルダー要素を使用してスペースを確保します。 - プレースホルダー: 動的コンテンツがロードされる間、プレースホルダーまたはスケルトンUIを表示します。
- スペースを予約する: 動的にコンテンツ(例:広告、ポップアップ、埋め込み)を挿入する場合は、CSSの
-
Webフォントの読み込みを最適化する:
font-display
プロパティ:@font-face
宣言でfont-display: swap
(フォールバックフォントを即座に表示し、ロード時にWebフォントに切り替える)またはfont-display: optional
(Webフォントの読み込みに時間がかかる場合、フォールバックが使用される可能性があり、レイアウトシフトを回避する)を使用します。CLSにはswap
が一般的に推奨されます。- フォントのプリロード: 重要なWebフォントを
<link rel="preload" as="font" crossorigin>
を使用してプリロードし、早期に利用できるようにします。
@font-face { font-family: 'MyWebFont'; src: url('myfont.woff2') format('woff2'); font-display: swap; /* または 'optional' */ }
<link rel="preload" href="/fonts/myfont.woff2" as="font" type="font/woff2" crossorigin>
-
既存コンテンツの上にコンテンツを挿入しない:
- 動的にコンテンツを挿入する必要がある場合は、既存コンテンツの下に挿入するか、事前にスペースを予約するようにします。
- 初期レンダリング後にビューポートの上部に表示されるバナーやポップアップには注意してください。これらは重大なCLSを引き起こす可能性があります。
結論
LCP、INP、CLSの最適化は、技術的なベンチマークを満たすことだけではありません。それは、ユーザーにより優れた、より楽しい体験を提供することです。サーバーパフォーマンス、効率的なリソース読み込み、応答性の高いインタラクション、視覚的な安定性に焦点を当てることで、開発者は迅速に読み込まれ、即座に反応し、予測可能で満足のいくユーザー体験を提供するウェブサイトを作成できます。これらの戦略を実装することで、Core Web Vitalsのスコアが向上するだけでなく、ユーザーエンゲージメントと満足度も高まります。