動画をファーストビューに自動再生ループで置く方法|YouTube APIの実装手順

動画をファーストビューに自動再生ループで置くには、YouTubeのIFrame Player APIでプレーヤーを生成し、ミュート状態で再生を開始したうえで、再生終了イベントを拾って再生し直します。埋め込みコードにloop=1を付けるだけでは、ループも自動再生も安定しません。この記事では、受け皿のHTMLからプレーヤーの生成、画面全面をカバーするCSS、スマホでの落とし穴まで、実際に動く形のコードで順番に解説します。

目次

結論:APIで実現できるが、まず自社MP4を検討する

MacBook Pro on top of brown wooden table during daytime
Photo by Le Buzz Studio on Unsplash

先に結論を書きます。YouTube IFrame Player APIを使えば、ファーストビューでの自動再生ループは問題なく実装できます。ただし制作の現場では、まず「自社サーバーに置いた短いMP4で足りないか」を検討します。理由は3つです。

  1. APIを使うとiframe_apiのスクリプトとプレーヤー一式を読み込むため、ページで最も重い場所に最も重い部品を置くことになる
  2. YouTube側の仕様変更で挙動が変わるリスクを、ページの一等地で抱えることになる
  3. 10〜15秒のループ映像なら、MP4を自前で配信したほうが軽く、確実に動く

それでもAPIを選ぶ理由があるとすれば、素材がすでにYouTubeにあって差し替え運用をYouTube側で完結させたい、長尺の映像を使いたい、動画の視聴データをYouTube側で見たい、といったケースです。判断基準は記事の後半で表にまとめました。まず読み込みの重さそのものを避けたい方は、動画を軽く埋め込む方法のほうを先に読んでください。

全体像:必要な部品は3つだけ

実装は次の3点セットでできています。ここを押さえておくと、後の手順で迷いません。

部品役割
受け皿のdivAPIがここをiframeに差し替える。IDを付けておく
iframe_apiのスクリプト読み込みが完了するとonYouTubeIframeAPIReadyが自動で呼ばれる
YT.Playerのインスタンスプレーヤー本体。パラメータとイベントをここで設定する

重要なのは、onYouTubeIframeAPIReadyという関数名が固定だという点です。この名前でグローバルに定義しておくと、APIの読み込み完了時にYouTube側から呼び出されます。自分で呼ぶ必要はありません。

ステップ1:受け皿のHTMLを書く

ファーストビューの構造を作ります。動画の上にキャッチコピーを重ねる前提で、レイヤーを3層に分けておくと後の調整が楽です。

<section class="hero">
  <div class="hero__video" aria-hidden="true">
    <div id="hero-player"></div>
  </div>
  <div class="hero__overlay" aria-hidden="true"></div>
  <div class="hero__inner">
    <h1>ここにキャッチコピー</h1>
    <p>サブコピーやボタンを置きます</p>
  </div>
</section>

動画とオーバーレイにはaria-hidden="true"を付けます。背景として流しているだけの映像を、スクリーンリーダーが読み上げる対象にしないためです。id="hero-player"のdivは、後でAPIによってiframeに置き換わります。この中に何かを書いても消えるので、空のままにしておいてください。

ステップ2:IFrame Player APIを読み込む

APIのスクリプトを読み込みます。公式のリファレンスではJavaScriptで動的に挿入する書き方が紹介されていますが、単純にscriptタグで読み込んでも動きます。

<script src="https://www.youtube.com/iframe_api"></script>
<script src="/assets/hero-video.js"></script>

注意点として、この2本にはdeferasyncを付けないでください。onYouTubeIframeAPIReadyを定義する自作スクリプトが、APIの読み込み完了より後に実行されてしまうと、コールバックが呼ばれず何も起きません。順番を確実にしたいなら、</body>の直前にこの順で並べるのが最も安全です。

ステップ3:プレーヤーを生成する

man in black long sleeve shirt using computer
Photo by Mohammad Rahmani on Unsplash

ここが本体です。hero-video.jsに次の内容を書きます。

var heroPlayer;
var HERO_VIDEO_ID = 'VIDEO_ID';

