MENU

【WordPress高速化】YouTube埋め込みを遅延読み込み

【WordPress高速化】YouTube埋め込みを遅延読み込み
目次

はじめに

「WordPress高速化」シリーズの第3回です。【WordPress高速化】SWELLのCLSをCSSで改善(以下「前回の記事」)では、ページのずれ(CLS)を直しました。今回からは、読み込むものを減らして速くする話に進みます。

今回取り上げるのは、記事に埋め込んだYouTubeの動画です。YouTubeの埋め込みは、プレーヤーを動かすために1本あたり約1.2MBのファイルを読み込みます。しかも、WordPressの標準のままだと、動画が画面に入っていなくても読み込まれることがありました。

これを、JavaScriptのIntersection Observer(交差オブザーバー)を使って、「動画が画面に近づいたときだけ読み込む」ように変えます。テスト用の記事で測った結果は次のとおりです。

ページを開いた直後(スクロール前)動画までスクロールした後
WordPressの標準約1.2MB(13件)約1.2MB
Intersection Observerを使用0KB(0件)約1.2MB

動画まで読まずにページを離れる読者には、YouTubeのファイルを1つも読み込ませずに済みます。

この記事のコードは、子テーマの functions.php と JavaScript のファイルを使います。functions.php の書き方は、【WordPress×PHP】functions.phpの書き方で解説しています。編集する前に、必ずバックアップを取ってください。

Intersection Observerとは?

Intersection Observerは、「ある要素が画面に入ったか(画面と交差したか)」を、ブラウザが見張って知らせてくれる仕組みです。ブラウザに標準で用意されている機能(API)なので、ライブラリを追加しなくても使えます。くわしい仕様は、MDNの交差オブザーバー APIにまとめられています。

YouTubeのような動画のほかにも、X(旧Twitter)やInstagramの投稿の埋め込み、広告、画像など、「画面に入ったときに初めて必要になるもの」なら何にでも使えます。

これまでは、スクロールのイベント(scroll)を使って、スクロールのたびに要素の位置を計算する方法がよく使われていました。イベントの基本は【JavaScript】イベント処理を解説_Webの基礎で紹介しています。

比較項目スクロールのイベントIntersection Observer
動くタイミングスクロールのたびに何度も画面に入ったとき・出たときだけ
位置の計算自分で書くブラウザがやってくれる
ページへの負担大きくなりやすい小さい
Intersection Observerの仕組み。画面(ビューポート)の上下にrootMarginで指定した余白を足した範囲に、見張っている要素が入ると、ブラウザが関数を呼び出して知らせる

基本の書き方

// 1. 画面に入ったときに呼ばれる関数を決めて、見張り役を作る
const observer = new IntersectionObserver((entries) => {
	entries.forEach((entry) => {
		if (entry.isIntersecting) {
			console.log('画面に入りました', entry.target);
		}
	});
}, { rootMargin: '200px 0px' });

// 2. 見張りたい要素を登録する
observer.observe(document.querySelector('#target'));
書き方意味
entries状態が変わった要素の一覧(まとめて届くので forEach で1つずつ見る)
entry.isIntersecting画面に入っていれば true
entry.targetその要素そのもの
rootMargin画面の範囲を広げる余白。'200px 0px' なら、画面の200px手前で「入った」と判定する
observer.unobserve(要素)その要素の見張りをやめる(1回読み込めば十分なときに使う)

rootMargin を付けると、要素が画面に入る少し前に読み込みを始められます。読者がスクロールしてきたときには、もう表示が終わっている、という状態を作れます。

WordPressの標準の遅延読み込み

実は、WordPressはYouTubeの埋め込みにも、最初から遅延読み込みの指定を付けています。ブロックエディターの「YouTube」ブロックで動画を埋め込むと、次のようなHTMLが出力されます。

<iframe loading="lazy" title="動画のタイトル" width="500" height="281"
	src="https://www.youtube.com/embed/動画のID?feature=oembed" ...></iframe>

loading="lazy" は、「画面に近づくまで読み込まない」という指示です。それなのに、なぜ画面の外の動画が読み込まれたのでしょうか。

理由は、どれくらい手前で読み込むかを、ブラウザが決めているからです。テスト用のページで確かめると、Chromeでは、iframeが画面の下端から約2,400px手前にある時点で読み込みが始まりました(回線の速さなどで変わります)。

