Webサイトのパフォーマンス最適化において、画像や動画の遅延読み込み(Lazy Loading)は必須のテクニックです。しかし、実際に実装しようとすると以下のような問題に直面します:

  • <picture>タグでの画像切り替えはよく見かけるが、動画やiframeでは?
  • <video>タグのmedia属性はiPhoneで動作しないことがある
  • iframe(youtube)のレスポンシブ切り替えの情報が少ない
  • デバイスサイズに応じて最適なメディアを配信したい

この記事では、これらの問題をresponse.js(response-lazy.js)で一気に解決する方法を紹介します。


    従来の方法の問題点

    1. <picture>タグ - 画像のみ対応

    <!-- 画像は問題なし -->
    <picture>
      <source media="(max-width: 743.9px)" srcset="img/photo_sp.jpg" />
      <img src="img/photo_pc.jpg" alt="写真" />
    </picture>
    

    良い点:

    • ✅ ブラウザネイティブでレスポンシブ対応
    • ✅ SEOフレンドリー

    問題点:

    • ❌ 画像にしか使えない
    • ❌ 動画、iframe、embedには非対応

    2. <video>タグのmedia属性 - iPhone で動作不安定

    <!-- iPhoneで正常に動作しないことがある -->
    <video>
      <source src="/movie/mv_sp.mp4" type="video/mp4" media="(max-width: 799px)">
      <source src="/movie/mv_pc.mp4" type="video/mp4">
    </video>
    

    問題点:

    • ❌ Safariでの動作が不安定
    • ❌ 特にiPhoneで切り替わらないケースが多い
    • ❌ ブラウザ間の挙動が異なる

    3. iframeのレスポンシブ切り替え - 情報が少ない

    「iframe レスポンシブ 切り替え」で検索しても、アスペクト比を保つ方法ばかりで、デバイスごとに異なるコンテンツを表示する方法はほとんど見つかりません。

    <!-- こういうことがしたいけど、方法が分からない -->
    <iframe src="どうやって切り替える?"></iframe>
    

    解決策:response.js

    response.jsを使えば、画像・動画・iframeを統一的な方法でレスポンシブ&遅延読み込みできます。

    ryanve/response.js: Responsive design toolkit(Github)
    https://github.com/ryanve/response.js

    特徴

    • 📱 レスポンシブ: ブレークポイントに応じたメディア配信
    • 🎬 多機能: img, video, iframe, embed, objectに対応
    • 🍎 クロスブラウザ: iPhone/Safari含め安定動作
    • 🚀 遅延読み込み: IntersectionObserverで効率的な遅延読み込み(response-lazy.js)

    基本的な使い方

    <!DOCTYPE html>
    <html lang="ja">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>My Website</title>
    </head>
    <!-- Breakpoints の設定 -->
    <body data-responsejs='{"create": [
    { "prop":"width", "prefix":"src", "mode":"src", "breakpoints":[0,440,744,768,960,1200] },
    { "prop":"width", "prefix":"r", "mode":"markup", "breakpoints":[0,440,744,768,960,1200] }
    ]}'>
      <!-- コンテンツ -->
               ⌇
               ⌇
    
      <!-- response.js をbody終了タグの直前で読み込み -->
      <script src="https://unpkg.com/@sarap422/response-lazy@0.10.2/response.min.js"></script>
      <script src="https://unpkg.com/@sarap422/response-lazy@0.10.2/response-lazy.min.js"></script>
    </body>
    </html>
    

    画像・動画・iframeタグ に書くルール

    1. class="lazy" を追加
    2. src に1px透明GIFを設定(プレースホルダー)
    3. data-src○○ に実際の画像/動画URLを設定
    4. loading="lazy"と併用しない(response-lazy.jsと競合します)
    5. fetchpriority="low"は不要(効果が小さい)

    実装例

    例1: レスポンシブ画像(基本)

    <img 
      class="lazy" 
      style="aspect-ratio:16/9;"
      src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" 
      data-src0="img/photo_mobile.jpg" 
      data-src744="img/photo_desktop.jpg" 
      alt="商品写真"
    />
    

    動作:

    • 743px以下: photo_mobile.jpg
    • 744px以上: photo_desktop.jpg

    例2: レスポンシブ動画(iPhoneでも動作!)

    <video 
      class="lazy" 
      style="aspect-ratio:16/9;" 
      src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" 
      data-src0="video/hero_sp.mp4" 
      data-src744="video/hero_pc.mp4" 
      autoplay muted playsinline loop
    ></video>
    

    ポイント:

    • ✅ iPhone/Safariでも正常に動作
    • <video>media属性不要
    • ✅ 遅延読み込みで初期ロード時間を短縮

    例3: YouTube埋め込み(iframe)

    <div style="aspect-ratio:16/9;">
      <iframe class="lazy" 
        src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" 
        data-src0="https://www.youtube.com/embed/VIDEO_ID_SP" 
        data-src744="https://www.youtube.com/embed/VIDEO_ID_PC" 
        frameborder="0" 
        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen muted
      ></iframe>
    </div>
    

    用途:

    • モバイルとデスクトップで異なる動画を表示
    • 縦画面用と横画面用で別の動画
    • 短い版と長い版の使い分け

    例4: 複数ブレークポイント

    <img 
      class="lazy" 
      style="aspect-ratio:21/9;" 
      src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" 
      data-src0="img/hero_mobile.jpg" 
      data-src440="img/hero_small.jpg" 
      data-src744="img/hero_tablet.jpg" 
      data-src1200="img/hero_desktop.jpg" 
      alt="メインビジュアル"
    />
    

    ブレークポイント:

    • 0-439px: hero_mobile.jpg
    • 440-743px: hero_small.jpg
    • 744-1199px: hero_tablet.jpg
    • 1200px以上: hero_desktop.jpg

    ブレークポイントの設定

    data属性 適用されるビューポート幅
    data-src0 0px - 439px
    data-src440 440px - 743px
    data-src744 744px - 767px
    data-src768 768px - 959px
    data-src960 960px - 1199px
    data-src1200 1200px以上

    フォールバック機能:
    該当するブレークポイントの画像がない場合、より小さいブレークポイントの画像にフォールバックします。


    実際の効果

    パフォーマンス改善

    指標 モバイル デスクトップ
    初期ロード時間 1-10秒短縮 0.5-5秒短縮
    データ転送量 50-70%削減 30-50%削減
    Time to Interactive 大幅改善 改善

    Core Web Vitals への影響

    • LCP (Largest Contentful Paint): ✅ 改善
    • FID (First Input Delay): ✅ 改善

    まとめ

    response.js を使えば:

    ✅ 画像・動画・iframeを統一的な方法で遅延読み込み
    ✅ デバイスサイズに応じた最適なメディアを配信
    ✅ iPhoneでも安定動作
    ✅ わずか3KBで軽量
    ✅ CDNから簡単導入

    従来の方法では難しかった「動画やiframeのレスポンシブ切り替え+遅延読み込み」が、シンプルなHTMLで実現できます。


    参考リンク