function onYouTubeIframeAPIReady() {
  heroPlayer = new YT.Player('hero-player', {
    videoId: HERO_VIDEO_ID,
    playerVars: {
      autoplay: 1,
      controls: 0,
      disablekb: 1,
      fs: 0,
      rel: 0,
      playsinline: 1,
      iv_load_policy: 3,
      loop: 1,
      playlist: HERO_VIDEO_ID,
      origin: window.location.origin
    },
    events: {
      onReady: onHeroReady,
      onStateChange: onHeroStateChange
    }
  });
}

playerVarsで指定している内容

背景動画として使うため、操作させる要素をすべて消しています。controls: 0で操作UIを、disablekb: 1でキーボード操作を、fs: 0で全画面ボタンを、iv_load_policy: 3でアノテーションを消しています。playsinline: 1はiOSでインライン再生させるために必須です。これがないと、再生時に全画面へ切り替わってレイアウトが崩れます。

originには自サイトのオリジンを渡します。enablejsapiを有効にしてAPIから制御する場合、公式ドキュメントでも指定が推奨されている項目です。YT.Playerで生成する場合はenablejsapiが自動で有効になるため、明示的に書く必要はありません。

ステップ4:自動再生を成立させる(ミュートの正しい書き方)

ここでつまずく人が最も多いはずです。音が出る状態での自動再生は、主要ブラウザで原則ブロックされます。つまり自動再生を成立させるには、必ずミュート状態で始める必要があります。

playerVarsのmuteに頼らない

解説記事でよく見るmute: 1という指定ですが、muteはGoogleのプレーヤーパラメータ公式一覧に掲載されていません。慣用的に使われている非公式のパラメータです。動く場面は多いものの、仕様として保証されたものではないため、ファーストビューという失敗できない場所では使わないほうが安全です。

onReadyでmute()してから再生する

function onHeroReady(event) {
  event.target.mute();
  event.target.playVideo();
  document.querySelector('.hero').classList.add('is-video-ready');
}

APIのmute()メソッドは公式に定義されたメソッドです。プレーヤーの準備が整ったonReadyの時点で確実にミュートしてからplayVideo()を呼べば、自動再生がブロックされる条件を外せます。最後の1行は、動画の準備ができたことをCSS側に伝えるためのクラス付与です。これを使って、静止画から動画へ滑らかに切り替えます。

音を出したい場合は必ずボタンを置く

document.querySelector('.hero__sound').addEventListener('click', function () {
  if (heroPlayer.isMuted()) {
    heroPlayer.unMute();
    this.setAttribute('aria-pressed', 'true');
  } else {
    heroPlayer.mute();
    this.setAttribute('aria-pressed', 'false');
  }
});

音声付きで見せたい場合は、ユーザーの操作を起点にするしかありません。ミュート解除ボタンを重ねて置き、押されたときにunMute()を呼びます。勝手に音が鳴るサイトは離脱の原因になるため、たとえ技術的に可能でも避けてください。

ステップ5:確実にループさせる

loop: 1を指定してもループしない、という相談は非常に多いです。原因は仕様にあります。

loopにはplaylistの指定が必須

単一の動画をループさせる場合、loopだけでは効きません。playlistパラメータに同じ動画IDを指定する必要があります。ステップ3のコードでplaylist: HERO_VIDEO_IDと、videoIdと同じ値を渡しているのはこのためです。ここが抜けていると、1回再生して止まります。

それでも止まるのでイベントで補強する

function onHeroStateChange(event) {
  if (event.data === YT.PlayerState.ENDED) {
    heroPlayer.seekTo(0);
    heroPlayer.playVideo();
  }
}

loopplaylistを正しく指定しても、再生開始位置をstartで指定していたり、通信状況が悪かったりすると、末尾で止まることがあります。再生状態の変化を拾って、終了したら先頭に戻して再生し直す処理を入れておけば確実です。制作では、この2行を保険として必ず入れています。

一部分だけを繰り返したいとき

var LOOP_START = 12;
var LOOP_END = 27;

