言語を切り替える
テーマを切り替える

フロントエンド性能最適化の実践:Core Web Vitals満点攻略

Lighthouseのスコアが60点しかなく、1週間で90点まで上げなければならない。Chrome DevToolsを開き、LCP、FID、CLSといった指標の意味を理解する必要があります。フロントエンド開発者にとって、パフォーマンス最適化は突然降ってくる追加タスクになりがちです。

落とし穴も少なくありません。初めて最適化したとき、すべての画像に遅延読み込みを設定した結果、LCPスコアがかえって悪化しました。ファーストビューの大きな画像は遅延読み込みすべきではなかったのです。Service Workerのキャッシュ戦略に2日費やしても、スコアは2点しか上がりませんでした。本記事は理論の紹介ではなく、2週間で確実に成果が出る実戦ガイドです。どの施策がROI最高か、避けるべき落とし穴は何か、Lighthouseスコアを60から90以上に引き上げる優先順位を解説します。

70%+
LCP問題
画像が原因
41%
圧縮率向上
AVIF vs JPEG
2週間
最適化期間
60点→90+
Source: 実戦データ

第1章:Core Web Vitals 3大指標を理解する

専門用語に怯える必要はありません。要するに、読み込みは速いか、クリックはすぐ反応するか、画面はグラつかないかの3点です。

Core Web Vitalsとは

Googleが2020年に提唱したユーザー体験の3指標で、SEO順位に直接影響します。コンテンツがどれほど良くても、性能が悪ければ順位は下がります。2024年3月には大きな更新があり、INPがFIDに代わってコア指標になりました。まだFIDを最適化しているなら、情報を更新しましょう。

LCP - 最大コンテンツの描画

LCPはページの主要コンテンツが表示されるまでの時間を測ります。通常はファーストビューの大きな画像、見出し、動画です。基準は次のとおりです。

  • 2.5秒未満:良好(緑)
  • 2.5〜4秒:要改善(黄)
  • 4秒以上:不良(赤)

レストランに例えると、LCPはメインディッシュが出てくるまでの時間です。10分待っても料理が来なければ、不満になりますよね。

あるデータでは、読み込み時間が3秒から5秒に伸びると直帰率は38%増加します。モバイルで3秒を超えると、53%のユーザーが離脱します。LCPを改善すれば、コンバージョン率は7〜15%向上します。

38%
直帰率の増加
Source: 読み込み時間 3秒→5秒

INP - インタラクションから次の描画まで

2024年3月の新指標で、FIDに正式に代わりました。クリック、キーボード入力、タップに対する応答速度を、入力から描画完了まで通して評価します。基準は次のとおりです。

  • 200ms未満:良好(緑)
  • 200〜500ms:要改善(黄)
  • 500ms以上:不良(赤)

GoogleがFIDを置き換えた理由は、FIDが「初回入力の遅延」だけを測るのに対し、INPはインタラクション全体をカバーするからです。レストランで言えば、FIDは店員が注文を聞いたかどうかだけ。INPは注文から料理が出るまでの全工程です。

あるプロジェクトではINPが650msでした。ボタンを押してから半秒以上待つ状態です。原因はYouTubeの自動埋め込みで、削除後INPは220msに改善し、ユーザーからも「サクサク動く」と好評でした。

CLS - 累積レイアウトシフト

CLSはページの視覚的安定性を測ります。ボタンを押そうとした瞬間にページが跳ねて、広告をクリックしてしまった経験はありませんか。それがCLSです。基準は次のとおりです。

  • 0.1未満:良好(緑)
  • 0.1〜0.25:要改善(黄)
  • 0.25以上:不良(赤)

初めてCLSが0.5だったとき、「0.5なら小さい数字」と思いましたが、これは壊滅的な数値です。主な原因は、画像のサイズ未指定、広告の突然挿入、フォント読み込みによるチラつき(FOIT)です。


第2章:LCP最適化 - ROI最高の性能改善

LCPを最優先にする理由は次のとおりです。

  • 影響が最も直感的:ユーザーが最初に「遅い」と感じる部分
  • 改善幅が大きい:5秒かかっていたものを2秒以下にできる
  • 技術が成熟している:画像最適化、CDN加速など確立された手法が多い
  • ROIが最高:少ない工数で大きな効果が出る

Core Web Vitals最適化の完全フロー

