Youtubeの埋め込み動画をページのスクロールに合わせて再生したい
商品やサービスのプロモーションとして、Youtubeにアップした動画をサイトやブログに埋め込んで使用することがあります。
せっかく用意した動画なので、ページを見ている人にできるだけ再生してほしいところですが、よほど興味・関心が高いユーザーでない限り、わざわざ再生ボタンを押すことはありません。
関心度が低いユーザーに対する仕掛けとして、動画が見える位置までスクロールされたタイミングで自動的に再生させる、という方法があります。
JavaScriptのスクロールイベントと、Youtubeで提供されているIFrame Player APIを組み合わせることで、スクロールに合わせた再生が実現できます。
本記事では、Youtubeの埋め込み動画をスクロールと連動させて再生する方法についてサンプルコードを交えて紹介します。
また、応用パターンとして、1つのページに複数の動画を埋め込んでいる場合のサンプルコードも掲載しています。
動作イメージ
ページがスクロールされて、動画の上端が見えたタイミングで再生を開始します。
更にスクロールされて、動画の上端がウィンドウ外に見切れたタイミングで再生を停止します。
サンプルコード
html
<iframe id="youtube_player" width="640" height="360" src="https://www.youtube.com/embed/xxxxxxxxxxx?enablejsapi=1&origin=https://www.xxx.com" frameborder="0"></iframe>
JavaScript
window.addEventListener('DOMContentLoaded', function() {
youtubeIframe = document.getElementById('youtube_player');
if(youtubeIframe) {
const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
}, false);
function onYouTubeIframeAPIReady() {
const ytPlayer = new YT.Player('youtube_player', {
events: {
'onReady': onPlayerReady
}
});
}
function onPlayerReady(event) {
switchVideo(event.target);
window.addEventListener('scroll', function() {
switchVideo(event.target);
}, false);
}
function switchVideo(targetPlayer) {
const playerPosition = targetPlayer.getIframe().getBoundingClientRect().top + window.pageYOffset;
const startPosition = window.pageYOffset + window.innerHeight;
const endPosition = window.pageYOffset;
if((playerPosition < startPosition) && (playerPosition > endPosition)) {
targetPlayer.mute();
targetPlayer.playVideo();
}
else {
targetPlayer.pauseVideo();
}
}
サンプルコードの解説
動画の埋め込み
<iframe id="youtube_player" width="640" height="360" src="https://www.youtube.com/embed/xxxxxxxxxxx?enablejsapi=1&origin=https://www.xxx.com" frameborder="0"></iframe>
iframeタグを使ってYoutube動画を埋め込んでいる部分です。
src="https://www.youtube.com/embed/xxxxxxxxxxx?enablejsapi=1&origin=https://www.xxx.com"
動画URLにパラメーターとして「enablejsapi=1」と指定することで、IFrame Player APIを使った動画の制御が有効になります。
2つ目のパラメーターとして「origin=https://www.xxx.com」という形式で動画を配置しているサイトのドメインを指定しています。これは必須ではありませんが、公式ドキュメントにある通り、外部からの不正なアクセスや操作の防止策として、なるべく設定するようにしましょう。
origin はオプションですが、このパラメータを含めると、悪意のあるサードパーティの JavaScript がページに追加されたり、YouTube プレーヤーの制御を奪われたりすることを防止できます。
設定の際は、http"s"や"www"の有無に注意してください。また、末尾に「/」は不要です。
IFrame Player APIの読み込み
window.addEventListener('DOMContentLoaded', function() {
youtubeIframe = document.getElementById('youtube_player');
if(youtubeIframe) {
const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
}, false);
APIの読み込みを行っている部分です。
ページ内に「youtube_player」のidが設定された要素が見つかった場合のみ、APIの読み込みを実行します。
APIの読み込み完了時の処理
function onYouTubeIframeAPIReady() {
const ytPlayer = new YT.Player('youtube_player', {
events: {
'onReady': onPlayerReady
}
});
}
APIの読み込み完了後、自動的に実行される処理です。
埋め込み動画用のクラス「YT.Player」のインスタンスを生成し、初期化を行います。
初期化時の第一引数として、埋め込み動画のiframeに設定されたid「youtube_player」を渡します。
第二引数として、所定のイベント発生時に実行させたい関数を設定します。
サンプルコードでは、動画再生の準備が完了した際のイベント「onReady」が発生した際に、関数「onPlayerReady」が実行されるようにしています。
動画再生の準備が完了した時の処理
function onPlayerReady(event) {
switchVideo(event.target);
window.addEventListener('scroll', function() {
switchVideo(event.target);
}, false);
}
動画が再生可能な状態になったときに実行される処理です。引数の「event」に、再生可能になった動画の情報が渡されています。
ページがスクロールされた状態で画面更新されたときにすぐ再生するため、動画の再生状態を切り替える関数「switchVideo」を一度実行します。
あとは画面のスクロールイベントが発生した際に「switchVideo」が実行されるようイベント登録します。
動画の再生・停止を制御する処理
function switchVideo(targetPlayer) {
const playerPosition = targetPlayer.getIframe().getBoundingClientRect().top + window.pageYOffset;
const startPosition = window.pageYOffset + window.innerHeight;
const endPosition = window.pageYOffset;
if((playerPosition < startPosition) && (playerPosition > endPosition)) {
targetPlayer.mute();
targetPlayer.playVideo();
}
else {
targetPlayer.pauseVideo();
}
}
ウィンドウのスクロール位置と、埋め込み動画の位置をチェックして動画の制御を行う処理です。
const playerPosition = targetPlayer.getIframe().getBoundingClientRect().top + window.pageYOffset;
埋め込み動画の位置を取得している部分です。
引数の「targetPlayer」に対して関数「getIframe」を実行すると、埋め込み動画の要素(iframeタグ)が取得できます。これを使って位置情報を取得します。
「getBoundingClientRect().top」で、表示領域内の上端から要素までの高さを取得、「window.pageYOffset」で表示領域外のスクロール量を取得して、双方を足しています。
const startPosition = window.pageYOffset + window.innerHeight;
const endPosition = window.pageYOffset;
スクロール位置を取得している部分です。
「startPosition」には、表示領域外のスクロール量(window.pageYOffset)とウィンドウの高さ(window.innerHeight)を足したものを格納しています。この値を動画の位置が超えたら再生を開始します。
「endPosition」には、表示領域外のスクロール量(window.pageYOffset)を格納しています。動画の位置がこの値を超えたら再生を停止します。
if((playerPosition < startPosition) && (playerPosition > endPosition)) {
targetPlayer.mute();
targetPlayer.playVideo();
}
else {
targetPlayer.pauseVideo();
}
取得した各種位置情報を使って判定・制御を行っている部分です。
動画の上端がウィンドウ内に表示されたら再生を開始し、動画の上端がウィンドウの外に見切れたら停止させます。
再生の前に「targetPlayer.mute();」で音を消しておかないと、再生ができません。ご注意ください。
1ページに複数のYoutube動画を埋め込んでいる場合
html
<iframe id="player1" class="youtube_player" width="640" height="360" src="https://www.youtube.com/embed/xxxxxxxxxxx?enablejsapi=1&origin=https://www.xxx.com" frameborder="0"></iframe>
<iframe id="player2" class="youtube_player" width="640" height="360" src="https://www.youtube.com/embed/yyyyyyyyyyy?enablejsapi=1&origin=https://www.xxx.com" frameborder="0"></iframe>
<iframe id="player3" class="youtube_player" width="640" height="360" src="https://www.youtube.com/embed/zzzzzzzzzzz?enablejsapi=1&origin=https://www.xxx.com" frameborder="0"></iframe>
各iframeのクラスに「youtube_player」を設定します。id属性にはそれぞれ個別の名前を設定してください(連番形式である必要はありません)。
JavaScript
let youtubeIframes = [];
window.addEventListener('DOMContentLoaded', function() {
youtubeIframes = document.getElementsByClassName('youtube_player');
if(youtubeIframes.length) {
const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
}, false);
function onYouTubeIframeAPIReady() {
const players = [];
for(let i = 0; i < youtubeIframes.length; i++) {
players[i] = new YT.Player(youtubeIframes[i].id, {
events: {
'onReady': onPlayerReady
}
});
}
}
function onPlayerReady(event) {
switchVideo(event.target);
window.addEventListener('scroll', function() {
switchVideo(event.target);
}, false);
}
function switchVideo(targetPlayer) {
const playerPosition = targetPlayer.getIframe().getBoundingClientRect().top + window.pageYOffset;
const startPosition = window.pageYOffset + window.innerHeight;
const endPosition = window.pageYOffset;
if((playerPosition < startPosition) && (playerPosition > endPosition)) {
targetPlayer.mute();
targetPlayer.playVideo();
}
else {
targetPlayer.pauseVideo();
}
}
変更点は、windowのDOMContentLoadedイベント、onYouTubeIframeAPIReadyの2か所になります。
let youtubeIframes = [];
window.addEventListener('DOMContentLoaded', function() {
youtubeIframes = document.getElementsByClassName('youtube_player');
if(youtubeIframes.length) {
const tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
}, false);
function onYouTubeIframeAPIReady() {
const players = [];
for(let i = 0; i < youtubeIframes.length; i++) {
players[i] = new YT.Player(youtubeIframes[i].id, {
events: {
'onReady': onPlayerReady
}
});
}
}
windowのDOMContentLoadedイベントで「youtube_player」クラスが設定された要素をまとめて取得しておきます。
「onYouTubeIframeAPIReady」で「youtube_player」クラスの要素の数だけループを回して、埋め込み動画情報を生成します。
あとは動画ごとに「onPlayerReady」が呼ばれ、制御が行われていくという流れになります。
ご質問など受け付けています
記事の中でわかりにくかったところ、もっと知りたかったこと、間違っていることなど、何でもお気軽にご連絡ください。
ご連絡は下記フォームを利用いただくか、ツイッターアカウント@flat8migi宛てでもOKです。