MENU

【WordPress高速化】自動再生の動画を遅延読み込み

【WordPress高速化】自動再生の動画を遅延読み込み
目次

はじめに

「WordPress高速化」シリーズの第11回です。当サイトでは、操作の様子を見せるために、記事にmp4の動画を入れることがあります。動画ブロックで入れた動画が、いつ読み込まれているのかを調べてみました。

結果は次のとおりです。

  • 動画がページのかなり下にあっても、開いた直後に動画のファイルが丸ごと読み込まれていた
  • 自動再生の動画は、preload="none"(読み込まない指定)を付けてもブラウザが無視して読み込む
  • Intersection Observerで近づいてから読み込むようにすると、テスト記事の開いた直後の動画の読み込みが3,798KB→232KBになった

この記事では、自動再生の動画を画面に近づいてから読み込む方法と、再生ボタン付きの動画をブロックの設定だけで軽くする方法を解説します。

WordPress 7.1.4、SWELL 2.19、Chrome 157 で確認しています。子テーマの functions.php を編集し、JavaScriptのファイルを追加します。編集する前に、必ずバックアップを取ってください。

動画ブロックは、いつ読み込まれるか

本番の記事で確かめる

当サイトで動画を入れている記事を、スクロールせずに開いて、読み込まれたファイルを調べました。

記事動画の種類動画の位置開いた直後に読み込んだ量
VBAのユーザーフォームの記事自動再生(ミュート・ループ)×3本4,000〜8,400px下291KB(3本とも丸ごと)
GASの第7回再生ボタン付き ×1本3,000px下169KB(丸ごと)

どちらも、読者が動画の位置までスクロールしていないのに、動画のファイルを最後まで読み込んでいました。ページ全体の読み込み量(約1.3MB)の1〜2割にあたります。

なお、本文の画像には、WordPressが自動で loading="lazy" を付けているので、画面に近づくまで読み込まれていませんでした。遅延読み込みが効いていないのは、動画だけです。

preload の指定と、実際の読み込み量

<video> タグには、preload という属性で「最初にどこまで読み込むか」を指定できます。

preload の値意味
auto全部読み込んでよい
metadata長さや大きさなどの情報だけ読み込む
none再生されるまで読み込まない

ただし、これはブラウザへの「お願い」で、実際にどれだけ読み込むかはブラウザが決めます。そこで、テスト用の動画を2つ(232KBと3.3MB)用意して、ページの4,000px下に置き、スクロールせずに読み込まれた量をChromeで測りました。

動画の書き方ごとに、開いた直後に読み込んだ量。自動再生はpreload="none"でも読み込み、Intersection Observerを使うと0KBになる
動画の書き方小さい動画(232KB)大きい動画(3.3MB)
自動再生(指定なし)232KB4,134KB
自動再生+preload="none"232KB3,047KB
自動再生+Intersection Observer0KB0KB
再生ボタン付き(指定なし)232KB1,958KB
再生ボタン付き+preload="metadata"232KB1,984KB
再生ボタン付き+preload="none"0KB0KB

わかったことは、次の3つです。

  • 自動再生の動画は、preload の指定が効かない:自動再生(autoplay)は「すぐ再生する」指定なので、preload="none" より優先されます
  • preload="metadata" は、ほとんど効果がない:小さい動画は丸ごと、大きい動画でも約2MB読み込みました
  • 再生ボタン付きの動画は、preload="none" で0KBになる:ただし、最初のコマも読み込まないので、再生するまで黒い枠になります

大きい動画で、読み込んだ量がファイルの大きさを超えているのは、ループ再生のために同じ部分を読み直しているためです。

つまり、自動再生の動画は、ページに書いてある限り読み込まれてしまうので、画面に近づくまで src(動画のURL)を書かないようにする必要があります。再生ボタン付きの動画は、preload="none" で済みます。

SWELLの「画像等のLazyload」との関係

SWELLには、「SWELL設定」→「高速化」に「画像等のLazyload」という設定があり、次の3つから選べます。

  • 使用しない
  • loading="lazy" を使用する
  • スクリプト(lazysizes.js)を使って遅延読み込みさせる

3つ目のスクリプトを選ぶと、画像だけでなく、動画にも遅延読み込みがかかります。これで解決できるかを確かめるため、テスト記事に動画を4本入れて比べました(結果は後の「実測」で詳しく紹介します)。

SWELLの設定開いた直後最後までスクロールしたときの合計
loading="lazy"(当サイトの設定)3,798KB3,798KB
スクリプト(lazysizes.js)0KB8,351KB

スクリプトにすると、開いた直後は0KBになりました。しかし、preload="none" にした再生ボタン付きの動画まで、近づいたときに丸ごと読み込んでいました(3.6MB)。再生ボタンを押さない読者の分まで読み込むので、最後までスクロールしたときの合計は、かえって多くなります。