LCP、INP、CLSの包括的改善。2週間でLighthouseスコアを60から90以上に引き上げる

Estimated time: PT2W

  1. 1

    Step 1: P0優先:画像最適化(LCP)

    LCP問題の70%以上は画像。ROIが最も高い施策です。
  2. 2

    Step 2: P0優先:第三者スクリプトの遅延(INP)

    第三者スクリプトはINPの主なボトルネックです。
  3. 3

    Step 3: P0優先:画像にサイズ指定(CLS)

    CLSは最も修正しやすい指標です。
  4. 4

    Step 4: P1優先:コード分割とリソース最適化

    1. ルート単位のコード分割:
  5. 5

    Step 5: P1優先:フォントとサーバー最適化

    1. フォント最適化:
  6. 6

    Step 6: P2優先:高度な最適化

    高度な最適化(ROI中程度、難易度高):

1. 画像最適化(ROI: ⭐⭐⭐⭐⭐)

LCP改善の最重要ポイントで、問題の70%以上を占めます。性能最適化はいつもここから始めます。

a) 次世代フォーマットの利用

画像フォーマットを軽視しないでください。JPEGからAVIFに変えるだけで、1枚300KB節約できます。

<!-- 方法1:<picture>タグでブラウザに最適フォーマットを選ばせる -->
<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="Hero image"> <!-- フォールバック、古いブラウザ用 -->
</picture>
// 方法2:Next.jsの自動最適化(推奨)
import Image from 'next/image'
<Image
  src="/hero.jpg"
  width={1200}
  height={600}
  priority // 重要:LCP画像には必ずpriority。遅延読み込みしない!
/>

実データ:

  • AVIFはJPEGより41%高い圧縮率
  • WebPはJPEGより30%高い圧縮率
  • 実戦例:ECサイトのヒーロー画像を500KB→120KB(AVIF)に、LCPを4.2秒→2.1秒に半減

b) 画像の遅延読み込み(LCP画像を除く)

ここで落とし穴があります。LCP画像まで遅延読み込みすると、スコアが下がります。

<!-- ❌ 誤った例:LCP画像を遅延読み込みしてはいけない -->
<img src="hero.jpg" loading="lazy">
<!-- ✅ 正しい:ファーストビューの大きな画像はeager、それ以外はlazy -->
<img src="hero.jpg" loading="eager"> <!-- LCP画像 -->
<img src="product1.jpg" loading="lazy"> <!-- 下の方の画像のみlazy -->
<img src="product2.jpg" loading="lazy">

覚えておいてください:ファーストビューに見える画像は、1枚も遅延読み込みしない。lazyはファーストビュー外の画像用です。

c) レスポンシブ画像

モバイルユーザーはデスクトップ用の大きな画像を読み込む必要はありません。srcsetで通信量を60%節約できます。

<img
  src="hero-800w.jpg"
  srcset="hero-400w.jpg 400w,
          hero-800w.jpg 800w,
          hero-1200w.jpg 1200w"
  sizes="(max-width: 600px) 400px,
         (max-width: 1000px) 800px,
         1200px"
  alt="Hero"
/>

実効果:モバイルで400w画像を配信すれば1200wよりLCPが1秒改善します。

d) 画像CDNとpreload

CDNは贅沢品ではなく必需品です。Alibaba Cloud OSS なら、年間コストもわずか数十人民元程度です。

<!-- 重要な画像をpreloadし、ブラウザに優先読み込みさせる -->
<link rel="preload" as="image" href="hero.jpg">
<!-- 画像CDN(自動フォーマット変換+圧縮) -->
<!-- Tencent Cloud COS、Alibaba Cloud OSS、Cloudflare Images が対応 -->
<img src="https://cdn.example.com/hero.jpg?x-oss-process=image/format,webp/quality,80">

e) 画像サイズと圧縮

おすすめツール:

  • TinyPNG:オンライン圧縮、手軽
  • ImageOptim:Mac向け、一括圧縮
  • Squoosh:Google製、AVIF対応

圧縮ルール:

  • ファーストビューの大きな画像は品質80%(視覚差は小さい)
  • その他は70%で十分
  • サイズはデザイン稿の2倍幅(高解像度ディスプレイ対応)

f) 大きなBase64インラインを避ける