読み込みが始まる位置の比較。loading="lazy"は画面の下端から約2,400px手前で読み込みが始まるため、記事の途中にある動画もページを開いた直後に読み込まれる。Intersection Observer(rootMargin 200px)は約200px手前で読み込みが始まる

2,400pxは、パソコンの画面で2〜3画面分です。記事の前半に埋め込んだ動画は、ページを開いた時点で読み込まれてしまいます。Intersection Observerなら、この距離を自分で決められます。

Intersection ObserverでYouTubeを遅延読み込みする

考え方は次の2段階です。

  1. PHP:YouTubeのiframeの src を data-src に書き換えて、最初は読み込まないようにする
  2. JavaScript:iframeが画面に近づいたら、data-src の値を src に戻して読み込む

Step1:functions.phpでsrcをdata-srcに書き換える

子テーマの functions.php に、次のコードを追加します。

// YouTubeの埋め込みを、画面に近づくまで読み込まないようにする
add_filter('embed_oembed_html', function ($html, $url) {
	// 管理画面・ブロックエディターのプレビュー・RSSフィードでは書き換えない
	if (is_admin() || wp_is_json_request() || is_feed()) {
		return $html;
	}
	// YouTube以外の埋め込みはそのまま
	if (!str_contains($url, 'youtube.com') && !str_contains($url, 'youtu.be')) {
		return $html;
	}
	// src を data-src に変えて、最初は読み込まないようにする
	return str_replace(' src="', ' data-src="', $html);
}, 10, 2);

// 記事ページだけ、遅延読み込み用のJavaScriptを読み込む
add_action('wp_enqueue_scripts', function () {
	if (!is_singular()) {
		return;
	}
	wp_enqueue_script(
		'yt-lazy',
		get_stylesheet_directory_uri() . '/js/yt-lazy.js',
		[],
		'1.0',
		['in_footer' => true, 'strategy' => 'defer']
	);
});
  • embed_oembed_html は、YouTubeなどの埋め込みのHTMLを出力する直前に呼ばれるフィルターフックです。フィルターフックの仕組みは【WordPress×PHP】フィルターフックの仕組みと使い方で解説しています
  • ブロックエディターのプレビューも同じフックを通るため、wp_is_json_request() で除外しています。除外しないと、編集画面で動画が表示されなくなります
  • 出力のたびに書き換えるので、過去の記事を保存し直す必要はありません
  • JavaScriptは wp_enqueue_script で、記事ページ(is_singular())だけ、フッターで読み込みます。wp_enqueue_script は【WordPress×PHP】アクションフックの仕組みと使い方で紹介した wp_enqueue_scripts フックの中で呼び出します

Step2:JavaScriptで画面に近づいたら読み込む

子テーマのフォルダに js フォルダを作り、yt-lazy.js というファイルを置きます(wp-content/themes/swell_child/js/yt-lazy.js)。

// data-src を持つ iframe が画面に近づいたら、src に入れて読み込む
document.addEventListener('DOMContentLoaded', () => {
	const frames = document.querySelectorAll('iframe[data-src]');

	const observer = new IntersectionObserver((entries, obs) => {
		entries.forEach((entry) => {
			if (!entry.isIntersecting) {
				return;
			}
			const frame = entry.target;
			frame.src = frame.dataset.src;
			obs.unobserve(frame);
		});
	}, { rootMargin: '200px 0px' });

	frames.forEach((frame) => observer.observe(frame));
});
  • iframe[data-src] で、Step1で書き換えたiframeだけを集めます
  • 画面の200px手前に来たら、frame.dataset.src(data-src の値)を src に入れます。これでYouTubeの読み込みが始まります
  • 1回読み込んだら、unobserve で見張りをやめます

読み込みを始める距離は、rootMargin の数値で調整できます。早めに読み込みたいなら '600px 0px' のように大きくします。

Step3:検証ツールで確認する

  1. 動画を埋め込んだ記事を開き、F12で検証ツールを開く
  2. 「ネットワーク」タブを開き、上の検索欄に youtube と入力する
  3. ページを再読み込みする(スクロールはしない)

動画が画面の外にあれば、一覧には何も表示されません。そのまま動画までスクロールすると、YouTubeのファイルが読み込まれるのが確認できます。

効果:画面外の動画の読み込みが0KBに

テスト用の記事で、本文の途中(ページの上端から約2,000px)にYouTubeを埋め込み、通信量を測りました。

