ホームページにYoutube動画を沢山並べたい。
そんな気分の時はありますでしょうか。
そんな気分って普通はないと思いますよ。
みんな大好きYoutube、イェ-!
どうやって動画を貼り付けるの?
その方法はYoutubeのオフィシャルにあるので参照ください。
動画と再生リストを埋め込む:Youtubeオフィシャル
https://support.google.com/youtube/answer/171780?hl=ja
動画の下の[→共有]ボタンから、[埋め込む]ボタンが出るので押すと、HTML コードがあります。そのコードをコピーして自分のウェブサイトに貼り付けます。
この記事は、ページを下にスクロールしていく段階で、youtube動画を自動で再生させようという趣旨の記録になります。
何を言ってるの?どうやるの?
サンプルを用意しましたのでご確認ください。
【共有】ソースコード
スクロールしたら自動再生したい、共有サンプルは以下になります。
共有サンプルページ
https://astrowave.jp/amnesia_record/scroll_youtube_play.php
要件は以下です。
・スクロールで見えたら自動再生したい。
・表示範囲外に足突っ込んだら停止したい。
・クリックしたらモーダルして音声ありで再生したい。
・表示範囲外に行っても自動再生が停止しないでほしい。【オプション】
・Loopして再生されっぱなしにしたい。【オプション】
埋め込み以外に何か特殊なことをしたい、アクションを起こしたい場合はYoutubeの IFrame Player APIを利用します。
※また、自動再生を使うということは「mute」を使う必要があります。
(スクロール中にいきなり音が鳴るのは問題事項となります。音はクリックのようなユーザーアクションが必須です。)
なんで自動再生にする必要あるんですか?
動いてたら触ってみたいでしょ?
ただアニメーションするだけのバナーと違い、動画は情報量がリッチなので、雰囲気作りとかに利用されがちです。が、通信パケット量がかさみます。
沢山動画があると超格安プランの人にはちょっとギガ的に辛いページ、だよね。
html
<section class="main">
<p>●スクロール再生</p>
<div class="youtube-wrap">
<div class="cont01 portrait-sp">
<div class="video-container">
<div id="youtube_player01" class="youtube_player" data-video-id="Gyh6ccKiu7c" data-video-id-sp="aV4BRjcMg2U" data-video-orientation="landscape" data-video-orientation-sp="portrait"></div>
<a href="javascript:void(0);" class="thumbnail">
<picture>
<source media="(min-width: 768px)" srcset="./img/landscape_movie_cover.webp">
<img src="./img/portrait_movie_cover.webp" alt="">
</picture>
</a>
</div>
</div>
<div class="cont02">
<div class="video-container">
<div id="youtube_player02" class="youtube_player" data-video-id="_XmvErwJJHM" data-video-id-sp="_XmvErwJJHM" data-video-orientation="landscape"></div>
<a href="javascript:void(0);" class="thumbnail">
<img src="./img/landscape_movie_cover.webp" alt="">
</a>
</div>
</div>
<div class="cont03 portrait">
<div class="video-container">
<div id="youtube_player03" class="youtube_player" data-video-id="aV4BRjcMg2U" data-video-id-sp="aV4BRjcMg2U" data-video-orientation="portrait"></div>
<a href="javascript:void(0);" class="thumbnail">
<img src="./img/portrait_movie_cover.webp" alt="">
</a>
</div>
</div>
<div class="cont04">
<div class="video-container">
<div id="youtube_player04" class="youtube_player" data-video-id="Gyh6ccKiu7c" data-video-id-sp="Gyh6ccKiu7c" data-video-orientation="landscape"></div>
<a href="javascript:void(0);" class="thumbnail">
<img src="./img/landscape_movie_cover.webp" alt="">
</a>
</div>
</div>
</div>
</section>
<div class="youtube-modal" id="videoModal">
<div class="youtube-modal__overlay js-video-modal-close"></div>
<div class="youtube-modal__close js-video-modal-close"></div>
<div class="youtube-modal__inner">
<div class="youtube-modal__player" id="videoModalPlayer"></div>
</div>
</div>
基本:
パソコンの時、横長タイプの動画とします。
それを踏まえて以下の設定をしました。
・portrait-sp(4行目)を入れたら、スマホの時は縦タイプ。
・portrait(23行目)を入れたら、パソコンでもスマホでも縦タイプ。
data属性:(4つ)
・data-video-id=”” ←パソコン動画Youtube ID(横長タイプ)
・data-video-id-sp=”” ←スマホ動画Youtube ID(縦タイプ)
・data-video-orientation=”” ←モーダル時のパソコン動画タイプ(横長/縦?)
・data-video-orientation-sp=”” ←モーダル時のスマホ動画タイプ(横長/縦?)
基本パソコンの時は横長タイプを意識しながら、各箇所に手動でYoutubeの動画IDやportrait/landscape を適用してください。
※適用例:運用テクニックの記述
<div id="youtube_player01" class="youtube_player" data-video-id="Gyh6ccKiu7c" data-video-id-sp="aV4BRjcMg2U" data-video-orientation="landscape" data-video-orientation-sp="portrait"></div>
面倒ですか?
運用の作業でしょうか。
慣れるまでちょっと悩みそうかも。
何回かテストすればスグに慣れます。
css
.video-container {
position: relative;
width: 100%;
height: 0;
padding-top: 56.25%;
}
.youtube-wrap .video-container iframe {
pointer-events: none;
}
.youtube_player {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.thumbnail {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
}
.thumbnail img {
width: 100%;
height: 100%;
opacity: 1;
transition: opacity .3s;
object-fit: cover;
}
.thumbnail.is-hidden img {
opacity: 0;
transition: opacity .3s;
}
.modal__bg {
background: #00000080;
height: 100vh;
position: absolute;
width: 100%;
top: 0;
}
.scroll {
overflow-y: auto;
max-height: calc(100svh + -0px);
}
.modal_box {
max-width: unset;
margin: 40px 80px;
background: #e0dfd6;
position: relative;
}
.youtube-modal {
position: fixed;
left: 0;
top: 0;
z-index: 1001;
opacity: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
transition: opacity .3s;
background: #000c;
}
.youtube-modal.is-visible {
opacity: 1;
pointer-events: all;
}
.youtube-modal__inner {
position: relative;
z-index: 2;
}
.youtube-modal__overlay {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.youtube-modal__close {
position: absolute;
right: 0;
top: 0;
width: 50px;
height: 50px;
cursor: pointer;
z-index: 3;
}
.youtube-modal__close:before {
transform: translate(-50%, -50%) rotate(45deg);
}
.youtube-modal__close:after {
transform: translate(-50%, -50%) rotate(-45deg);
}
.youtube-modal__close:before, .youtube-modal__close:after {
content: "";
display: block;
position: absolute;
left: 50%;
top: 50%;
width: 20px;
height: 2px;
background: #fff;
}
.youtube-modal__player {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
background: #000;
}
.youtube-modal__inner:before {
content: "";
display: block;
width: 100%;
padding-top: 56.25%;
}
.youtube-modal[data-video-orientation=portrait] .youtube-modal__inner {
width: auto;
height: 80vh;
max-width: unset;
z-index: 2;
}
.portrait {
width: 100%;
max-width: 56.375%;
margin: 0 auto;
}
.portrait .video-container {
padding-top: 177.777%;
}
@media (797px <= width) {
.youtube-modal[data-video-orientation=portrait] .youtube-modal__inner {
height: 80vh;
}
.youtube-modal[data-video-orientation=portrait] .youtube-modal__inner:before {
width: auto;
height: 100%;
padding-top: 0;
padding-left: calc(80vh* .56375);
}
.youtube-modal[data-video-orientation=portrait] .youtube-modal__inner:before {
padding-left: calc(80vh* .56375);
}
.youtube-modal__inner {
width: 80%;
max-width: 130vh;
}
}
@media (width < 769px) {
.youtube-modal[data-video-orientation=portrait] .youtube-modal__inner {
width: 100%;
max-width: 56.375vh;
height: auto;
}
.youtube-modal[data-video-orientation=portrait] .youtube-modal__inner:before {
padding-left: 0;
padding-top: 177.38%;
}
.portrait-sp .video-container {
padding-top: 177.777%;
}
.youtube-modal__inner {
width: 100%;
}
}
動画のレスポンシブって、cssは記述が長くなりがちです。
あまり見ないcssが1つあります。
data属性の判別、.youtube-modal[data-video-orientation=portrait]と書かれている部分です。
portrait/landscape (縦/横向き)の、portraitということは縦タイプの動画に気を使っている感じですね。
こんなcss指定知ってました?
私は知らなかったです。
今回、そのdata属性(data-video-orientation)は、
モーダルをさせた時に働くcssとして設定しました。
下のscript(114行目)で、<div class="youtube-modal" id="videoModal">にdata属性が書き込まれるようにしています。
script
<script>
var ytPlayer = [];
var ytEvent = {
"onReady": onPlayerReady,
"onStateChange": onPlayerStateChange
};
var tag = document.createElement("script");
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 画面幅でPCかスマホかを判定する関数
function isMobile() {
return window.innerWidth < 769;
}
function onYouTubeIframeAPIReady() {
$(".youtube_player").each(function (index, element) {
// 画面幅に応じてdata-video-idかdata-video-id-spを取得
var videoId = isMobile() ? $(element).data('video-id-sp') : $(element).data('video-id');
ytPlayer[index] = new YT.Player(element.id, {
height: '100%',
width: '100%',
videoId: videoId,
events: ytEvent,
playerVars: { autoplay: 0, playsinline: 1, mute: 1 }
});
});
}
function onPlayerReady(event) {
var playerId = event.target.getIframe().id;
var container = $(`#${playerId}`).closest('.video-container');
container.find('.thumbnail').removeClass('is-hidden');
checkAndPlaySingleVideo(event.target);
}
function onPlayerStateChange(event) {
var playerId = event.target.getIframe().id;
var container = $(`#${playerId}`).closest('.video-container');
var thumbnail = container.find('.thumbnail');
if (event.data === YT.PlayerState.PLAYING) {
thumbnail.addClass('is-hidden'); // 再生中はサムネイルを隠す
} else if (event.data === YT.PlayerState.PAUSED || event.data === YT.PlayerState.ENDED) {
thumbnail.removeClass('is-hidden'); // 一時停止または終了時にサムネイルを表示
}
}
window.addEventListener("scroll", function() {
checkAndPlayVideos();
});
function checkAndPlayVideos() {
$(".youtube_player").each(function (index, element) {
checkAndPlaySingleVideo(ytPlayer[index]);
});
}
function checkAndPlaySingleVideo(player) {
if (player && typeof player.getIframe === "function") {
var iframe = player.getIframe();
var iframeTop = iframe.getBoundingClientRect().top;
var iframeBottom = iframe.getBoundingClientRect().bottom;
// 画面内にプレイヤーがあるかを判定
if (iframeTop >= 0 && iframeBottom <= window.innerHeight) {
player.mute(); // 自動再生時にはミュート
player.playVideo();
} else {
player.pauseVideo();
}
}
}
// ----------------------------
// モーダル用のYouTubeプレイヤー変数
// ----------------------------
var modalPlayer;
// モーダルの要素
var videoModal = document.getElementById('videoModal');
var videoModalCloseButtons = document.querySelectorAll('.js-video-modal-close');
// 画面幅でPCかスマホかを判定する関数
function isMobile() {
return window.innerWidth < 769;
}
// サムネイルクリックでモーダル表示 & 動画再生
$(".thumbnail").on("click", function () {
var container = $(this).closest('.video-container');
var videoPlayer = container.find('.youtube_player');
var videoIdSp = videoPlayer.data('video-id-sp');
var videoId = videoPlayer.data('video-id');
var orientationSp = videoPlayer.data('video-orientation-sp'); // スマホ用のorientation
var orientation = videoPlayer.data('video-orientation'); // PC用のorientation
// スマホかPCかで動画IDとorientationを決定
var videoToPlay = isMobile() ? videoIdSp : videoId;
var orientationToUse = isMobile() && orientationSp ? orientationSp : orientation;
// モーダル表示
showModal(videoToPlay, orientationToUse);
});
// モーダルを表示して動画を再生する関数
function showModal(videoId, orientation) {
// モーダルに is-visible クラスを追加し、data-video-orientationを設定
var videoModal = document.getElementById('videoModal');
videoModal.classList.add('is-visible');
videoModal.setAttribute('data-video-orientation', orientation);
// プレイヤーが初期化されていない場合、初期化する
if (!modalPlayer) {
modalPlayer = new YT.Player('videoModalPlayer', {
height: '100%',
width: '100%',
videoId: videoId,
playerVars: {
autoplay: 1,
playsinline: 1
}
});
} else {
// 既存プレイヤーに新しい動画IDをロード
modalPlayer.loadVideoById(videoId);
}
}
// モーダルを閉じて動画を停止する関数
function closeModal() {
// モーダルから is-visible クラスを削除
var videoModal = document.getElementById('videoModal');
videoModal.classList.remove('is-visible');
// 動画を停止
if (modalPlayer) {
modalPlayer.stopVideo();
}
}
// モーダルのクローズボタンにイベントを追加
var videoModalCloseButtons = document.querySelectorAll('.js-video-modal-close');
videoModalCloseButtons.forEach(function (closeButton) {
closeButton.addEventListener('click', function () {
closeModal();
});
});
// モーダル外をクリックしても閉じる処理
var videoModal = document.getElementById('videoModal');
videoModal.addEventListener('click', function (e) {
if (e.target === videoModal || e.target.classList.contains('js-video-modal-close')) {
closeModal();
}
});
</script>
スクリプトも長いです。すみません。
Youtubeの IFrame Player APIを利用していることがわかると思います。
・パソコンとスマホで、動画の種類を変えるyoutubeの動画idの変更(21行目)
・パソコンとスマホで、モーダルの時のyoutubeの動画idの変更(102〜103行目)
以上が気を使う部分でしょうか。
あまり複雑にしたくなかったので。
もしスマホ用の動画(data-video-id-sp="")がなかったら、という分岐は設けませんでした。パソコンもスマホも同じ横長タイプなら、data-video-id-sp=""にもパソコン用の動画idを仕込んでください。
※AIさんがすぐ改修対応できると言ってましたが、やめときました。
より詳しい解説はchatGPTさんに放り込んでください。
【オプション】ありそうな要件
【オプション】表示範囲外に行っても自動再生が停止しないでほしい。
サムネイル画像がパカパカと出たり消えたりするのがウザい。
そういうことを言われましたでしょうか。
動画プレイヤーがちょっとでも画面に入ったら自動再生したい場合。
checkAndPlaySingleVideo 関数を改修します。
function checkAndPlaySingleVideo(player) {
if (player && typeof player.getIframe === "function") {
var iframe = player.getIframe();
var iframeRect = iframe.getBoundingClientRect();
// プレイヤーの一部が画面に表示されているかを判定
var isVisible = iframeRect.top < window.innerHeight && iframeRect.bottom > 0;
if (isVisible) {
player.mute(); // 自動再生時にはミュート
player.playVideo();
}
}
}
ソースが長くて疲れます。
【オプション】Loopして再生されっぱなしにしたい場合。
以下の関数を変更します。
function onYouTubeIframeAPIReady() {
$(".youtube_player").each(function (index, element) {
// videoIdを取得し、ログに出力して確認
var videoId = isMobile() ? $(element).data('video-id-sp') : $(element).data('video-id');
console.log("videoId for player", index, videoId); // ログを追加して確認
ytPlayer[index] = new YT.Player(element.id, {
height: '100%',
width: '100%',
videoId: videoId, // videoIdが適切に設定されているか確認
events: ytEvent,
playerVars: { autoplay: 0, playsinline: 1, mute: 1, controls: 0, loop: 1, playlist: videoId }
});
});
}
ループを1にして、ループする動画指定を入れます。
playerVars: { autoplay: 0, playsinline: 1, mute: 1, controls: 0, loop: 1, playlist: videoId }
function onPlayerStateChange(event) {
var playerId = event.target.getIframe().id;
var container = $(`#${playerId}`).closest('.video-container');
var thumbnail = container.find('.thumbnail');
if (event.data === YT.PlayerState.PLAYING) {
thumbnail.addClass('is-hidden'); // 再生中はサムネイルを隠す
}
// 動画が終了したときにはサムネイルを表示しない(ループ再生のため)
else if (event.data === YT.PlayerState.PAUSED) {
thumbnail.removeClass('is-hidden'); // 一時停止時にサムネイルを表示
}
}
YT.PlayerState.ENDED の処理変更: 動画がループする際に YT.PlayerState.ENDED が発生しますが、この時点でサムネイルを表示せず、再ループまで待ちます。
【AI】イラストを描いてもらった
今回の記事のキャッチ画像で使わせてもらいます「Memeplex.app」で作成した画像です。誰でもgoogleアカウントでログインして使えます。
この記事にピッタリなイラストのための考えたリクエストは、「ハイテクな部屋の壁一面に整然と敷き詰められたモニターへ映し出される各国の監視映像に驚く捜査官」です。
選んだモードは以下の3つです。
・特撮
・サイバーパンク風
・UnrealEngine5風

参考サイト置き場
参考にさせていただきました。ありがとうございます。
動画と再生リストを埋め込む:Youtubeオフィシャル
https://support.google.com/youtube/answer/171780?hl=ja
Youtubeの IFrame Player APIを利用します。