// ❌ 大きな画像をインラインしない(10KB超)
// HTMLが肥大化し、レンダリングが遅れる
const heroImage = 'data:image/jpeg;base64,/9j/4AAQSkZJRg...' // 500KB
// ✅ 小さなアイコンのみBase64(10KB未満)
// ローディングアイコン、シンプルなSVGアイコンなど
const icon = 'data:image/svg+xml;base64,PHN2ZyB3aWR...' // 2KB

2. サーバー応答時間の最適化(ROI: ⭐⭐⭐⭐)

a) CDNの利用

すべての静的リソースをCDNに載せます。HTMLもCDNキャッシュ(SSG/ISR併用)できます。TTFBが200ms→50msに短縮された事例もあり、体感差は明確です。

b) SSRまたはSSG

// Next.js - 静的生成(最優先、性能が最良)
export async function getStaticProps() {
  const data = await fetchData()
  return {
    props: { data },
    revalidate: 60 // ISR:60秒後に再生成
  }
}
// またはサーバーサイドレンダリング(リアルタイム性が必要な場合)
export async function getServerSideProps() {
  const data = await fetchData()
  return { props: { data } }
}

c) データベースクエリの最適化

  • インデックスを追加(explain分析を忘れずに)
  • Redisでホットデータをキャッシュ
  • N+1クエリを避ける(joinやdataloaderを使用)

3. リソース読み込みの最適化(ROI: ⭐⭐⭐)

a) クリティカルCSSのインライン化

<!-- ファーストビューの重要CSSを<head>にインライン、レンダリングブロックを回避 -->
<style>
  .hero {
    width: 100%;
    height: 600px;
    background: #f0f0f0;
  }
  .nav {
    position: fixed;
    top: 0;
    width: 100%;
  }
</style>
<!-- 非クリティカルCSSは遅延読み込み -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>

b) フォント最適化

/* font-displayでFOIT(Flash of Invisible Text)を回避 */
@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
  font-display: swap; /* フォールバックを即表示、白画面を回避 */
}
<!-- 重要フォントをpreload -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

第3章:INP最適化 - インタラクションを滑らかに

第三者スクリプトはINPの最大の敵です。1ページに12個の第三者スクリプトが読み込まれる例もあり、Google Analytics、Facebook Pixel、チャット、広告…INPが800ms超になることもあります。

1. JavaScript実行の最適化(ROI: ⭐⭐⭐⭐)

a) コード分割(Code Splitting)

「必要なページのコードだけ読み込む」という考え方です。

// React - ルート単位のコード分割
import { lazy, Suspense } from 'react'
const Dashboard = lazy(() => import('./Dashboard'))
const Profile = lazy(() => import('./Profile'))
function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </Suspense>
  )
}
// Vue 3 - 非同期コンポーネントも同様
const Dashboard = defineAsyncComponent(() => import('./Dashboard.vue'))

実効果:ある管理画面で1.2MB→初期200KBに、INPを450ms→180msに改善。ページ表示が倍速になりました。

b) 長いタスクの分割

メインスレッドが50ms以上ブロックされると長いタスクとなり、INPが悪化します。

// ❌ メインスレッドをブロックする長いタスク(フリーズ)
function processLargeData(data) {
  for (let i = 0; i < 10000; i++) {
    // 複雑な計算、1万件を一括処理
    heavyCalculation(data[i])
  }
}
// ✅ requestIdleCallbackで小タスクに分割
function processLargeData(data) {
  let index = 0
  function processChunk() {
    const chunkSize = 100 // 100件ずつ処理
    let count = 0
    while (index < data.length && count < chunkSize) {
      heavyCalculation(data[index])
      index++
      count++
    }
    if (index < data.length) {
      // 未完了なら次のアイドル時に続行
      requestIdleCallback(processChunk)
    }
  }
  requestIdleCallback(processChunk)
}

c) Web Workersの利用

複雑な計算をWorkerに移し、メインスレッドをブロックしません。

// worker.js
self.onmessage = (e) => {
  const result = complexCalculation(e.data) // Worker内で複雑な計算
  self.postMessage(result)
}
// main.js
const worker = new Worker('worker.js')
worker.postMessage(data)
worker.onmessage = (e) => {
  console.log('Result:', e.data)
  // 結果を受け取りUIを更新
}

2. 第三者スクリプトの最適化(ROI: ⭐⭐⭐⭐⭐)

第三者スクリプトは、来客が多いほど混乱するパーティのようなものです。各スクリプトがリソースを奪い合います。

a) 非重要スクリプトの遅延読み込み