画面幅方法スクロール前動画までスクロールした後
パソコン(1366px)WordPressの標準13件・1,195KB1,195KB
パソコン(1366px)Intersection Observer0件・0KB1,191KB
スマホ(375px)WordPressの標準13件・1,140KB1,141KB
スマホ(375px)Intersection Observer0件・0KB1,145KB
YouTube関連の通信量の比較。スクロール前は、WordPressの標準が約1.2MB、Intersection Observerが0KB。動画までスクロールした後は、どちらも約1.2MB

動画まで読んだ場合の通信量は変わりません。違うのは、動画を見ない読者に、約1.2MBを読み込ませなくて済むことです。特に、通信量や回線の速さが気になるスマホの読者に効果があります。

注意点

  • CLS(ずれ)は起きません:iframeには最初から width と height が付いているので、読み込む前から動画の枠の大きさは決まっています。前回の記事のような高さの確保は不要です
  • 記事の冒頭にある動画には効果がありません:最初から画面に入っている動画は、すぐに読み込まれます(害もありません)
  • SWELLの「スクリプトの遅延読み込み」とは別の仕組みです:SWELLの機能は、指定したスクリプトを「ユーザーが操作したとき、または数秒後」にまとめて読み込みます。今回の方法は、動画ごとに「画面に近づいたとき」に読み込みます。yt-lazy.js をSWELLの遅延の対象に入れると、見張りを始めるのが遅れるので、入れないでください

よくある質問・エラー対処

Q. 動画が表示されなくなりました

→ JavaScriptのファイルが読み込まれていない可能性があります。検証ツールの「コンソール」にエラーが出ていないか、「ネットワーク」タブで yt-lazy.js が読み込まれているかを確認してください。ファイルの場所(swell_child/js/yt-lazy.js)やファイル名の間違いが多い原因です。キャッシュ系のプラグインを使っている場合は、キャッシュも削除してください。


Q. YouTube以外の埋め込み(Vimeo、X、Instagramなど)にも使えますか

→ 使えます。ただし、埋め込みの仕組みによって、書き換える場所が変わります。

埋め込み埋め込みの仕組み対応のしかた
Vimeoなどの動画YouTubeと同じiframeStep1の str_contains の条件に vimeo.com などを追加するだけ(JavaScriptはそのまま使える)
X(旧Twitter)・Instagram投稿の引用(blockquote)と、それを埋め込みに変えるスクリプトiframeの src ではなく、スクリプトの読み込みを、投稿が画面に近づくまで遅らせる

XやInstagramの埋め込みは、ページに置かれた <script> が、あとから投稿の表示を作る仕組みです。そのため、今回のコードをそのまま当てはめても効果はありません。考え方は同じで、「投稿の blockquote を Intersection Observer で見張り、画面に近づいたらスクリプトを読み込む」形にします。


Q. 埋め込んでいた動画が非公開になったらどうなりますか

→ 遅延読み込みとは関係なく、YouTube側の「この動画は再生できません」のような表示になります。当サイトでも、以前埋め込んでいた動画が非公開になり、リンクに差し替えた記事がありました。古い記事の動画は、ときどき確認しておくと安心です。

おわりに(まとめ)

まとめ

YouTubeの埋め込みは、Intersection Observerで「画面に近づいたときだけ」読み込むようにできます。

  • ✅ YouTubeの埋め込みは、1本あたり約1.2MBを読み込む
  • ✅ WordPressの標準の loading=”lazy” は、画面の約2,400px手前で読み込みが始まる
  • ✅ Intersection Observerは、要素が画面に入ったことをブラウザが知らせてくれる仕組み
  • ✅ PHPで src を data-src に書き換え、JavaScriptで画面に近づいたら src に戻す
  • ✅ 画面外の動画は、スクロール前の読み込みが約1.2MBから0KBになった

次回の【WordPress高速化】AdSenseを枠ごとに遅延読み込みでは、同じIntersection Observerを使って、Google AdSenseの広告を広告枠ごとに遅延読み込みする方法を解説しています。

この記事が、少しでも誰かのお役に立てれば幸いです。

関連記事

当サイトの記事で使用したVBAなどのサンプルをDLできます

この記事のサンプルはありません!

ダウンロードページへは下のカードをクリックすればジャンプできます。
よろしければご利用ください!


【CSS】テキスト関連プロパティについて基本解説|Webの基礎


よかったらシェアしてね!
  • URLをコピーしました!
目次