また、スクリプトにすると、画像の遅延読み込みもJavaScriptで行う方式に変わります。そこで当サイトでは、「loading="lazy" を使用する」のまま、自動再生の動画だけをコードで遅延読み込みすることにしました。

手順:自動再生の動画を、近づいてから読み込む

考え方は、【WordPress高速化】YouTube埋め込みを遅延読み込み(以下、第3回)と同じ2段階です。

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

Intersection Observer(要素が画面に近づいたことを知らせる仕組み)の基本は、第3回で解説しています。

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

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

// 自動再生の動画を、画面に近づくまで読み込まないようにする
add_filter('render_block_core/video', function ($html) {
	// 管理画面・RSSフィードでは書き換えない
	if (is_admin() || is_feed()) {
		return $html;
	}
	$tags = new WP_HTML_Tag_Processor($html);
	// 自動再生でない動画はそのまま
	if (!$tags->next_tag('video') || null === $tags->get_attribute('autoplay')) {
		return $html;
	}
	$src = $tags->get_attribute('src');
	if (!$src) {
		return $html;
	}
	// src を data-src に変えて、最初は読み込まないようにする
	$tags->set_attribute('data-src', $src);
	$tags->remove_attribute('src');
	return $tags->get_updated_html();
});

// 記事ページだけ、遅延読み込み用のJavaScriptを読み込む
add_action('wp_enqueue_scripts', function () {
	if (!is_singular()) {
		return;
	}
	wp_enqueue_script(
		'video-lazy',
		get_stylesheet_directory_uri() . '/js/video-lazy.js',
		[],
		'1.0',
		['in_footer' => true, 'strategy' => 'defer']
	);
});
  • render_block_core/video:動画ブロックのHTMLを出力する直前に呼ばれるフィルターフックです。フィルターフックの仕組みは【WordPress×PHP】フィルターフックの仕組みと使い方で解説しています
  • WP_HTML_Tag_Processor:HTMLのタグを1つずつ調べて、属性を書き換えられるWordPressの機能です。動画ブロックには、字幕(<track>)の src やポスター画像の指定が入ることがあるので、文字の置き換えではなく、<video> タグの src だけを確実に書き換えるために使っています
  • get_attribute('autoplay'):自動再生の指定がない動画は、null が返るので、書き換えずにそのまま出力します
  • 出力のたびに書き換えるので、過去の記事を保存し直す必要はありません

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

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

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

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

	videos.forEach((video) => observer.observe(video));
});
  • video[data-src]:Step1で書き換えた動画だけを集めます
  • 画面の200px手前に来たら、data-src の値を src に入れます。動画には自動再生の指定が残っているので、読み込みが終わるとそのまま再生が始まります
  • 1回読み込んだら、unobserve で見張りをやめます

第3回のコードと見比べると、iframe が video に変わっただけです。第3回の yt-lazy.js をすでに使っている場合は、1行目の 'iframe[data-src]' を 'iframe[data-src], video[data-src]' に変えれば、1つのファイルで両方に使えます。その場合、Step1の後半(wp_enqueue_script の部分)は不要です。

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

  1. 自動再生の動画を入れた記事を開き、F12で検証ツールを開く
  2. 「ネットワーク」タブを開き、上の検索欄に mp4 と入力する。「キャッシュを無効化」にもチェックを入れる
  3. ページの一番上で再読み込みし、動画まで少しずつスクロールする

自動再生の動画は、画面に近づいたときに一覧に追加されます。このとき「イニシエータ」(読み込みのきっかけ)の列は「その他」になります。

同じ記事に、プリロードを指定していない再生ボタン付きの動画がある場合、そちらは開いた直後に読み込まれます。イニシエータには、記事のHTMLの行(記事のURL:行番号)が表示されます。

検証ツールのネットワークタブ。1行目は開いた直後に読み込まれた再生ボタン付きの動画(イニシエータはHTMLの行)、2行目は近づいてから読み込まれた自動再生の動画(イニシエータはその他)

上の画像では、1行目が再生ボタン付きの動画、2行目が自動再生の動画です。再生ボタン付きの動画を開いた直後に読み込ませない方法は、次の章で説明します。

再生ボタン付きの動画は、ブロックの設定で

再生ボタン付きの動画は、コードを使わずに、動画ブロックの設定だけで軽くできます。

  1. 記事の編集画面で、動画ブロックを選ぶ
  2. 右側の設定で、「先読み」(プリロード)を「なし」にする
  3. 「ポスター画像を設定」から、動画の最初の画面などの画像を選ぶ
  4. 記事を更新する
動画ブロックの設定で、自動再生をオフ、先読みを「なし」にし、ポスター画像を設定したところ

