LESSON 30分

「Webページの転送量の半分以上は画像だ」と佐藤CTOはデータを示した。「画像最適化だけで、ページロード時間を劇的に改善できる。」

1. 画像フォーマットの選択

フォーマット用途圧縮率ブラウザ対応
WebP汎用(写真・イラスト)JPEG比25-35%小さい97%+
AVIF高品質写真JPEG比50%小さい92%+
SVGアイコン・ロゴベクター(無限拡大)100%
PNG透過が必要な画像ロスレス100%
<!-- picture要素で最適なフォーマットを提供 -->
<picture>
  <source srcset="/hero.avif" type="image/avif" />
  <source srcset="/hero.webp" type="image/webp" />
  <img src="/hero.jpg" alt="Hero" width="1200" height="600"
       loading="eager" fetchpriority="high" decoding="async" />
</picture>

2. レスポンシブ画像

<!-- srcset + sizes でデバイスに最適なサイズを配信 -->
<img
  srcset="
    /product-400.webp 400w,
    /product-800.webp 800w,
    /product-1200.webp 1200w"
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
  src="/product-800.webp"
  alt="商品画像"
  width="800" height="600"
  loading="lazy"
  decoding="async"
/>

画像CDNの活用

// Cloudflare Images / imgproxy 等で動的リサイズ
function getOptimizedImageUrl(
  src: string,
  width: number,
  format: 'webp' | 'avif' = 'webp',
  quality: number = 80
): string {
  return `https://cdn.example.com/cdn-cgi/image/width=${width},format=${format},quality=${quality}/${src}`;
}

3. 遅延読み込み(Lazy Loading)

<!-- ネイティブ lazy loading -->
<img src="/product.webp" loading="lazy" alt="Product" width="400" height="300" />

<!-- 注意: LCP対象の画像には lazy loading を使わない! -->
<!-- Above-the-fold の画像は eager + fetchpriority="high" -->
// Intersection Observer による高度な制御
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target as HTMLImageElement;
      img.src = img.dataset.src!;
      observer.unobserve(img);
    }
  });
}, { rootMargin: '200px' }); // 200px手前でプリロード開始

4. フォント最適化

/* font-display で表示戦略を制御 */
@font-face {
  font-family: 'NotoSansJP';
  src: url('/fonts/NotoSansJP-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap; /* FOUT(Flash of Unstyled Text)を許容 */
  unicode-range: U+3000-9FFF; /* 日本語のみ */
}
<!-- フォントのプリロード -->
<link rel="preload" href="/fonts/NotoSansJP-Regular.woff2"
      as="font" type="font/woff2" crossorigin />
font-display値挙動推奨場面
swapフォールバック即表示、ロード後切替本文テキスト
optional極めて短い非表示期間、無ければフォールバック高パフォーマンス重視
fallback短い非表示期間、中程度の切替期間バランス型

5. リソースヒント

<head>
  <!-- preconnect: 事前にTCP/TLS接続を確立 -->
  <link rel="preconnect" href="https://cdn.example.com" />
  <link rel="preconnect" href="https://fonts.googleapis.com" />

  <!-- dns-prefetch: DNS解決だけ先にやる -->
  <link rel="dns-prefetch" href="https://analytics.example.com" />

  <!-- preload: 高優先度リソースを早期にフェッチ -->
  <link rel="preload" href="/critical.css" as="style" />
  <link rel="preload" href="/hero.webp" as="image" />

  <!-- prefetch: 次のナビゲーションで使うリソースを先読み -->
  <link rel="prefetch" href="/products/popular.json" />

  <!-- modulepreload: ESモジュールの先読み -->
  <link rel="modulepreload" href="/js/checkout.js" />
</head>

まとめ

トピック要点
画像フォーマットWebP/AVIFを優先、picture要素でフォールバック
レスポンシブ画像srcset + sizes でデバイスに最適なサイズを配信
遅延読み込みbelow-the-fold のみ lazy、LCP画像は eager
フォントwoff2 + font-display: swap + unicode-range
リソースヒントpreload/preconnect/prefetch で取得を最適化

チェックリスト

  • WebP/AVIFの使い分けとフォールバック設定ができる
  • srcset + sizes でレスポンシブ画像を実装できる
  • lazy loadingの適切な使い所を判断できる
  • フォント最適化(woff2, font-display, unicode-range)を適用できる
  • リソースヒントの種類と使い分けを理解した

次のステップへ

画像・アセット最適化を学んだ。次は レンダリングパフォーマンス で、ブラウザの描画パイプラインを最適化しよう。

推定読了時間: 30分