function onHeroStateChange(event) {
  if (event.data === YT.PlayerState.PLAYING) {
    clearInterval(heroPlayer.__timer);
    heroPlayer.__timer = setInterval(function () {
      if (heroPlayer.getCurrentTime() >= LOOP_END) {
        heroPlayer.seekTo(LOOP_START);
      }
    }, 250);
  }
}

長尺の動画から「12秒目から27秒目まで」だけを繰り返したい場合は、再生位置を定期的に監視して、終点に達したら始点へ戻します。endパラメータを使う方法もありますが、終点で停止扱いになりループと相性が悪いため、この書き方のほうが安定します。

ステップ6:画面全面をカバーするCSS

silver MacBook Air on table near iMac
Photo by UX Store on Unsplash

YouTubeのプレーヤーは16対9の比率で表示されます。ファーストビューの縦横比はこれと一致しないため、そのままでは上下か左右に余白ができます。画面の比率に応じて拡大し、はみ出した分を隠す形にします。

.hero {
  position: relative;
  width: 100%;
  height: 100svh;
  overflow: hidden;
  background: #111 center/cover no-repeat url("/img/hero-fallback.jpg");
}
.hero__video {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100vw;
  height: 56.25vw;        /* 100vw × 9 ÷ 16 */
  min-width: 177.78svh;   /* 100svh × 16 ÷ 9 */
  min-height: 100svh;
  pointer-events: none;
  opacity: 0;
  transition: opacity .8s ease;
}
.hero.is-video-ready .hero__video { opacity: 1; }
.hero__video iframe { width: 100%; height: 100%; border: 0; }
.hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,.45), rgba(0,0,0,.25));
}
.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  height: 100%;
  color: #fff;
  text-align: center;
}

ポイントは4つ

1つ目は56.25vw177.78svhの組み合わせです。横長の画面では幅を基準に、縦長の画面では高さを基準に拡大されるので、どちらでも隙間ができません。2つ目はpointer-events: noneで、これがないとiframeがクリックを奪い、上に置いたボタンが押せなくなります。

3つ目は.heroの背景に指定したフォールバック画像です。動画が再生されるまで、そして自動再生がブロックされた環境では、この静止画が見えます。動画と同じ構図の画像を用意しておけば、再生されなくても見た目が破綻しません。4つ目は100svhで、スマートフォンのアドレスバーの伸縮によって高さが変動する問題を避けられます。

文字を読ませるためのオーバーレイ

映像の上に白文字を重ねると、明るいシーンで読めなくなります。半透明の黒をグラデーションで重ねておけば、映像の明暗が変わっても最低限のコントラストを確保できます。アクセシビリティの基準では、通常サイズの文字で4.5対1のコントラスト比が求められます。映像は常に動くので、最も明るいフレームを基準に確認してください。

ステップ7:スマホ対応とフォールバック

ファーストビューの動画で最も事故が起きるのがスマートフォンです。次の3点を必ず入れてください。

省電力モードでは再生されない前提で作る

iOSの低電力モードや、通信量節約の設定が有効な端末では、ミュートしていても自動再生がブロックされることがあります。これは制作側から回避できません。だからこそステップ6のフォールバック画像が重要になります。「再生されなくても成立する画面」を先に作り、動画は上乗せの演出だと考えてください。

スマホでは動画を読み込まない選択もある

var isSmall = window.matchMedia('(max-width: 767px)').matches;
var saveData = navigator.connection && navigator.connection.saveData;

function onYouTubeIframeAPIReady() {
  if (isSmall || saveData) { return; }   // 静止画のままにする
  heroPlayer = new YT.Player('hero-player', { /* 以下同じ */ });
}

スマートフォンでは動画そのものを読み込まず、静止画で見せるという判断もあります。縦画面では16対9の映像を大きく拡大して切り抜くことになり、意図した構図が伝わらないケースが多いためです。通信量節約設定をsaveDataで検出して除外しておくのも、ユーザーへの配慮として有効です。

視差効果を減らす設定を尊重する

@media (prefers-reduced-motion: reduce) {
  .hero__video { display: none; }
}

