本日も業務内で発生した問題を解決したので、記載していきます。
今回は、videoタグで動画を埋め込み、それをjsで制御する。と、いったものです。
正直、動画の再生制御は実装したことがなく、調べながらの作業でした。
多くはありませんが、動画を採用しているサイトは見かけるので、今回学習したことを記録しておこうと思います。
JavaScriptを使用して動画をコントロールする。
最初にvideoタグについて詳しく知りたい方は、以下のリンクからご覧ください。
今回は、videoタグについて書いていこうと思います。 先日、案件でメインビジュアルに動画を設置するというものがあり、さらにPCとSPで動画を切り替えて欲しいと言う要望もありました。レスポンシブに対応させる方法など調べて実装してみた[…]
動画の制御というと、controls属性を使って、動画をコントロールする方法がありますが、今回はそうでなく、デザインを重視した方法でコントロールする方法をご紹介します。
あと、今回の動画は、メインビジュアルに設置します。
CSSアニメーションでメインビジュアルを表現するのではなく、その代わりに動画を設置する。といった形です。
動画終了後に動画は非表示にして、動画終了の画面と同じ画像が現れるようにしていきます。
以上のことを踏まえて、実装に必要な機能を整理していきます。
必要な機能。
まずは、必要な機能、条件みたいなものを書き出しておきます。
- 動画の再生終了後は、動画を非表示。
- 動画の再生中には、動画をスキップさせるためのボタンを設置する。
- 動画再生終了後には、動画のリプレイボタンを設置して、再度再生可能な状態にする。
- 動画は、PCとSPで表示させる画像が違う。
冒頭でお伝えした機能にプラス、動画をコントールするための機能を実装していきます。
2〜4の条件は、動画を設置するにあたり、ご依頼主様よりいただいた条件です。
srcの切り替えは、.attr();を使用。.play();と.pause();で動画のをコントロールする。(完成コード)
それでは、この条件をそれぞれ解決したコードを先に紹介しておきます。
//html
<div id="opv-wrap">
<div id="movie_skipBtn"><a>SKIP</a></div>
<video id="opv" autoplay muted playsinline src=""></video>
</div>
<div id="movie_replayBtn"><a>REPLAY</a></div>
//js
const opvWrap = $('#opv-wrap');
const opVideo = $('#opv').get(0);
const video = $('#opv');
const main = $('main');
const replayBtn = $('#movie_replayBtn');
const skipBtn = $('#movie_skipBtn');
const windowSp = window.matchMedia('(max-width:799px)').matches;
movieSwitch();
$(document).on('lead', function() {
setTimeout(function() {
opvWrap.fadeIn(1000);
}, 500);
});
opVideo.addEventListener('ended', function() {
movieStop();
});
replayBtn.on('click', function() {
opVideo.play();
opvWrap.fadeIn();
$(this).fadeOut();
skipBtn.fadeIn();
main.removeClass('js-movieEnd');
});
skipBtn.on('click', function() {
opVideo.pause();
movieStop();
});
function movieStop() {
$('#opv-wrap').fadeOut();
main.addClass('js-movieEnd');
replayBtn.fadeIn();
}
function movieSwitch() {
if(windowSp) {
video.attr("src", "/sp/movie/mv.mp4");
} else {
video.attr("src", "/movie/mv.mp4");
}
}
</script>
それでは、それぞれ解説していきます。
.attr();でvideoのsrcを切り替える。
動画は、pcとspで違うものを再生させます。
レスポンシブに切り替えなくてはならないので、jsでウインドウ幅を検知させ、.attr();でsrcの中を切り替えます。
const windowSp = window.matchMedia('(max-width:799px)').matches;
movieSwitch();
function movieSwitch() {
if(windowSp) {
video.attr("src", "/sp/movie/mv.mp4");
} else {
video.attr("src", "/movie/mv.mp4");
}
}
ifで条件分岐されていますので、条件を変更・追加してあげれば、細かく動画を切り替えることも可能です。
PC→タブレット→SPといいた具合に。
videoタグにsourceを使用してmediaで動画を切り替える方法もある。
jsは、めんどくさい。ので、HTMLで切り替える方法もありますが・・・
iPhone(Safari)ではうまく動作しませんでした。
<video id="opv" autoplay muted playsinline>
<source src="/movie/mv.mp4" type="video/mp4" media="(max-width: 799px)">
<source src="/movie/mv.mp4" type="video/mp4">
</video>
ブレイクポイントを media=”(max-width: 799px)としていすることで、読み込まれる動画が切り替わるのですが、なぜか切り替わりません。
Androidは、問題なくsourceで切り替えることができました。
$(document).on(‘lead’, function(){});を使用して全て読み込まれてから動画を表示させる。
続いてjsですが、まずは動画を格納している要素全体を取得しておきます。
<div id="opv-wrap">
<div id="movie_skipBtn"><a>SKIP</a></div>
<video id="opv" autoplay muted playsinline src=""></video>
</div>
<div id="movie_replayBtn"><a>REPLAY</a></div>
上記でいうところの「id=”opv-wrap”」の部分ですね。
$(document).on('lead', function() {
setTimeout(function() {
opvWrap.fadeIn(1000);
}, 500);
});
js発火のタイミングの注意点としては、Webサイト全体が読み込まれてから動画を表示させるようにします。
そしないと、Webサイトが読み込まれている最中に動画の再生が始まってしまい、表示されたときには動画が途中からになっていることがあります。
特にメインジュアルに動画を置いている場合、早い段階で読み込まれてしまうので、Webサイトが完全に読み込まれていない状態で動画がスタートしてしまうことが多くありました。
その結果、動画も再生はされているがみることができず、やっと見れるようになっても動画が進んでしまっていました。
setTimeoutは、念のための対策です。
Webサイト読み込み完了から少しタイムラグを設けることで、動画再生のタイミングをサイトが読み込まれたあと、さらに遅延させています。
タイムラグを設けることで、一呼吸おいてから動画の再生を始めることができます。
発火タイミングが.ready();ではいけない理由。
結論から言うと、別に.ready();でもいいです。
ただ、やはりすべて読み込まれてから動画の再生をしてからの方がいいと思います。
理由としては、ページの表示速度です。
今回は、動画をメインビジュアルに設置しているため、ページ下部の画像よりも先に動画が読み込まれて再生が始まります。
すると、動画の再生中にページの読み込まれる関係か、表示速度が遅くなっている気がします。(気のせいかな?)
その点、.on(‘lead’);は全て(HTML構造、画像などのリソース)が読み込まれたあとに動画が再生するので、ページが完全に表示されてから再生が始まります。
動画の影響でページの読み込み速度が遅くなることもありませんし、動画も最初から再生されます。
以上のことから、私は.on(‘lead’);で発火させています。
addEventListener(‘ended’, function() {});で動画の終了を検知する。
上記までで、動画が無事に読み込まれ、再生されました。
次は、動画が終了したときの動作です。
$(document).on('lead', function() {
setTimeout(function() {
opvWrap.fadeIn(1000);
}, 500);
});
.on(‘lead’, function() {});で、動画を再生させたら再生終了後は、動画要素全体を非表示にしたいので、「addEventListener(‘ended’, function() {});」の記述を使います。
opVideo.addEventListener('ended', function() {
$('#opv-wrap').fadeOut();
main.addClass('js-movieEnd');
replayBtn.fadeIn();
});
endedで動画の再生の終了を検知して、再生が終了したら要素を非表示にして、その後に「リプレイボタン(replayBtn.fadeIn();)」を表示させています。
.play();で意図的に動画を再生させる。
続いては、再生が完了した動画をリプレイボタンで、再度再生させます。
replayBtn.on('click', function() {
opVideo.play();
opvWrap.fadeIn();
$(this).fadeOut();
skipBtn.fadeIn();
});
ここで、ポイントとなるのは.play();です。
.play();は、動画を再生させることができます。
動画の要素を取得して、そこに.play();を指定してあげます。
スキップされたときは、.pause();で動画を一時停止させる。
最後は、動画の一時停止です。
冒頭でお話ししましたが、videoタグにcontrols属性をつけることで動画をコントロールすることはできますが、デザイン的な問題があります。
そんなときは、自身で作ったボタン要素に.pause();を指定してあげて、動画をコントロールします。
skipBtn.on('click', function() {
opVideo.pause();
$('#opv-wrap').fadeOut();
replayBtn.fadeIn();
});
動画を再生するのと同時に、リプレイボタンは非表示にしてあげます。
共通部分は、関数化しておくと見やすくなる。
以上、今回の条件をクリアして、動画をコンロールすることができました。
「動画の制御」ということで、少し難しく感じたかもしれませんが、やってみると初心者でもできるほど簡単な記述で制御することができます。
最後になりましたが、今回記述したjsの内容は、共通部分を関数にすることで、実行の記述をもっと簡素化することもできます。
例えば、下記のように動画の要素を非表示にしたとき、リプレイボタンを表示、スキップボタンを非表示にする。といった動作は一連の動作になります。
function movieStop() {
$('#opv-wrap').fadeOut();
main.addClass('js-movieEnd');
replayBtn.fadeIn();
}
共通の部分は、関数にすると繰り返し同じ動作を書かなくていいので、少し長いjsを書くときは意識してみるといいかもしれません。
使用するときは、使いたい処理の中で関数を宣言してあげるだけです。
movieStop();
可読性が上がるので、試してみてください。