<!-- ❌ ブロッキング読み込み(ページレンダリングを止める) -->
<script src="analytics.js"></script>
<!-- ✅ ページ読み込み完了まで待つ -->
<script defer src="analytics.js"></script>
<!-- ✅ または手動で3秒遅延(より積極的) -->
<script>
  window.addEventListener('load', () => {
    setTimeout(() => {
      const script = document.createElement('script')
      script.src = 'analytics.js'
      document.body.appendChild(script)
    }, 3000) // ユーザーが3秒閲覧してから分析スクリプトを読み込む
  })
</script>

b) Facadeパターンで重いコンポーネントを遅延

YouTube埋め込みは1MB超。直接読み込むとINPが深刻に悪化します。

// YouTube軽量カバー、クリック時に本物の動画を読み込む
function VideoFacade({ videoId }) {
  const [showVideo, setShowVideo] = useState(false)
  if (!showVideo) {
    return (
      <div
        className="video-facade"
        style={{
          backgroundImage: `url(https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg)`,
          cursor: 'pointer'
        }}
        onClick={() => setShowVideo(true)}
      >
        <button className="play-button">▶ 動画を再生</button>
      </div>
    )
  }
  return <iframe src={`https://www.youtube.com/embed/${videoId}`} />
}

実効果:あるブログでYouTube自動埋め込みを削除、INPを650ms→220msに改善。

3. イベント処理の最適化(ROI: ⭐⭐⭐)

a) デバウンスとスロットル

import { debounce, throttle } from 'lodash'
// 検索ボックスのデバウンス(入力停止300ms後に実行)
const handleSearch = debounce((value) => {
  fetchSearchResults(value)
}, 300)
// スクロールのスロットル(100msに1回まで)
const handleScroll = throttle(() => {
  updateScrollPosition()
}, 100)

b) Passiveイベントリスナー

// スクロール性能向上、preventDefaultを呼ばないことをブラウザに通知
window.addEventListener('scroll', handleScroll, { passive: true })
window.addEventListener('touchmove', handleTouch, { passive: true })

第4章:CLS最適化 - 画面の揺れを防ぐ

CLSは本を読んでいる最中に誰かがページを押し上げ、さっき読んでいた行を探し直すようなもの。非常にイライラします。幸い、CLSは最も修正しやすい指標です。

1. 画像と動画にサイズを指定(ROI: ⭐⭐⭐⭐⭐)

サイズ未指定の画像がCLSの最大の原因ですが、修正も最も簡単です。

<!-- ❌ サイズ未指定、読み込み時に揺れる -->
<img src="photo.jpg" alt="Photo">
<!-- ✅ サイズ指定、ブラウザが事前にスペースを確保 -->
<img src="photo.jpg" width="800" height="600" alt="Photo">
<!-- ✅ CSS aspect-ratio(モダンブラウザ対応) -->
<style>
  img {
    width: 100%;
    aspect-ratio: 16 / 9;
  }
</style>

実例:あるニュースサイトで全画像にサイズを追加、CLSを0.35→0.05に改善。これだけです。

2. フォント読み込みの最適化(ROI: ⭐⭐⭐⭐)

a) font-display: swapの使用

@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
  font-display: swap; /* FOIT(フォント読み込み中の白画面)を回避 */
}

b) 重要フォントのpreload

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

c) システムフォントまたはVariable Font

/* システムフォント、読み込み不要、遅延ゼロ */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
/* Variable Font、1ファイルに全ウェイト(100-900) */
@font-face {
  font-family: 'Inter';
  src: url('Inter-Variable.woff2') format('woff2-variations');
  font-weight: 100 900;
}

3. 動的コンテンツのスペース確保(ROI: ⭐⭐⭐⭐)

a) 広告枠のスペース確保

.ad-container {
  min-height: 250px; /* 広告読み込み前も高さを確保、揺れない */
  background: #f0f0f0; /* プレースホルダー背景 */
}

b) スケルトンスクリーン

見た目だけでなく、レイアウトの安定にも重要です。