先読みを「なし」にすると、再生ボタンが押されるまで動画を読み込みません。その代わり、最初のコマも表示されなくなり、黒い枠だけになってしまいます。ポスター画像は、先読み「なし」とセットで設定してください。ポスター画像は普通の画像なので、動画より軽く済みます。

ポスター画像は、「ポスター画像を設定」を押した後の画面からアップロードできます。動画を一時停止した画面を切り取って使うと、再生前と再生後の見た目がそろいます。

実測:対策前後の比較

テスト記事に、次の4本の動画を、ページの下のほうに離して入れました。

  • 自動再生(小:232KB)
  • 自動再生(大:3.3MB)
  • 再生ボタン付き・先読み「なし」・ポスター画像あり(大)
  • 再生ボタン付き・指定なし(小)
テスト記事の動画の読み込み量。開いた直後は、loading="lazy"のまま3,798KB、スクリプト0KB、記事のコード232KB
パターン開いた直後最後までスクロールしたときの合計再生CLS
SWELLの設定 loading="lazy" のまま3,798KB3,798KB○0
SWELLの設定をスクリプトにする0KB8,351KB○0
loading="lazy"+この記事のコード232KB5,314KB○0

この記事のコードを入れると、開いた直後の読み込みは3,798KB→232KBになりました。残った232KBは、「再生ボタン付き・指定なし」の動画です。この動画もプリロードを「なし」にすれば、開いた直後は0KBになります。

自動再生の動画は、近づいたときに読み込まれ、どれも問題なく再生されました。プリロード「なし」の動画は、再生ボタンを押すまで0KBのままです。

最後までスクロールしたときの合計が増えているのは、自動再生(大)の動画がループ再生で読み直しをしているためです。開いた直後に読み込むか、近づいてから読み込むかの違いなので、最後まで読む読者にとっての合計は、ほとんど変わりません。途中で読むのをやめた読者や、動画の手前までしか読まない読者の分だけ、読み込みが減ります。

注意点

  • 自動再生はミュートが前提:Chromeなどのブラウザは、音が出る動画の自動再生を止めます。動画ブロックの設定で「自動再生」と「ミュート」を両方オンにしてください
  • 動画の幅と高さ:動画ブロックでメディアライブラリから入れた動画には、幅と高さが自動で付きます。古い記事の動画には付いていないことがありますが、当サイトで幅と高さのない動画でも測ったところ、近づいてから読み込んでもレイアウトのずれ(CLS)は0でした
  • キャッシュを削除してから確かめる:SWELLのキャッシュやキャッシュ系のプラグインを使っている場合は、コードを追加したら削除してください
  • 読み込みを始める距離:大きな動画をスマホの回線で見ると、近づいてから読み込むので再生が少し遅れることがあります。rootMargin の '200px 0px' を '600px 0px' のように大きくすると、早めに読み込み始めます

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

Q. 動画までスクロールしても、再生されません

→ まず、ページのソースで <video を検索し、data-src に書き換わっているか確認してください。書き換わっているのに再生されない場合は、video-lazy.js の場所(swell_child/js/video-lazy.js)が正しいか、検証ツールの「Console」タブにエラーが出ていないかを確認してください。ミュートがオフの動画は、ブラウザが自動再生を止めることがあります。


Q. SWELLの「画像等のLazyload」をスクリプトにしている場合は、このコードは必要ですか

→ スクリプトにしている場合は、自動再生の動画もSWELLが遅延読み込みするので、このコードは必要ありません。ただし、プリロード「なし」の動画も近づいたときに読み込まれます。この記事のコードを追加しても、SWELLは data-src が付いた動画を書き換えないので、両方を入れても問題はありません。


Q. ブロックエディター以前の記事の動画( ショートコード)にも効きますか

→ 効きません。このコードは動画ブロックだけが対象です。 ショートコードの動画は、動画のURLが <video> タグの中の <source> タグに入っていて、作りが違います。対象の記事が少なければ、動画ブロックに入れ直すのが手軽です。

おわりに(まとめ)

まとめ

自動再生の動画はコードで、再生ボタン付きの動画はブロックの設定で、画面に近づくまで読み込まないようにできます。

  • ✅ 動画ブロックの動画は、画面の外にあっても、開いた直後に読み込まれる
  • ✅ 自動再生の動画は、preload="none" が効かない。src を後から入れる
  • ✅ render_block_core/video と WP_HTML_Tag_Processor で、自動再生の動画だけ data-src に書き換える
  • ✅ 再生ボタン付きの動画は、先読み「なし」とポスター画像をセットで設定する
  • ✅ テスト記事では、開いた直後の動画の読み込みが3,798KB→232KBになった

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

関連記事

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

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

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


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


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