OSの設定で「視差効果を減らす」を有効にしているユーザーは、動きのある表現で不快感や体調不良を感じる場合があります。prefers-reduced-motionを見て動画を非表示にし、フォールバック画像だけを見せる分岐を入れておいてください。これはアクセシビリティ診断でも確認される項目です。

背景動画で使うパラメータ早見表

パラメータ推奨値役割
autoplay1読み込み後に再生を開始する。ミュートとの併用が前提
controls0操作UIを消す。背景として使うなら必須
disablekb1キーボードでの誤操作を防ぐ
fs0全画面ボタンを消す
playsinline1iOSでインライン再生させる。抜けると全画面になる
loop1ループ再生。playlistとセットでないと効かない
playlistvideoIdと同じ値単一動画をループさせるために必要
rel0終了後の関連動画を同一チャンネル内に限定する
iv_load_policy3アノテーションを非表示にする
origin自サイトのオリジンAPI制御時のセキュリティ対策として指定する

表にmuteを入れていないのは意図的です。前述のとおり公式一覧にないため、onReadymute()を呼ぶ方法を使ってください。同じ理由で、ロゴを控えめにするmodestbrandingも入れていません。こちらは2023年8月15日に廃止されており、指定しても効果がありません。

動かないときのチェックリスト

graphical user interface, text, application
Photo by Nebular on Unsplash

プレーヤーが表示されない

まずonYouTubeIframeAPIReadyが呼ばれているか、関数の先頭にログを入れて確認します。呼ばれていない場合は、スクリプトの読み込み順かdeferの付け忘れが原因です。呼ばれているのに表示されない場合は、YT.Playerの第1引数に渡したIDと、HTMLのid属性が一致しているかを見てください。この関数はグローバルスコープに置く必要があるため、モジュール内やDOMContentLoaded内で定義していると呼ばれません。

再生が始まらない

ミュートの処理が抜けている可能性が高いです。onReadyの中でmute()playVideo()より先に呼んでいるか確認してください。順番が逆だと、再生を試みた時点でブロックされます。あわせて、その動画が埋め込みを許可しているかも確認します。チャンネル側の設定や権利者の制限で埋め込みが無効になっている動画は、どう書いても再生されません。

ループせずに止まる

playlistパラメータに動画IDを指定しているか確認してください。ここが最も多い原因です。指定済みなら、ステップ5のonStateChangeによる補強を入れます。再生位置をstartで指定している場合は、ループ時に先頭ではなくその位置へ戻したいはずなので、seekTo(0)0を開始秒数に変えてください。

上に重ねたボタンが押せない

pointer-events: noneの指定漏れです。iframeは前面でクリックを受け取るため、これがないと下層のように見えていても操作を奪います。あわせて.hero__innerposition: relativez-indexが効いているかも確認してください。

上下に黒帯が出る・構図が切れる

黒帯が出るのはmin-widthmin-heightの計算が合っていないケースです。56.25vw177.78svhの数値を確認してください。構図が切れるのは拡大による切り抜きなので、CSSでは解決しません。被写体を中央寄りに配置した素材を用意するか、画面幅ごとにobject-positionに相当する位置調整(transformの平行移動)を加えます。

YouTube APIと自社MP4の使い分け

観点YouTube IFrame Player API自社サーバーのMP4
初期読み込みプレーヤー一式で1MB前後動画ファイルのみ。2MB以下に抑えられる
表示速度への影響大きい。ファーストビューでは特に不利小さい。posterで先に絵を出せる
実装量JavaScriptが必要videoタグと属性だけで済む
長尺への対応得意。配信はYouTube任せ不向き。容量がそのまま負荷になる
差し替え運用YouTube側で完結するサーバーへの再アップロードが必要
UIの完全制御ロゴやUIを完全には消せない完全に制御できる
視聴データYouTube側で取得できる自前で計測が必要

判断はシンプルです。15秒前後の短いイメージ映像をループさせたいだけなら、自社MP4を選んでください。ファーストビューの表示速度は問い合わせ率に直結するため、ここに1MBのスクリプトを置く判断は慎重にすべきです。逆に、既存のブランドムービーをそのまま流用したい、映像を頻繁に差し替える運用がある、といった事情があればAPIが向いています。