// 読み込み前にスケルトンを表示、コンテンツの突然出現による揺れを防ぐ
function ProductCard({ loading, data }) {
  if (loading) {
    return (
      <div className="skeleton">
        <div className="skeleton-image" style={{ width: '100%', height: '200px', background: '#e0e0e0' }} />
        <div className="skeleton-title" style={{ width: '80%', height: '20px', background: '#e0e0e0', margin: '10px 0' }} />
        <div className="skeleton-price" style={{ width: '40%', height: '20px', background: '#e0e0e0' }} />
      </div>
    )
  }
  return (
    <div className="product">
      <img src={data.image} alt={data.title} />
      <h3>{data.title}</h3>
      <p>{data.price}</p>
    </div>
  )
}

4. 既存コンテンツの上への挿入を避ける(ROI: ⭐⭐⭐⭐⭐)

// ❌ 上部にバナーを挿入、コンテンツが下にずれる(CLS悪化)
<div>
  {showBanner && <Banner />}
  <Content />
</div>
// ✅ fixed配置でレイアウトに影響しない
<div>
  {showBanner && <Banner style={{ position: 'fixed', top: 0, zIndex: 1000 }} />}
  <Content style={{ marginTop: showBanner ? '60px' : '0' }} />
</div>

5. アニメーションはtop/leftではなくtransform(ROI: ⭐⭐⭐)

topでアニメーションするとCLSが悪化する例を見たことがあります。

/* ❌ layoutをトリガー、CLSの原因 */
.element {
  position: relative;
  animation: slideIn 0.3s;
}
@keyframes slideIn {
  from { top: -100px; } /* top変更はリフローをトリガー */
  to { top: 0; }
}
/* ✅ transformのみ、compositeのみ(GPU加速) */
.element {
  animation: slideIn 0.3s;
}
@keyframes slideIn {
  from { transform: translateY(-100px); }
  to { transform: translateY(0); }
}

第5章:総合実戦 - 完全な最適化フロー

優先順位が重要です。いきなりSSRから始めないでください。まず画像最適化を。初回最適化では画像にサイズを付けただけで10点向上しました。本当にタダ同然の点数です。

最適化優先順位マトリックス

施策ROI難易度優先度
画像にサイズ追加極高極低P0
画像フォーマット変換極高P0
LCP画像最適化極高P0
第三者スクリプト遅延極高P0
フォント最適化P1
コード分割P1
CDNP1
SSR/SSGP2
Web WorkersP3

計測ツールとコマンド

# 1. Lighthouse(最も権威ある)
# Chrome DevTools > Lighthouse > Generate report
# シークレットモードを使う。拡張機能がスコアを歪める
# 2. WebPageTest(実機テスト)
# https://webpagetest.org
# 地域や回線速度を選択可能
# 3. Chrome DevTools Performanceパネル
# 読み込み過程を記録し、ボトルネックを分析
# 各タスクの所要時間が見える
# 4. npmパッケージ分析
npx webpack-bundle-analyzer
# どのパッケージが最大かを可視化
# 5. 画像分析
npx sharp-cli info image.jpg
# 画像のサイズ、形式、ファイルサイズを確認

落とし穴回避ガイド

  1. ❌ 本番環境でLighthouseを計測しない(シークレットモードか拡張機能無効化)
  2. ❌ 1回だけテストしない(最低3回の平均を取る。ネットワーク変動が大きい)
  3. ❌ デスクトップだけテストしない(モバイルが重要。トラフィックの75%はモバイル)
  4. ❌ Network throttlingを無視しない(Fast 3Gなど遅い回線をシミュレート)
  5. ❌ LCP画像を遅延読み込みしない(この落とし穴を踏んだ経験あり)

まとめ

性能最適化は一度きりの作業ではなく、継続的なプロセスです。筋トレのように、継続と規律が必要です。Lighthouseスコアが60から90に上がった瞬間、達成感は本物です。

性能最適化は技術作業であると同時に、ユーザー体験への敬意でもあります。1秒改善するごとに、ユーザーを留められます。モバイルユーザーの忍耐は3秒しかありません。その3秒を1秒に短縮する力を、今あなたは持っています。

共に、すべてのユーザーが滑らかなブラウジング体験を享受できるようにしましょう。

FAQ

Core Web Vitals 3大指標の基準は?
LCP(最大コンテンツの描画):
• 2.5秒未満が良好、2.5〜4秒は要改善、4秒超は不良

INP(インタラクションから次の描画まで):
• 200ms未満が良好、200〜500msは要改善、500ms超は不良
• 2024年3月にINPがFIDに代わってコア指標に

CLS(累積レイアウトシフト):
• 0.1未満が良好、0.1〜0.25は要改善、0.25超は不良

