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タグ に書くルール
class="lazy"を追加srcに1px透明GIFを設定(プレースホルダー)data-src○○に実際の画像/動画URLを設定loading="lazy"と併用しない(response-lazy.jsと競合します)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で実現できます。

