HTMLのvideo要素で動画の遅延読み込みやスクロール位置で動画を読み込む方法
![HTMLのvideo要素で動画の遅延読み込みやスクロール位置で動画を読み込む方法](https://blanche-toile.com/freestyle/wp-content/uploads/2024/07/html-video-lazy-loading-mv.png)
Webページの背景で動画を使ったり、動画コンテンツをWebサイトでしか得られない情報とする場合は、HTMLのvideo要素で動画を扱っていくことになるでしょう。
しかし、ファイルサイズの大きい動画データとなると読み込みに時間がかかるため、Webページのパフォーマンスに影響を与えます。
自動再生の動画コンテンツをファーストビューで表示させる以外の活用方法であれば、動画データを遅延読み込みさせたほうがいいでしょう。
ここでは、HTMLのvideo要素で動画データを遅延読み込みする方法についてご紹介します。
video要素の動画を遅延読み込みする方法は、動画の利用用途によって変わってきます。
video要素にcontrols属性を設定し、コントロールパネルでユーザーが操作を行えるように動画を扱っていくのか、またはautoplay属性で自動再生するように動画を扱っていくかで、設定が変わったりプログラミングが必要になったりします。
それぞれのパターンでの遅延読み込みの方法を見ていきたいと思います。
コントロールパネルを表示した動画を扱う場合
ユーザーに操作してもらうためにコントロールパネルを表示して動画を扱う場合は、HTMLのみで遅延読み込みを実装することができます。
以下、HTMLのサンプルコードになります。
playsinline属性は、動画再生時にWebブラウザによっては動画が全画面表示となることもあるので、それを防ぐために設定しています。そしてcontrols属性でコントロールパネルを表示します。
その他の設定も見てみましょう。
HTML
<video playsinline controls preload="none" poster="video/video_thumbnail.jpg">
<source src="video/sample.mp4" type="video/mp4">
<source src="video/sample.webm" type="video/webm">
</video>
動画データの読み込みを遅延させるには、video要素にpreload属性を設定します。
preload属性はWebページ読み込み時に、動画ファイルも読み込むかどうかを指定することができます。preload属性の値を「none」とすることで、Webページ読み込み時に動画ファイルを読み込まないようにできます。
また、動画データを読み込まないことで、動画の最初のフレームがサムネイル画像として表示されないので、動画が読み込まれる前に表示する画像をposter属性で設定します。
CSSは横幅や中央配置など、動画コンテンツのレイアウト調整として共有しておきます。
CSS
video {
width: 100%;
max-width: fit-content;
display: block;
margin-inline: auto;
}
以下、Webブラウザのデベロッパーツールによる実装結果の確認です。
Webページアクセス時は、poster属性で設定した画像を含めて必要データが読み込まれますが、動画データは読み込まれていないのが確認できます。
そして、ユーザーが再生ボタンを操作したタイミングで、動画データが読み込まれて再生されます。
![HTMLのvideo要素の動画データの遅延読み込み](https://blanche-toile.com/freestyle/wp-content/uploads/2024/07/html-video-lazy-loading-01.png)
動画データを読み込む前のサムネイル画像は、動画のフレームを画像として準備するといいでしょう。意外と手軽に準備できます。
以下の記事の「HTMLのVideo要素で動画フレームをコピーする」の項目でご紹介しています。
動画を自動再生で扱う場合
動画を自動再生で扱う場合は、遅延読み込み後に動画の再生を実装しないといけないので、JavaScriptの処理が必要になります。
まずはHTMLから見ていきます。
autoplay属性で実装する自動再生では、loop属性とmuted属性を設定していないと、コントロールパネルを使わずユーザーの操作なしに動画を再生することはできません。preload属性とposter属性の設定と共に、loop属性とmuted属性を追加しておきます。
以下、HTMLのサンプルコードになります。
HTML
<video id="myVideo" playsinline muted loop preload="none" poster="video/video_thumbnail.jpg">
<source src="video/sample.mp4" type="video/mp4">
<source src="video/sample.webm" type="video/webm">
</video>
動画の再生はJavaScriptの処理で実装しますので、autoplay属性は設定しなくてもOKです。
続いては、JavaScriptのプログラムを見ていきます。
JavaScriptで動画を再生させるには、1つ問題をクリアする必要があります。
ブラウザのセキュリティポリシーにより、クリックやタッチなどの操作を行わないと自動再生が許可されません。
ユーザーのインタラクションなしで自動再生が許可されているかどうかはブラウザのポリシーに依存します。
autoplayを前提としてコントロールパネルを付けずに動画を扱っていく場合は、ユーザーにクリックやタッチ操作を求めないので動画を再生することができません。ただ、スクロールの操作はWebページを閲覧する時に必ず行うでしょう。
私が試した結果、ユーザーのスクロールイベントをトリガーにして動画を再生することが可能のようです。
ということで、スクロールイベントで動画を再生する方法で実装します。
以下、サンプルコードになります。
JavaScript
document.addEventListener("DOMContentLoaded", () => {
const video = document.getElementById("myVideo");
const playVideo = () => {
// 動画データを読み込んでから再生する
video.load(); // 動画データを読み込む
video.play() // 動画を再生
};
// スクロールイベントをリッスン(「{once: true}」で一度だけ実行)
window.addEventListener('scroll', playVideo, {once: true});
});
まずはaddEventListenerメソッドで、DOMツリー読み込み完了後のDOMContentLoadedイベントが発生した時に、さまざまな処理を実行していきます。
video要素を変数に格納しておき、video要素のオブジェクト変数に対して、動画データを読み込んだり再生を実装します。
動画データを読み込みや動画の再生の処理は、playVideoという関数に定義しておきます。
そして「window.addEventListener(‘scroll’, playVideo, {once: true});」で、ユーザーがスクロールしたらplayVideoの関数が実行されるようにします。
addEventListenerメソッドで実行されたスクロールイベントは、スクロールするたびに登録されたイベントリスナーが呼び出されて、動画データの読み込みと再生が繰り返し行われ、動画が常に最初からスタートしてしまいます。
イベントリスナーを一度だけ実行したら破棄・削除して再度実行されることがないように、addEventListenerメソッドの第3引数に {once: true} とオプションの設定は必要になります。
以下、実装結果の確認です。
まずWebページのアクセス時に、poster属性で設定した画像を含めて必要なデータが読み込まれます。
そして、ユーザーがページをスクロールしたらスクロールイベントが発火し、loadメソッドで動画データを読み込みはじめてからplayメソッドで再生します。
![HTMLのvideo要素の動画データの遅延読み込みとスクロールイベントでの再生](https://blanche-toile.com/freestyle/wp-content/uploads/2024/07/html-video-lazy-loading-02.png)
playメソッドは再生が正常に開始されるとPromiseを返すため、エラーハンドリングが必要になる場合もあります。
そのような場合を想定して、catchメソッドでrejectedステータス(プロミス拒否)のPromiseオブジェクトを受け取り、エラー処理を設定しておくのもいいでしょう。
サンプルでは、コンソールに情報を出力するだけとしておきます。
以下、動画の再生部分を修正しています。
JavaScript
document.addEventListener("DOMContentLoaded", () => {
const video = document.getElementById("myVideo");
const playVideo = () => {
// 動画データを読み込む
video.load(); // 動画データを読み込む
// 動画を再生
video.play().catch(error => {
console.log('再生エラー:', error);
});
};
// スクロールイベントをリッスン(「{once: true}」で一度だけ実行)
window.addEventListener('scroll', playVideo, {once: true});
});
ちなみに、loop属性やmuted属性といった属性の設定は、JavaScriptでも追加の操作ができます。
HTML
<video id="myVideo" playsinline preload="none" poster="video/video_thumbnail.jpg">
<source src="video/sample.mp4" type="video/mp4">
<source src="video/sample.webm" type="video/webm">
</video>
HTMLのvideo要素では最低限の設定だけしておいて、JavaScriptのplayVideoの関数で動画を再生する前に、loopメソッドとmutedメソッドを使って属性を追加することができます。
JavaScript
document.addEventListener("DOMContentLoaded", () => {
const video = document.getElementById("myVideo");
const playVideo = () => {
// loop属性とmuted属性を追加
video.loop = true;
video.muted = true;
// 動画データを読み込む
video.load();
// 動画を再生
video.play().catch(error => {
console.log('再生エラー:', error);
});
};
// スクロールイベントをリッスン(「{once: true}」で一度だけ実行)
window.addEventListener('scroll', playVideo, {once: true});
});
スクロール位置で動画の読み込みと再生をする
ここまでで、スクロールイベントで動画データの読み込みと再生ができることがわかりました。
となれば「スクロール時に動画を含むコンテンツが可視範囲に入ったら動画を再生する」といった実装も可能です。
サンプルとして、HTMLのvideo要素にCSSクラス「tgtVideo」を付与しておきます。
HTML
<video id="myVideo" class="tgtVideo" playsinline preload="none" poster="video/video_thumbnail.jpg">
<source src="video/sample.mp4" type="video/mp4">
<source src="video/sample.webm" type="video/webm">
</video>
JavaScriptでは以下のように、対象の要素をconst定数「targetElem」に格納して、スクロールイベントで要素の位置や現在のスクロール位置などと計算させて、対象の要素までスクロールしたら動画を読み込んで再生する処理を実装します。
以下、サンプルコードになります。
JavaScript
document.addEventListener("DOMContentLoaded", () => {
const video = document.getElementById("myVideo");
const targetElem = document.querySelectorAll(".tgtVideo");
let executed = false;
window.addEventListener("scroll", () => {
targetElem.forEach((targetElem) => {
const ePos = targetElem.offsetTop;
const scroll = window.scrollY;
const windowHeight = window.innerHeight;
if (scroll > ePos - windowHeight) {
if (!executed) {
const playVideo = () => {
// loop属性とmuted属性を追加
video.loop = true;
video.muted = true;
// 動画データを読み込む
video.load();
// 動画を再生
video.play().catch(error => {
console.log('再生エラー:', error);
});
};
// スクロールイベントをリッスン(「{once: true}」で一度だけ実行)
window.addEventListener('scroll', playVideo, {once: true});
executed = true;
}
}
});
});
});
ポイントは、スクロール位置の判定だけでなく、スクロールイベントの実行回数のコントロールにあります。
この場合、外側のスクロールイベントはスクロールするたびに実行され、内側のスクロールイベントが{once: true}で一度だけだとしても、その一度だけを何度も実行してしまいます。
内側のスクロールイベントを一度だけの実行させるには、フラグとなる変数(executed)を使って、条件が一度満たされたらその後は実行されないようにする必要があります。
変数「executed」の値がはtrueではなくfalseだった場合は、まだ一度も実行されていませんのでif文のスクロールイベントで実装する動画の読み込みと再生のプログラムが実行されます。一度実行した時に変数「executed」の値をtrueにすることで、次からはif文の条件が満たされなくなるので、一度だけの実行とすることができます。
まとめ
HTMLのvideo要素で読み込む動画は、preload属性を設定することで遅延読み込みが可能となり、コントローラパネル付きで動画を扱う場合は、HTMLのみで手軽に実装できます。
自動再生で動画を扱う場合はJavaScriptの処理が必要になり、スクロールイベントで動画の再生が可能になります。
Webパフォーマンスを高めるため、利用用途に合わせて動画の読み込みをコントロールしてみてください。