重要データ:
• 読み込み時間が3秒→5秒で直帰率38%増加
• モバイルで3秒超えると53%のユーザーが離脱
• LCP改善でコンバージョン率7〜15%向上
LCP(最大コンテンツの描画)をどう最適化する?
画像最適化がLCP問題の70%以上を占めます:

1) 次世代フォーマット(AVIFはJPEGより41%高い圧縮率、WebPは30%)
• 実戦例:ヒーロー画像500KB→120KB、LCP 4.2秒→2.1秒

2) LCP画像にはpriorityを付け、遅延読み込みしない。ファーストビューはeager

3) レスポンシブ画像srcsetで通信量60%削減

4) CDNと重要画像のpreload

5) サーバー応答時間の最適化(CDN、SSR/SSG、DBクエリ)

優先度:画像最適化のROIが最高、少ない工数で効果大。
INP(インタラクションから次の描画まで)をどう最適化する?
主要な改善策:

1) コード分割(ルート単位、React lazy、Vue defineAsyncComponent)
• 実戦例:1.2MB→初期200KB、INP 450ms→180ms

2) 第三者スクリプトの遅延(deferまたは手動3秒遅延)、Facadeパターンで重いコンポーネントを遅延

3) 自動埋め込みの第三者コンテンツを削除(YouTube自動埋め込み、INP 650ms→220ms)

4) requestIdleCallbackで長いタスクを分割

5) Web Workersで複雑な計算を処理

6) デバウンス・スロットルとPassiveイベントリスナー
CLS(累積レイアウトシフト)をどう最適化する?
CLSは最も修正しやすい:

1) 画像にサイズ指定(width/height属性またはCSS aspect-ratio)
• 実戦例:CLS 0.35→0.05

2) フォント最適化(font-display:swapでFOIT回避、重要フォントpreload、システムフォントやVariable Font)

3) 動的コンテンツのスペース確保(広告枠min-height、スケルトンスクリーン)

4) 既存コンテンツの上への挿入を避ける(fixed配置)

5) アニメーションはtop/leftではなくtransform(compositeのみ、layoutをトリガーしない)
性能最適化の優先順位は?
P0優先(ROI極高、難易度低):
• 画像にサイズ追加
• 画像フォーマット変換(AVIF/WebP)
• LCP画像最適化(priority、遅延読み込みしない)
• 第三者スクリプト遅延

P1優先(ROI高):
• フォント最適化(font-display:swap)
• コード分割
• CDN

P2優先(ROI中、難易度高):
• SSR/SSG

P3優先(ROI低、難易度高):
• Web Workers

推奨:まずP0から。画像にサイズを付けるだけで10点向上、タダ同然。いきなりSSRから始めず、まず画像最適化を。
LCP画像を遅延読み込みしてもいい?
絶対にダメです。最もよくある落とし穴です。

LCP画像(ファーストビューの大きな画像)にはpriorityまたはloading="eager"を付け、遅延読み込みしない。lazyはファーストビュー外の画像用です。

誤った例:
<img src="hero.jpg" loading="lazy"> → LCPスコアが下がる

正しい例:
• ファーストビューの大きな画像はeager、それ以外はlazy
• ファーストビューに見える画像は1枚も遅延読み込みしない
Core Web Vitalsをどう計測・テストする?
計測ツール:

1) Lighthouse(Chrome DevTools、最も権威。シークレットモードで拡張機能の干渉を回避)

2) WebPageTest(実機テスト、地域・回線速度を選択可能)

3) Chrome DevTools Performanceパネル(読み込み過程を記録しボトルネック分析)

4) webpack-bundle-analyzer(どのパッケージが最大か可視化)

5) sharp-cli info(画像のサイズ、形式、ファイルサイズ確認)

落とし穴:
• 本番環境でテストしない
• 1回だけテストしない(最低3回の平均)
• デスクトップだけテストしない(モバイルが重要、75%のトラフィック)
• Network throttlingを無視しない(遅い回線をシミュレート)

6分で読めます · 公開日: 2025年11月24日 · 更新日: 2026年6月8日

シリーズの読書導線 第 6 / 6 記事

フロントエンドフレームワーク比較

検索からこのページに来た場合は、前後の記事もあわせて読むと同じテーマの理解がかなり早く深まります。

シリーズ全体を見る

関連記事

コメント

GitHubアカウントでログインしてコメントできます