もう1点、YouTubeを背景動画として使う場合はロゴやUIを完全には消せない仕様である点も踏まえてください。ブランドサイトで映像だけを見せたいという要件があるなら、この時点で自社配信を選ぶことになります。

よくある質問(FAQ)

音声付きで自動再生することはできませんか?

できません。ユーザーの操作なしに音を出す自動再生は、主要ブラウザで原則ブロックされます。制作側で回避する手段はないため、ミュートで自動再生し、ミュート解除ボタンを置く形が唯一の解になります。

ファーストビューに動画を置くとSEOで不利になりますか?

動画を置くこと自体がペナルティになるわけではありません。ただし表示速度が落ちればページ体験の評価に影響します。特にファーストビューはLCPの計測対象になりやすい場所です。フォールバック画像を軽くしておき、その画像がすぐ表示される状態を作ることが、結果的にSEO面でも有利に働きます。

限定公開の動画でも使えますか?

限定公開(リンクを知っている人のみ)の動画は埋め込めます。非公開(プライベート)の動画は埋め込めません。検索結果に出したくないだけなら限定公開を選んでください。ただしURLが分かれば誰でも視聴できる状態である点は理解しておく必要があります。

複数の動画を順番にループさせたいのですが?

playlistにカンマ区切りで動画IDを並べ、loop: 1を指定すれば、リスト全体を繰り返します。ただし動画の切り替わりでプレーヤーの読み込みが挟まり、一瞬暗転します。背景として滑らかに見せたいなら、複数の映像を1本に編集してからアップロードするほうが確実です。

WordPressでも同じ方法で実装できますか?

できます。ファーストビューはテーマのテンプレートファイル(front-page.phpなど)に直接書くことになるので、子テーマを作ってそこに実装してください。JavaScriptとCSSはwp_enqueue_scriptwp_enqueue_styleで読み込みます。ブロックエディターの本文に貼る方法もありますが、ファーストビュー全面に広げるにはテーマ側のレイアウト制御が必要になるため、テンプレートに書くほうが確実です。

動画が読み込まれるまでの間、何が表示されますか?

.heroの背景に指定したフォールバック画像です。この記事のCSSでは、プレーヤーの準備が整った時点でis-video-readyクラスを付け、透明度のアニメーションで動画へ切り替えています。切り替えを感じさせないよう、フォールバック画像には動画の冒頭フレームを書き出したものを使うのがおすすめです。

スマホでの表示確認はどうすればいいですか?

必ず実機で確認してください。ブラウザの開発者ツールにあるスマホ表示のシミュレーションでは、自動再生の制限や低電力モードの挙動が再現されません。iOSとAndroidの両方で、通常時と低電力モード時の見え方を確認するのが最低ラインです。

まとめ

YouTube IFrame Player APIでファーストビューに自動再生ループを実装する手順をまとめます。受け皿のdivを置き、iframe_apiを読み込み、onYouTubeIframeAPIReadyYT.Playerを生成します。自動再生はonReadymute()を呼んでからplayVideo()を実行して成立させ、ループはloopplaylistの両方を指定したうえで、onStateChangeで終了を検知して再生し直す形が確実です。

CSSでは56.25vw177.78svhで画面全面をカバーし、pointer-events: noneでクリックを通し、フォールバック画像を背景に敷きます。自動再生は環境によってブロックされる前提で、静止画だけでも成立する画面を先に作ってください。そして最後にもう一度お伝えしますが、15秒程度のループ映像なら自社サーバーのMP4のほうが軽く、確実です。ファーストビューは表示速度が最も問われる場所なので、まずそちらを検討したうえでAPIを選んでください。

最新情報をチェックしよう!

LET’S CONTACT

お問い合わせ

デザインと発信の力で、お客様の強みや想いを形にし、
成果につながるコンテンツを制作します。
「うちの場合はどうなる?」という段階からでも、どうぞお気軽にご相談ください。