HTML video タグで動画埋め込み(背景動画)

video タグの基本的な使い方や mp4 などの動画を背景として表示する方法、スマホでは動画を読み込まないようにしたり、JavaScript を使った動画の操作方法など。

更新日:2023年06月01日

作成日:2023年4月30日

背景動画

以下は HTML の video タグと CSS を使ってコンテンツの背景に動画を表示する例です。

動画を背景に表示するには background は使えないので、動画は video タグで表示し、コンテンツを絶対配置して重ねて表示しています。

Video Background

Lorem ipsum dolor sit amet consectetur adipisicing elit. Error libero, et voluptatem, sit, sint hic eos excepturi vel quo incidunt similique. Quam nemo amet iusto sint facilis dolorem dignissimos quidem.

サンプルを別ウィンドウで開く

HTML では動画(video 要素)とコンテンツ(.video-content)を div 要素(.video-wrapper)でラップして、.video-wrapper を配置する基準とします。

video 要素には必要に応じて複数の属性を指定できます。この例では以下の属性を指定しています。

  • src:埋め込む動画への URL を指定
  • muted:初期状態で消音(ミュート)
  • loop:繰り返し(ループ)再生
  • playsinline:インライン再生を有効に(iPhone などでインライン表示するために指定)
  • autoplay:動画が読み込まれたら自動的に再生
  • poster:動画が読み込まれている間に表示する画像を指定
<div class="video-wrapper">
  <video src="videos/sample.mp4" muted loop playsinline autoplay poster="images/sample.jpg"></video>
  <div class="video-content">
    <h2>Video Background</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit</p>
  </div>
</div>

上記のように video 要素に直接 src 属性で埋め込む動画を指定することもできますが、以下のように source 要素を使って異なる形式の動画ファイルを複数指定することもできます。

また、video 要素内にはブラウザが video 要素に対応していない場合に表示するメッセージを記述することもできます。

HTML
<div class="video-wrapper">
  <video muted loop playsinline autoplay poster="images/sample.jpg">
    <source src="videos/sample.webm" type="video/webm">
    <source src="videos/sample.mp4" type="video/mp4">
    <p>動画を再生するには  HTML5 video に対応したブラウザが必要です。</p>
  </video>
  <div class="video-content">
    <h2>Video Background</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit...</p>
  </div>
</div>

CSS では video 要素の親要素(.video-wrapper)に aspect-ratio プロパティ でアスペクト比を指定して、動画を親要素いっぱいに表示しています。

また、::before 疑似要素で動画の上に半透明のオーバーレイを表示しています。

コンテンツは絶対配置して、基本的に水平・垂直方向中央に配置するようにしていますが、top: 43% として垂直方向の位置を調整しています。また、コンテンツ内の全てのテキストを text-align: center で中央寄せにしています。

画面幅が狭い場合(この例では 480px以下の場合)はアスペクト比とコンテンツの位置を調整しています。実際にはフォントサイズなどの調整も必要になるかと思いますが省略しています。

CSS
/* ラッパー(外側の要素) */
.video-wrapper {
  aspect-ratio: 16 / 9;  /* 縦横比(アスペクト比) */
  overflow: hidden;
  position: relative; /* 絶対配置するコンテンツや疑似要素の基準とする */
  width: 100%;
  max-width: 1600px;
}

/* 疑似要素でオーバーレイを表示 */
.video-wrapper::before {
  content: "";
  position: absolute; /* 絶対配置 */
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background-color: rgba(9, 2, 108, 0.15);
}

/* video 要素 */
.video-wrapper video {
  width: 100%;  /* 明示的に幅を設定(必須) */
  height: 100%; /* 明示的に高さを設定(必須) */
  object-fit: cover; /* コンテンツボックスに収まるように拡大縮小 */
}

.video-content {
  margin: 0;
  position: absolute; /* 絶対配置 */
  top: 43%;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%);
  color: #fff;
  text-align: center;
}

#content .video-content h2 {
  font-size: 2rem;
  letter-spacing: 0.1rem;
  text-shadow: 2px 2px 2px #444;
  color: #fff;
}

.video-content p {
  max-width: 600px;
  padding: 0 2rem;
}

@media screen and (max-width: 480px) {
  .video-wrapper {
    aspect-ratio: 1 / 1;
  }
  .video-content {
    top:38%;
    margin-top: 1rem;
  }
}
.video-wrapper {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  position: relative;
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
}

.video-wrapper::before {
  content: "";
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background-color: rgba(9, 2, 108, 0.15);
}

.video-wrapper video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-content {
  margin: 0;
  position: absolute;
  top:38%;
  margin-top: 1rem;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%);
  color: #fff;
  text-align: center;
}

.video-content h2 {
  font-size: 2rem;
  letter-spacing: 0.1rem;
  text-shadow: 2px 2px 2px #444;
}

.video-content p {
  max-width: 600px;
  padding: 0 2rem;
}

@media screen and (min-width: 481px) {
  .video-wrapper {
    aspect-ratio: 1600 / 897;  /* 実際の動画に合わせた場合 */
  }
  .video-content {
    top:43%;
    margin-top: 0;
  }
}

@media only screen and (min-width: 768px){
  .video-content h2{
    font-size: 2.5rem;
  }
  .video-content p {
    max-width: 600px;
    padding: 0 0;
  }
}

@media only screen and (min-width: 992px){
  .video-content h2 {
    font-size: 3rem;
  }
}

@media only screen and (min-width: 1139px){
  .video-content h2 {
    font-size: 3.5rem;
  }
}

スマホでは動画を読み込まない

動画のファイルサイズが大きいと、スマホでは読み込みに時間がかかったり、モバイル通信量を消費するのでスマホでは動画を読み込まず、静止画像を表示するようにする例です。

但し、以下の例の場合、スマホの判定はビューポート幅(480px)を基準にしているので、確実にスマホを判定できるわけではありません。判定方法にはユーザーエージェントなどを使う方法もありますが、推奨される方法ではないので、ビューポート幅で判定しています。

そのため、スマホを横向きでこのページを開くと動画は読み込まれます。

単に CSS で video 要素を非表示にしただけではファイルはダウンロードされてしまうので、この例では JavaScript でメディアクエリを使ってビューポート幅により動画の読み込みを制御しています。

Video Background

Lorem ipsum dolor sit amet consectetur adipisicing elit. Error libero, et voluptatem, sit, sint hic eos excepturi vel quo incidunt similique. Quam nemo amet iusto sint facilis dolorem dignissimos quidem.

サンプルを別ウィンドウで開く

HTML の構造は前述の例と同じですが、以下では video 要素に指定する属性は、autoplay を削除し、preload="none" を指定して自動的に動画ファイルを読み込まないようにしています。

HTML
<div class="video-wrapper">
  <!-- preload="none" を指定し、autoplay は指定しない -->
  <video muted loop playsinline preload="none" poster="images/sample.jpg">
    <source src="videos/sample.webm" type="video/webm">
    <source src="videos/sample.mp4" type="video/mp4">
    <p>動画を再生するにはvideoタグをサポートしたブラウザが必要です。</p>
  </video>
  <div class="video-content">
    <h2>Video Background</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit..</p>
  </div>
</div>

ビューポート幅が480px以下の場合は、ビデオを非表示にして背景画像を表示するようにしています。

背景画像を設定しなくても video 要素の poster 属性に指定した画像が表示されますが、この場合は、poster 属性に指定した画像とは異なる画像を表示したいため別途背景画像を用意しています。

また、この例では動画の高さ(video 要素の親要素の高さ)を固定にしています。

CSS
.video-wrapper {
  overflow: hidden;
  position: relative;
  width: 100%;
  max-width: 1600px;
  height: 500px;  /* 高さ固定 */
  margin: auto;
}

.video-wrapper::before {
  content: "";
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background-color: rgba(0, 0, 0, 0.5);
}

.video-wrapper video {
  width: 100%;  /* 明示的に幅を設定(必須) */
  height: 100%; /* 明示的に高さを設定(必須) */
  object-fit: cover;  /* ラッパーにに収まるように拡大縮小 */
  object-position: 50% 0%;  /* 動画の位置の調整 */
}

.video-content {
  margin: 0;
  position: absolute;
  top: 43%;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%);
  color: #fff;
  text-align: center;
}

.video-content h2 {
  font-size: 2rem;
  letter-spacing: 0.1rem;
  text-shadow: 2px 2px 2px #444;
}

.video-content p {
  max-width: 600px;
  padding: 0 2rem;
}

/* ビューポート幅が 480px 以下の場合はビデオを非表示にして背景画像を表示 */
@media screen and (max-width: 480px) {
  .video-wrapper {
    height: 340px;  /* 高さの調整 */
    background: url(images/cover.jpg);  /* 別途背景画像を用意 */
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
  }

  .video-wrapper video {
    display: none;  /* ビデオを非表示(背景画像を表示するため) */
  }
}

JavaScript では、window.matchMedia() にメディアクエリを指定して作成される MediaQueryList オブジェクトの matches プロパティで指定したメディアクエリの条件にマッチするかを判定しています。

!window.matchMedia('(max-width: 480px)').matches は、メディアクエリ (max-width: 480px) の条件にマッチしない場合となるので、ビューポート幅が480pxより大きい場合となります。

ビューポート幅が480pxより大きい場合に、video の preload プロパティに auto を設定してファイルを読み込むようにし、autplay を true に設定して自動再生します。

JavaScript
document.addEventListener('DOMContentLoaded', ()=> {
  // .video-wrapper 内の video 要素を全て取得
  const videos = document.querySelectorAll('.video-wrapper video');

  // それぞれのビデオ要素について以下を実行
  videos.forEach((video) => {
    // ビューポート幅が 480px より大きい場合はビデオを再生
    if (!window.matchMedia('(max-width: 480px)').matches) {
      // preload プロパティに auto を設定
      video.preload = 'auto';
      // autplay プロパティを true に設定して自動再生
      video.autoplay = true;
    }
  });
}, false);

以下は上記をモバイルファーストに書き換えた例です(HTML は同じです)。この場合は、ビューポート幅が480px未満の場合は、ビデオを非表示にして背景画像を表示するようにしています。

CSS
.video-wrapper {
  overflow: hidden;
  position: relative;
  width: 100%;
  height: 340px;
  background: url(images/cover.jpg); /* 別途背景画像を用意 */
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.video-wrapper::before {
  content: "";
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background-color: rgba(0, 0, 0, 0.5);
}

.video-wrapper video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
  display: none;  /* ビデオを非表示(背景画像を表示するため) */
}

.video-content {
  margin: 0;
  position: absolute;
  top: 43%;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%);
  color: #fff;
  text-align: center;
}

.video-content h2 {
  font-size: 2rem;
  letter-spacing: 0.1rem;
  text-shadow: 2px 2px 2px #444;
}

.video-content p {
  max-width: 600px;
  padding: 0 2rem;
}

/* 480px 以上の場合はビデオを表示 */
@media screen and (min-width: 480px) {
  .video-wrapper {
    height: 500px;
    max-width: 1600px;
    margin: auto;
    background: none;
  }
  .video-wrapper video {
    display: block;  /* ビデオを表示 */
  }
}
JavaScript
document.addEventListener('DOMContentLoaded', () => {
  const videos = document.querySelectorAll('.video-wrapper video');
  videos.forEach((video) => {
    // ビューポート幅が 480px 以上の場合はビデオを再生
    if (window.matchMedia('(min-width: 480px)').matches) {
      video.preload = 'auto';
      video.autoplay = true;
    }
  });
}, false);

サンプルを別ウィンドウで開く

関連ページ:JavaScript でメディアクエリ(matchMedia と MediaQueryList)

ローディングアイコンを表示

動画のファイルサイズが大きい場合、通信環境によっては読み込み時間が長くなってしまうので、動画の読み込み中(正確には動画が再生できる状態になるまで)はローディングアイコンを表示する例です。

以下のサンプルの場合、動画のファイルサイズは 3.5MB なので LAN 環境ではローディングアイコンはほとんど見えないかと思います。

Video Background

Lorem ipsum dolor sit amet consectetur adipisicing elit. Error libero, et voluptatem, sit, sint hic eos excepturi vel quo incidunt similique. Quam nemo amet iusto sint facilis dolorem dignissimos quidem.

サンプルを別ウィンドウで開く(ビデオサイズ:7.5MB)

HTML は前述の例と同様、初期状態では video 要素に preload="none" を指定して動画を読み込まないようにして、JavaScript でビューポート幅が480px以上の場合は動画を読み込み再生するようにしています。

HTML
<div class="video-wrapper">
  <video muted loop playsinline preload="none" poster="images/sample.jpg">
    <source src="videos/sample.webm" type="video/webm">
    <source src="videos/sample.mp4" type="video/mp4">
    <p>動画を再生するにはvideoタグをサポートしたブラウザが必要です。</p>
  </video>
  <div class="video-content">
    <h2>Video Background</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit...</p>
  </div>
</div>

JavaScript では各 video 要素に canplay イベントのリスナを設定し、動画が再生できる状態になったこと(canplay イベント)を検知したら video_ready というクラスを追加します。

JavaScript
document.addEventListener('DOMContentLoaded', () => {
  // .video-wrappe を取得
  const videoWrappers = document.querySelectorAll('.video-wrapper');
  // メディアクエリを設定して MediaQueryList オブジェクトを作成
  const mql = window.matchMedia('(min-width: 480px)');
  // 取得した各 .video-wrappe で
  videoWrappers.forEach((wrapper) => {
    // video 要素を取得
    const video = wrapper.querySelector('video');

    // video 要素に canplay イベントのリスナを設定
    video.addEventListener('canplay', () => {
      // 動画が再生できる状態になったら video_ready クラスを追加
      wrapper.classList.add('video_ready');
    }, false);

    //ビューポート幅が480px以上の場合は動画を再生
    if (mql.matches) {
      video.preload = 'auto';
      video.autoplay = true;
    } else {
      //ビューポート幅が480px未満ではvideo_readyクラスを追加(ローディング画像を表示しない)
      video.parentElement.classList.add('video_ready');
    }
  });
}, false);

ビデオが再生できる状態になったら、JavaScript により .video-wrapper に .video_ready をいうクラスが追加されるので、それを利用してローディングアイコンの表示・非表示やスタイルを設定します。

ローディング画像は、.video-wrapper に .video_ready クラスが追加されるまでの間 ::after で表示します。また、.video-wrapper の背景画像に poster 属性に設定する画像を指定して背景画像を表示し、JavaScript でビューポート幅が480px以上の場合は背景画像を削除して代わりに動画を表示します。

CSS
.video-wrapper {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  position: relative;
  width: 100%;
  background: url(images/sample.jpg);  /* poster 属性に設定する画像を指定 */
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.video-wrapper::before {
  content: "";
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background-color: rgba(255, 255, 255, 0.7);
  transition: background-color 1s;  /*オーバーレイにトランジションを設定 */
}

/* JavaScript で .video_ready が付与された際のオーバーレイ */
.video-wrapper.video_ready::before {
  background-color: rgba(0, 0, 0, 0.3);
}

/* JavaScript で .video_ready が付与されるまではローディング画像を表示 */
.video-wrapper:not(.video_ready)::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
  width: 80px;
  height: 80px;
  background-image: url(images/spinner.png);  /* ローディング画像 */
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

/* ビューポート幅が480px未満の場合はビデオを非表示 */
.video-wrapper video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: none; /* ビデオを非表示 */
}

/* ビューポート幅が480px以上の場合 */
@media screen and (min-width: 480px) {
  /* .video_ready が付与されたら背景画像を非表示 */
  .video-wrapper.video_ready {
    background: none;
  }

  /* .video_ready が付与されたらビデオを表示 */
  .video-wrapper.video_ready video {
    display: block; /* ビデオを表示 */
  }

  /* .video_ready が付与された場合はトランジションの長さを変更 */
  .video-wrapper.video_ready::before {
    transition: background-color 8s;
  }
}

.video-content {
  margin: 0;
  position: absolute;
  top: 43%;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%);
  color: #fff;
  text-align: center;
}

.video-content h2 {
  font-size: 2rem;
  letter-spacing: 0.1rem;
  text-shadow: 2px 2px 2px #111;
}

.video-content p {
  max-width: 600px;
  padding: 0 2rem;
}

別ウィンドウで開くサンプルでは、.video-wrapper のスタイルを以下のように設定してビデオを全画面表示するようにしています。

.video-wrapper {
  width: 100%;
  height: 100vh;
  overflow: hidden;
  position: relative;
  background: url(images/sample.jpg);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

この例で使用しているローディングアイコン(以下)は icons8.com で作成したものです。

好きなアイコンを選択すると以下のようなウィンドウが開くので、ファイルのタイプや背景を透過にするか、サイズや色などが編集できるようになっています。編集したら「Generate」をクリックすると右側にプレビューが表示されるので問題なければ Download をクリックします。

また、画像を使わない以下のような HTML と CSS によるローディングアイコンもあります。

以下は Spinkit に掲載されているローディングアイコンを使った例です。

HTML と CSS ではサイトからコピーしたローディングアイコンの HTML と CSS を追加しています。JavaScript は前述の例と同じです。

<div class="video-wrapper">
  <video muted loop playsinline preload="none" poster="images/sample.jpg">
    <source src="videos/sample.webm" type="video/webm">
    <source src="videos/sample.mp4" type="video/mp4">
    <p>動画を再生するにはvideoタグをサポートしたブラウザが必要です。</p>
  </video>
  <div class="spinner"> <!-- ローディングアイコンの HTML -->
    <div class="bounce1"></div>
    <div class="bounce2"></div>
    <div class="bounce3"></div>
  </div>
  <div class="video-content">
    <h2>Video Background</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit...</p>
  </div>
</div>

このサンプルの場合、LAN 環境などではすぐに再生可能になり、ローディングアイコンの表示がわからないため、再生可能になってからトランジションで2秒かけてアイコンを非表示にしていますが、実際に使用する際は即座に非表示にすることになるかと思います。

サンプルを別ウィンドウで開く(ビデオサイズ:7.5MB)

video 要素(タグ)

HTML の video 要素(タグ)を使って動画(ファイル)を表示する(埋め込む)ことができます。

表示可能な動画のファイル形式はブラウザにより異なりますが、最も広くサポートされているのは MP4(拡張子は .mp4 コーデックは h.264)になります。

主要なモダンブラウザでは .mp4 以外にも .webm や .mov もサポートしています。

動画関連参考サイト(MDN)

video タグを使って動画ファイルを埋め込むには src 属性に動画ファイルのパスを指定します。

<video src="sample.mp4"></video><!-- src 属性に動画ファイルを指定 -->

上記を記述すると src 属性に指定した動画が表示されます。

※ 但し、iPhone などでは src 属性を指定しただけでは何も表示されず、空白になっています。

src 属性だけを指定しただけでは再生ボタンなどは表示されず、自動的に再生もされません。

video タグには src 属性の他に動画コントロール(再生ボタンなど)を表示するかや自動再生やループをするか、動画の幅や高さなどの属性を指定することができます。

video 要素の属性

video 要素にはグローバル属性(すべての HTML 要素で共通の属性)の他に以下のような属性を指定することができます。

video 要素に指定できる属性の一部抜粋
属性 説明
src 埋め込む動画への URL を指定します。この属性を省略して video 要素内で source タグを使用して埋め込む動画を指定することもできます。
controls この属性を指定すると、再生、音量、シーク、ポーズの各機能を制御するコントロールを表示します。表示されるコントロールはブラウザにより異なります。
controlslist この属性を指定すると表示するコントロールを選択することができ、以下を指定できます。(例) controlslist="nodownload"(ダウンロードメニューを非表示)
  • nodownload
  • nofullscreen
  • noremoteplayback
can i use controlslist(一部のブラウザではサポートされていません)
autoplay この属性を指定すると、データの読み込みが完了し、再生可能な状態になった時点で即座にコンテンツの再生が始まります。Chrome などのブラウザでは自動再生するには muted 属性も同時に指定する必要があります。
muted この属性を指定すると、初期状態でミュート(音が消された状態)になります。
playsinline 動画のインライン再生を有効にします。インライン再生とは、全画面表示せずにその位置で再生させることです。playsinline 属性が指定されていないと、iPhone などでは再生ボタンをタップすると拡大画面が表示されてそこで動画が再生されます。
loop この属性を指定すると、動画を繰り返し(ループ)再生します(動画の末尾に達すると自動的に先頭に戻って繰り返し再生)。
poster 動画が読み込まれている間(ダウンロード中)に表示する画像を指定することができます。この属性が指定されない場合、最初のフレームが利用可能になるまで何も表示されず、その後、最初のフレームをポスターフレームとして表示します。
preload 動画ファイルを事前に読み込むかどうかを指定する属性で次の値を指定できます。
  • none
  • metadata
  • auto
  • 空文字列(auto を指定したのと同じ)
※ 既定値はブラウザーごとに異なるため、必要に応じて明示的に指定します。
width / height 動画の表示領域の幅と高さをピクセル値で指定します(単位は付けません)。表示領域の幅と高さを設定できますが、動画自体の縦横比は変更できません。画像(img 要素)同様、レイアウトシフト対策として、width と height を指定することが推奨されます(または CSS で aspect-ratio を指定)。

以下の動画のサンプルには次のようなスタイルを設定しています。

video {
  aspect-ratio: 16/9;
  width: 70%;
  height: auto;
  max-width: 500px;
}
コントロールの表示(controls 属性)

再生ボタンなどのコントロールを表示するには video 要素に controls を指定します。

但し、表示されるコントロール(ボタンなどの形状や何が表示されるか)はブラウザにより異なります。

以下では controls 属性の他に、playsinline 属性と poster 属性も指定しています。

<video src="sample.mp4" controls playsinline poster="poster.jpg"></video>
playsinline 属性(iPhone)

playsinline 属性は iPhone や iPad でインライン再生できるようにするために指定します。

playsinline 属性が指定されていないと、iPhone などでは再生ボタンをタップすると拡大画面が表示されて動画が再生されます。

また、iPhone では自動再生しない場合、背景に何も表示されないので、以下では合わせて poster 属性も指定して背景に代替画像が表示されるようにしています。

<video src="sample.mp4" controls playsinline poster="poster.jpg"></video>
preload 属性

preload 属性は動画ファイルを事前に読み込むかどうかを指定する属性で次の値を指定できます。

  • none: 事前に動画ファイルを読み込まない。
  • metadata: 動画のメタデータ (再生時間などのメタ情報) のみを読み込む。
  • auto: 事前に動画ファイルを読み込む。
  • 空文字列: auto を指定したのと同じ。

既定値はブラウザーごとに異なるため必要に応じて明示的に指定します。

また、autoplay 属性を指定している場合は、preload="none" を指定しても事前に動画ファイルが読み込まれます(autoplay 属性は preload 属性より優先されます) 。

preload="none"

以下は preload="none" を指定して、事前に動画ファイルを読み込まないようにする例です。

preload="none" を指定した場合、controls 属性や poster 属性に代替画像を指定していないと何も表示されません(動画のスペース分の空白)。

controls 属性を指定して poster 属性を指定していない場合はコントロールのみが表示されますが、ブラウザにより表示が異なります(Chrome では背景が黒、Firefox や Safari では透明)。

<video src="sample.mp4" controls playsinline preload="none" poster="poster.jpg"></video>

この例では controls 属性と poster 属性に動画の最初のフレームと同じ画像を指定しています。

※ preload 属性に metadata を指定すれば、動画のメタデータのみが読み込まれ、最初のフレームをポスターフレーム(ポスター画像)として表示します。但し、Safari ではポスター画像が表示されないようなので、確実に何らかの画像を表示するには poster 属性に代替画像を指定します。

また、preload="none" を指定した場合、実際にファイルが読み込まれるまでブラウザは画像ファイルのサイズがわからないので、width 属性と height 属性を指定するか、CSS で幅と高さを指定します。

動画の遅延読み込み

自動再生しない動画の場合、preload="none" を指定することで動画の読み込みを延期する(動画を遅延読み込みする)ことができます。

参考:動画を遅延読み込みする

poster 属性(代替画像の表示)

poster 属性を使って動画ファイルが読み込まれている間に表示する画像を指定することができます。

この属性が指定されない場合、最初のフレームが利用可能になるまで何も表示されず、その後、最初のフレームをポスターフレームとして表示します。

今までの例では poster 属性に最初のフレームと同じ画像を使用していますが、以下は文字を入れた画像を指定しています。

以下は preload="none" を指定しているので、画像は読み込まれず最初のフレームも表示されませんが、poster 属性で指定した画像が表示されます。再生ボタンをクリックすると動画に切り替わります。

autoplay 属性(及び muted 属性)を指定した場合は、動画ファイルが読み込まれている間は poster 属性で指定した画像が表示され、その後動画が自動再生され表示されます。

<video src="sample.mp4" controls playsinline preload="none" poster="poster2.jpg"></video>
自動再生(autoplay 属性と muted 属性)

autoplay 属性を指定すると、データの読み込みが完了し、再生可能な状態になった時点で即座にコンテンツの再生が始まります。

但し、Chrome などでは muted 属性が指定されていない場合 autoplay は動作しないので、自動再生するには muted 属性も一緒に指定します。また、ページを表示していきなり音が鳴るのは好ましくないので、通常自動再生する場合は muted 属性も指定します

以下は autoplay、muted、playsinline、loop、poster 属性を指定して自動再生する例です。

poster 属性で代替画像を指定しているので、動画がダウンロードされるまでは代替画像が表示され、再生可能になると自動的に再生が始まり、loop 属性を指定しているので繰り返し再生されます。

controls 属性を指定していないので、再生ボタンなどのコントロールは表示されませんが、右クリックでコンテキストメニューからコントロールを表示することができます。

<video src="sample.mp4" autoplay muted playsinline loop poster="poster2.jpg"></video>

MDN : 動画と音声のコンテンツ

ダウンロードの防止

Chrome などでは controlslist 属性の値に nodownload を指定すると「ダウンロード」メニューを表示しないようにすることができます。但し、controlslist 属性は一部のブラウザでサポートされていません。

can i use controlslist

以下のように controlslist="nodownload" を指定すると、Chrome では右端のアイコンをクリックして表示されるメニュー項目から「ダウンロード」が消えますが、動画上で右クリックすると「名前を付けて動画を保存」が表示され、ダウンロードすることは可能です。

<video src="sample.mp4" controlslist="nodownload" controls playsinline poster="poster.jpg"></video>

但し、controlslist 属性は実験的なものであり、すべてのブラウザーでサポートされているとは限らないため、W3C の Markup Validation Service で検証すると「Error: Attribute controlslist not allowed on element video at this point.」のようなエラーになります。JavaScript のプロパティで設定することもできます。

コンテクストメニューを表示させない

oncontextmenu="return false;" を指定することで、右クリックでのコンテクストメニューを表示しないようにすることができます。

<video src="sample.mp4" controlslist="nodownload" oncontextmenu="return false;"  controls playsinline poster="poster.jpg">></video>

上記は JavaScript を使って設定することもできます。

//全てのビデオ要素を取得
const videos = document.querySelectorAll('video');

//ビデオ要素が1つ以上あれば
if(videos.length > 0) {
  videos.forEach(function(elem) {
    //ダウンロードメニューを表示しない
    elem.setAttribute('controlslist', 'nodownload');
    //コンテクストメニューを表示しない
    elem.addEventListener('contextmenu', (e) => {
      e.preventDefault();
    });
  });
}

完全にはダウンロードは防げない

但し、HTML のソースコードを見てビデオの URL からアクセスできてしまいます。

以下を .htaccess に記述することで、ビデオファイル(mp4、webm)に自分のサイト(以下の場合は https://www.example.com)からのみアクセスを許可できますが、リファラ(Referer)は偽装も可能なため、完全にアクセス(ダウンロード)を防ぐことはできません。

.htaccess
SetEnvIf Referer "^https://www\.example\.com" mysite
<Files ~ "\.(mp4|webm)$">
  order deny,allow
  deny from all
  allow from env=mysite
</Files>  

関連ページ:.htaccess の使い方(ファイルへのアクセス制御)

代替コンテンツ

video タグ内にテキストを記述すると、ブラウザが video 要素に対応していない場合にその内容が表示されます。ブラウザが video 要素に対応していれば、動画が表示されてテキストは表示されません。

テキストは p 要素などを使っても、単にテキストだけ記述しても問題ありません。

<video src="sample.mp4" controls>
  <p>お使いのブラウザーは HTML5 動画をサポートしていません。</p>
</video>

※ 現在のほどんどのブラウザは video 要素に対応しているため、mp4 形式(コーデック h.264)の動画であれば、代替コンテンツを記述しなくとも問題ないと思います。

can i use video

代替画像(背景画像)

代替画像は video 要素の poster 属性で指定することができます。そのため、敢えて設定する必要はないと思いますが video 要素に background プロパティを使って背景画像を指定することもできます。

但し、poster 属性で指定した画像は preload="none" を指定した場合に表示されますが、 background で指定した画像は(video 要素に対応しているブラウザでは)表示されないので、 background プロパティを指定する場合でも poster 属性を指定した方が確実です。

サイズの指定

width 属性と height 属性を使って動画の表示領域の幅と高さをピクセル値で指定することができますが固定値になります。以下の場合、幅320px、高さ180pxの固定サイズで表示されます。

video 要素の属性は省略しています。実際には controls playsinline 及び poster を指定しています。

<video src="sample.mp4" width="320" height="180"></video>

以下は width 属性と height 属性に実際の画像ファイルのサイズを指定し、CSS で表示サイズを設定する例です。img 要素同様、width 属性と height 属性を指定することで、レイアウトシフトを防止することができます(controls 属性などの記述は省略しています)。

レイアウトシフトの防止が目的の場合、width 属性と height 属性では縦横比が示せれば良いので、この場合、width="128" height="72" や width="16" height="9" でも問題ありませんが、CSS でサイズを指定しないとその値で表示されてしまいます。

<video class="foo" src="sample.mp4" width="1280" height="720"></video>

video 要素に width 属性と height 属性を指定してレスポンシブにする場合、CSS では width を%で指定し、height には auto を指定します。CSS での height を省略すると、height 属性で指定した高さ(この場合は 720px)が確保されてしまいます。

.foo {
  width: 70%;
  height: auto;  /* auto を指定 */
}

以下は video 要素を div 要素(.video-wrapper)でラップする例です。

.video-wrapper に width と max-width で幅と最大幅を指定して、video 要素は親要素の .video-wrapper の幅いっぱいに表示するようにしています(controls 属性などの記述は省略しています)。

<div class="video-wrapper">
  <video src="sample.mp4" width="1280" height="720"></video>
</div>

この例の場合も、video 要素に width 属性と height 属性を指定しているので、CSS では video 要素に height: auto を指定します。

.video-wrapper {
  width: 70%;  /* % で指定して可変に */
  max-width: 500px;  /* 必要に応じて最大幅を指定 */
}

.video-wrapper video {
  width: 100%;  /* 親要素の幅いっぱいに */
  height: auto;  /* height には auto を指定 */
}
縦横比(aspect-ratio)

aspect-ratio プロパティを使って要素にアスペクト比(縦横比)を設定することができます。

以下は video 要素に aspect-ratio を使って縦横比を設定する例です。

この例の場合、表示する動画ファイルは width="1280" height="720" なのでアスペクト比は 1280:720 (16:9)になり、以下のように指定することができます。

aspect-ratio を設定する場合、幅または高さのどちらかを指定します(他方は自動的に決定されますが、他方は auto を指定したほうが安全です)。

.asp16x9 {
  aspect-ratio: 16/9;  /* アスペクト比を設定(1280/720 でも同じ) */
  width: 70%;  /* % で指定(可変幅) */
  height: auto;  /* height には auto を指定 */
  max-width: 500px;  /* 必要に応じて */
}

aspect-ratio プロパティを使ってアスペクト比を設定することでレイアウトシフトを防止できるので、video 要素の width 属性と height 属性の指定は省略できます。

※ 上記の場合、CSS で height: auto; を指定ぜずに video 要素に height 属性を指定すると、その値が有効になってしまいます。

<video class="asp16x9" src="sample.mp4" controls playsinline></video>

以下はアスペクト比を指定した div 要素で video 要素をラップして配置する場合の例です。

<div class="video-wrapper">
  <video src="sample.mp4" controls playsinline></video>
</div>

表示する動画と同じ(または表示したい)アスペクト比と幅を設定した div 要素に overflow: hidden を指定します。

親要素の div 要素に video 要素がフィットするように、 video 要素の width と height に 100% を指定して object-fit: cover を指定します。

 .video-wrapper {
  aspect-ratio: 16/9;   /* 親要素に動画と同じ(または表示したい)アスペクト比を設定 */
  width: 70%;  /* % で指定して可変幅に */
  max-width: 500px;  /* 必要に応じて最大幅を指定 */
  overflow: hidden;  /* 指定したアスペクト比からはみ出さないように */
}

.video-wrapper video {
  width: 100%;  /* 親要素の幅いっぱいに表示 */
  height: 100%;  /* 親要素の幅いっぱいに表示 */
  object-fit: cover;  /* コンテンツボックスに収まるように拡大縮小 */
}

padding ハック

以下の padding ハックでも上記と同じ結果になります。padding ハックは aspect-ratio プロパティが広くサポートするまで使用されいていた手法で、コードが分かりにくいのと長くなるデメリットがあります。

.video-wrapper {
  position: relative;  /* 子要素(video)を配置する基準とする */
  overflow: hidden;
  width: 70%;  /* 上記の例と同じになるように 70% に指定 */
  max-width: 500px;  /* 上記の例と同じになるように指定 */
}

.video-wrapper::before {
  content: "";  /* 空文字列を指定 */
  display: block;   /* display: block でブロック要素に */
  padding-top: calc(9 / 16 * 100%) ; /* 56.25% でも同じ*/
}

.video-wrapper video {
  position: absolute; /* 絶対配置 */
  top: 0;
  left: 0;
  width: 100%;  /* 幅 100% */
  height: 100%;  /* 高さ 100% */
}
異なる縦横比で表示

aspect-ratio と object-fit を使えば、実際の動画ファイルの縦横比とは異なる縦横比で(トリミングして縦横比を維持したまま)表示することができます。

以下は縦横比が 16:9 の動画を縦横比 3:1 で表示する例です。

<div class="video-wrapper">
  <video src="sample.mp4" controls playsinline></video>
</div>

親要素に縦横比(アスペクト比)を指定し、video 要素には width: 100% と height: 100% を指定し、object-fit: cover を指定することで親要素のコンテンツボックスに収まるように拡大縮小(トリミング)されて表示されます。

親要素にフィットするように object-fit を設定する際は、width と height の両方に 100% を指定します。

また、表示する video 要素の位置は object-position で調整することができます。この例では垂直方向トップ(0%)にしています。

.video-wrapper {
  aspect-ratio: 3/1;  /* 動画ファイルとは異なる縦横比を指定 */
  width: 70%; /* % で指定(可変幅) */
  max-width: 500px;  /* 必要に応じて */
}

.video-wrapper video {
  width: 100%;  /* 親要素の幅いっぱいに表示 */
  height: 100%;  /* 親要素の高さいっぱいに表示 */
  object-fit: cover;  /* コンテンツボックスに収まるように拡大縮小 */
  object-position: 50% 0%;  /* 位置の調整 */
}

以下は video 要素自体に aspect-ratio と object-fit を指定する例です。

<video class="asp3x1" src="sample.mp4" controls playsinline></video>

aspect-ratio を設定した要素(この場合は video 要素)には、width または height のいずれかを指定します(他方は自動的に算出されます)。

.asp3x1 {
  aspect-ratio: 3/1;
  width: 70%; /* % で指定(可変幅) */
  max-width: 500px;  /* 必要に応じて */
  object-fit: cover;
  object-position: 50% 0%;
}
可変幅で高さを固定

以下は高さ固定で可変幅の親要素に video 要素を配置する例です。

video 要素には、width: 100% と height: 100%、及び object-fit: cover を指定します。必要に応じて object-position で位置を調整します。

<div class="video-wrapper">
  <video src="sample.mp4" controls playsinline></video>
</div>
.video-wrapper4 {
  width: 80%; /* 可変幅 */
  height: 200px; /* 高さ固定 */
}
.video-wrapper4 video {
  width: 100%;  /* 親要素の幅いっぱいに表示 */
  height: 100%;  /* 親要素の高さいっぱいに表示 */
  object-fit: cover;  /* コンテンツボックスに収まるように拡大縮小 */
  object-position: 50% 0%;  /* 位置の調整 */
}

以下は video 要素自体を高さ固定で可変幅で表示する例です。

<video class="fixed-height" src="sample.mp4" controls playsinline></video>
.fixed-height {
  width: 80%;
  height: 200px;
  object-fit: cover;
  object-position: 50% 0%;
}

複数の形式の動画を指定して読み込む

video 要素の中で source タグ(要素)を使って、複数の異なる形式の動画ファイルを指定できます。

ブラウザーやデバイスにより動画ファイル形式の対応状況が異なる可能性があるので、複数のファイル形式を準備しておき、ブラウザが自動的に最適なファイル形式を選択できるようにすることができます。

source 要素

source 要素は video 要素の入れ子として複数指定できる要素で、各 source 要素の src 属性に動画のデータと type 属性にファイルの形式を指定できます。

source 要素は空要素なので、閉じタグ </source> はありません。

以下の場合、最初に記述した WebM を試し、再生できない場合は MP4 を試します。 video 要素に対応していない場合は代替メッセージを表示します。

<video controls playsinline >
  <source src="sample.webm" type="video/webm"> <!-- WebM 形式 -->
  <source src="sample.mp4" type="video/mp4">; <!-- MP4 形式 -->
  お使いのブラウザーは HTML5 の video タグに対応していません。
</video>

WebM は HTML5 のために作成された Google が提供している動画ファイル形式で、ブラウザ単体で再生することができます。また、MP4 ファイルよりも圧縮効率が良いためファイルを軽くできます。

type 属性

type 属性が指定された場合、ユーザーエージェントが表示できる形式と比較し、扱えないものであれば、次に記述されている source 要素をチェックします。

type 属性が指定されていない場合は、サーバーからメディア形式を取得して、ユーザーエージェントが扱うことができるかどうかを確認し、表示ができない場合は、次の source 要素をチェックします。

また、type 属性にはオプションで codecs 引数を指定することもできます。

MDN:ウェブ動画コーデックガイド

Javascript で video を操作

JavaScript を使って動画(video 要素)を操作することができます。

以下は各プロパティで必要な属性を設定し、play() メソッドを使ってビデオを再生する例です。

属性は直接 HTML に記述することもできますし、以下のようにプロパティを使って設定することもできます。但し、playsinline というプロパティはないので、setAttribute() で追加しています。

<video class="js-video"></video>

video 要素を操作する際は基本的には DOMContentLoaded を利用して問題ないと思います。

document.addEventListener('DOMContentLoaded', () => {
  const video = document.querySelector('.js-video'); // 対象の video 要素を取得
  video.src = "sample.mp4"; //src プロパティに動画ファイルの URL を設定
  video.muted = true; //muted プロパティに true を設定
  video.controls = true; //controls プロパティに true を設定
  video.poster="poster.jpg" //poster プロパティに代替画像を設定
  video.width = "640"; //width プロパティで幅を設定
  video.height = "360"; //height プロパティで高さを設定
  video.setAttribute('playsinline',''); //setAttribute()で playsinline 属性を設定
  video.play();  //play() メソッドで再生 (または video.autoplay = true; で自動再生)
});

play() メソッドの代わりに autoplay プロパティに true を設定することで自動再生させることもできます。

また、muted プロパティに true を設定しない(または muted 属性を指定しない)で再生しようとすると、Safari や Firefox ではエラーになりませんが、Chrome では以下のようなエラーになります。

caught (in promise) DOMException: play() failed because the user didn't interact with the document first.

HTMLMediaElement / HTMLVideoElement

video 要素(及び audio要素)は HTMLMediaElement インターフェイスを継承していて、そのプロパティやメソッド、イベントを使うことができます。

また、video 要素は HTMLMediaElement から派生した HTMLVideoElement インターフェースによって実装されていて、video 要素を制御するためのメソッドやプロパティ、イベントが用意されています。

video のプロパティ

video 要素では以下のような HTMLMediaElement のプロパティを利用できます。

HTMLMediaElement のプロパティ(一部抜粋)
プロパティ 説明
autoplay HTML の autoplay 属性の値を反映し、論理値で指定します。初期値:false
controls HTML の controls 属性を反映し、コントロールを表示するかどうかを論理値で指定します。初期値:false
controlsList HTML の controlslist 属性に該当します(HTML の属性の list の l は小文字で、プロパティは大文字の L )。nodownload、nofullscreen、noremoteplayback を含む DOMTokenList を返します。読み取り専用。Chrome などでは video.controlsList = 'nodownload nofullscreen' のように設定できますが、「読み取り専用」とあるので setAttribute() を使った方が良いのかも知れません。
currentTime 現在の再生時刻を秒単位で示します。値を設定・変更すると指定された時刻にシーク(移動)します。(例)video.currentTime = 5

iPhone ではロード前に currentTime に0以外の値を設定すると正常に動作しません。currentTime に0以外の値を設定する場合は、preload に metadata を設定するか、loadeddata イベントを使って設定します(詳細)。

duration 再生時間を秒単位で示す倍精度浮動小数点値(読み取り専用)。メディアデータがない(指定されたデータが見つからなかったり、まだ、読み込まれていない)場合は NaN を返し、ライブメディアストリームなど再生時間が不明な場合は +Infinity を返します。メタ情報の読み込みが完了したタイミング(loadedmetadata イベント)で取得すると良いようです。
ended 再生を終了したかどうかを示す真偽値を返します(読み取り専用)。再生が終了した場合に true になります。
error 最新のエラーの MediaError オブジェクトです(読み取り専用)。エラーが発生していない場合は null。要素が error イベントを受け取ったら、このプロパティを調べることでエラーの詳細を調べられます。
loop 繰り返し(ループ)再生するかどうかを論理値で指定します。初期値:false
muted 音声がミュートされているかどうかを論理値で指定します。初期値:false
paused ビデオが一時停止中であるか否かを論理値で返します(読み取り専用)。
poster 代替画像の URL を指定します。
playbackRate メディアが再生されるレートを設定します。(例)video.playbackRate = 1.5
preload 動画ファイルを事前に読み込むかどうかを設定します。none, metadata, auto のいずれかを指定できます。
readyState メディアの準備状態を示すプロパティです(読み取り専用)。以下が定数とその値。
  • HAVE_NOTHING(0)
  • HAVE_METADATA(1)
  • HAVE_CURRENT_DATA(2)
  • HAVE_FUTURE_DATA(3)
  • HAVE_ENOUGH_DATA(4)
src 再生する動画への URL を指定(参照)します。
volume 音声の音量を double(無音 0.0 から最大 1.0 の間)で指定(参照)します。

video 要素では HTMLVideoElementt のプロパティやメソッドなども利用できます。

以下は、setAttribute() で controlslist 属性を追加し、contextmenu イベントでコンテクストメニュー(右クリックで表示されるメニュー)を非表示にする例です。

controlslist 属性は controlsList プロパティ(L は大文字)を使って video.controlsList = 'nodownload nofullscreen' のようにも設定できますが、MDN によると controlslist プロパティは読み取り専用となっているので、setAttribute() を使った方が良いのかも知れません。

document.addEventListener('DOMContentLoaded', () => {
    const video = document.querySelector('.js-video');
    video.src = "sample.mp4";
    video.muted = true;
    video.controls = true;
    video.poster="poster.jpg"
    video.width = "640";
    video.height = "360";
    video.setAttribute('playsinline','');
    // ダウンロードメニューを表示させない
    video.setAttribute('controlslist', 'nodownload');
    // フルスクリーン表示させない(Safari では無視される)
    video.setAttribute('controlslist', 'nofullscreen');
    // 上記は video.controlsList = 'nodownload nofullscreen'; でも同じ
    // コンテクストメニューを表示しない
    video.addEventListener('contextmenu', e => {
      e.preventDefault();
    });
    video.autoplay = true;  //自動再生 または video.play();
  });
音声のオン・オフ

autoplay 属性を指定する場合は、muted 属性を指定して初期状態として無音にする必要があります。

コントロールを表示してミュートをユーザーに解除してもらうこともできますが、以下はチェックボックスを表示して音声のオン・オフを操作できるようにする例です。

HTML では input 要素を使ってチェックボックスを表示します。

HTML
<div class="video-wrapper">
  <video poster="poster.jpg" muted loop playsinline autoplay>
    <source src="sample.webm" type="video/webm">
    <source src="sample.mp4" type="video/mp4">
    <p>動画を再生するにはvideoタグをサポートしたブラウザが必要です。</p>
  </video>
  <div class="video-content">
    <h2>Video Background</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
  </div>
  <div class="bgm-opt">
    <input type="checkbox" id="music-on1"> <!-- チェックボックス -->
    <label for="music-on1"> 音声 </label>
  </div>
  <p class="video-credit">video by fotogen</p>
</div>

JavaScript ではチェックボックスの change イベントを使って、チェックされれば muted 属性を false にして音を出すようにし、外されれば muted 属性を true にして消音状態にします。

JavaScript
document.addEventListener('DOMContentLoaded', () => {

  const videoWrappers = document.querySelectorAll('.video-wrapper');

  videoWrappers.forEach((wrapper) => {
    const video = wrapper.querySelector('video');
    // 必要に応じてボリュームを調整
    video.volume = .3;
    // チェックボックスの要素
    const checkbox = wrapper.querySelector('input[type="checkbox"]');
    // チェックボックスの change イベントにリスナーを設定
    checkbox.addEventListener('change', (e) => {
      if (e.currentTarget.checked) {
        // チェックされれば muted 属性を false に(音を出す)
        video.muted = false;
      } else {
        video.muted = true;
      }
    });
  });
}, false);
.video-wrapper {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  position: relative;
  width: 100%;
  max-width: 1600px;
  margin: 0 auto;
}

.video-wrapper::before {
  content: "";
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background-color: rgba(9, 2, 108, 0.15);
}

.video-wrapper video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-content {
  margin: 0;
  position: absolute;
  top: 38%;
  margin-top: 1rem;
  left: 50%;
  margin-right: -50%;
  transform: translate(-50%, -50%);
  color: #fff;
  text-align: center;
}

.video-content h2 {
  font-size: 2rem;
  letter-spacing: 0.1rem;
  text-shadow: 2px 2px 2px #444;
}

.video-content p {
  max-width: 600px;
  padding: 0 2rem;
}

.video-credit {
  position: absolute;
  right: 1rem;
  bottom: .5rem;
  color: #ccc;
  font-size: 12px;
}

/* チェックボックスの親要素 */
.bgm-opt {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  color: #fff;
}

@media screen and (min-width: 481px) {
  .video-wrapper {
    aspect-ratio: 1600 / 897;
  }

  .video-content {
    top: 43%;
    margin-top: 0;
  }
}

@media only screen and (min-width: 768px) {
  .video-content h2 {
    font-size: 2.5rem;
  }

  .video-content p {
    max-width: 600px;
    padding: 0 0;
  }
}

@media only screen and (min-width: 992px) {
  .video-content h2 {
    font-size: 3rem;
  }
}

@media only screen and (min-width: 1139px) {
  .video-content h2 {
    font-size: 3.5rem;
  }
}

サンプルを別ウィンドウで開く

関連ページ:JavaScript フォームとフォームコントロールの使い方

audio 要素で音声データを別途用意

以下は動画とは別に音声データ(mp3 ファイル)を用意して、チェックボックスの状態で音声データの再生・停止を行う例です。

audio 要素には controls 属性を指定せず、非表示にしています。また、loop 属性を指定して繰り返し再生するようにしています。

HTML
<div class="video-wrapper">
  <div class="video-wrapper">
    <video muted autoplay playsinline loop poster="poster.jpg">
      <source src="sample.webm" type="video/webm">
      <source src="sample.mp4" type="video/mp4">
    </video>
  </div>
  <div class="bgm">
    <audio src="sample.mp3" loop></audio> <!-- audio 要素 -->
    <input type="checkbox" id="music-on1">
    <label for="music-on1"> 音声 </label>
  </div>
</div>

JavaScript は前述の例とほぼ同じですが、動画の muted 属性を操作する代わりに、audio 要素の play() と pause() で音声の再生・停止を行っています。

JavaScript
document.addEventListener('DOMContentLoaded', () => {

  const videoWrappers = document.querySelectorAll('.video-wrapper');

  videoWrappers.forEach((wrapper) => {
    // audio 要素を取得
    const audio = wrapper.querySelector('audio');
    // 必要に応じてボリュームを調整
    audio.volume = .7;
    // チェックボックスの要素
    const checkbox = wrapper.querySelector('input[type="checkbox"]');
    // チェックボックスの change イベントにリスナーを設定
    checkbox.addEventListener('change', (e) => {
      if (e.currentTarget.checked) {
        // チェックされれば audio 要素を再生
        audio.play();
      } else {
        // チェックが外されれば再生を停止
        audio.pause();
      }
    });
  });
}, false);
.video-wrapper {
  aspect-ratio: 1/1;
  width: 100%;
  max-width: 1600px;
  margin: auto;
  position: relative;
}

.video-wrapper video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
}

.bgm {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  color: #fff;
}

@media screen and (min-width: 480px) {
  .video-wrapper {
    aspect-ratio: 16/9;
  }
}

サンプルを別ウィンドウで開く

video のメソッド

video 要素では以下のようなメソッドを利用できます。

HTMLMediaElement のメソッド(一部抜粋)
メソッド 説明
load() ビデオを先頭にリセットし、最適なソースを選択してビデオを読み込むプロセスを開始します。先読みされるビデオデータの量は、要素の preload 属性の値によって決まります。
pause() 再生を一時停止します。
play() 再生を開始します。play() メソッドは再生が開始されたときに解決または拒否される Promise を返します。
fastSeek() 低い精度で素早く指定時刻にシークします(※ Chrome ではサポートされていないのでエラー)。代わりに currentTime プロパティを設定すればその時刻にシークします。

以下はホバー時に動画を再生し、マウスアウトすると一時停止する例です。タッチデバイスの場合は、動画をタップすると再生され、動画以外の部分をタップすると一時停止します。

HTML
<div class="hover-video-wrapper">
  <video src="sample.mp4" poster="poster.jpg"></video>
</div>

この例の場合、動画の親要素(.hover-video-wrapper)の mouseenter と mouseleave イベントを使って、動画の再生と一時停止を設定しています。また、video 要素の属性を JavaScript のプロパティを使って設定していますが、video 要素に HTML で設定した方が管理しやすいかも知れません。

document.addEventListener('DOMContentLoaded', () => {

  const hoverVideoWrappers = document.querySelectorAll('.hover-video-wrapper');

  hoverVideoWrappers.forEach((wrapper) => {
    // video 要素
    const video = wrapper.querySelector('video');
    // プロパティを設定
    video.muted = true;
    video.setAttribute('playsinline', '');
    video.preload = 'auto';

    // .hover-video-wrapper の mouseenter イベント
    wrapper.addEventListener('mouseenter', ()=> {
      video.play(); // 再生
    }, false);

    // .hover-video-wrapper の mouseleave イベント
    wrapper.addEventListener('mouseleave', ()=> {
      video.pause(); // 一時停
    }, false);
  });
});
.hover-video-wrapper {
  aspect-ratio: 1618/1000;
  width: 100%;
  max-width: 600px;
  position: relative;
  overflow: hidden;
}

/* オーバーレイ */
.hover-video-wrapper::before {
  content: '';
  position: absolute;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background-color: rgba(0, 0, 0, 0.4);
  transition: background-color 1s; /* トランジション */
}

/* ホバー時のオーバーレイ */
.hover-video-wrapper:hover::before {
  background-color: rgba(0, 0, 0, 0);
}

.hover-video-wrapper video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

以下はボタンをクリックすると動画の再生と一時停止をトグルする例です。また、Back ボタンをクリックすると currentTime プロパティを使って動画を先頭に戻します。

HTML
<div class="js-video-wrapper">
  <video src="sample.mp4" poster="poster.jpg"></video>
  <button class="play" type="button">Play</button>
  <button class="back" type="button">Back</button>
</div>

play() メソッドは Promise を返すので、その Promise を監視することで実際の再生状態が判定できます。

await を指定した Promise が rejected となった場合はエラーをスローするので try...catch 構文を使って判定しています。

また、ビデオの再生終了の検出は ended イベントを利用しています。

JavaScript
document.addEventListener('DOMContentLoaded', () => {

  const videoWrappers = document.querySelectorAll('.js-video-wrapper');

  videoWrappers.forEach((wrapper) => {
    // video 要素
    const video = wrapper.querySelector('video');
    video.muted = true;
    video.setAttribute('playsinline', '');
    video.preload= 'auto';

    // Play ボタン
    const play = wrapper.querySelector('button.play');
    // Back ボタン
    const back = wrapper.querySelector('button.back');

    // Play ボタンに click イベントのリスナーを登録
    play.addEventListener('click', handlePlayBtn, false);
    // Back ボタンに click イベントのリスナーを登録
    back.addEventListener('click', handleBackBtn, false);
    // video 要素に ended イベントのリスナーを登録
    video.addEventListener('ended', videoEnded, false);

    // ビデオを再生する非同期関数
    async function playVideo() {
      try {
        // await を指定して Promise が確定するまで待つ
        await video.play();
        // Promise が解決されたらボタンに playing クラスを追加してテキストを変更
        play.classList.add('playing');
        play.textContent = 'Pause';
      } catch (err) {
        // 再生が開始されない場合(Promise が拒否された場合)はクラスを削除
        play.classList.remove('playing');
      }
    }

    // Play ボタンのクリックイベントのリスナー
    function handlePlayBtn() {
      // ビデオが一時停止状態の場合(読み取り専用の paused プロパティで判定)
      if (video.paused) {
        // playVideo()を呼び出す
        playVideo();
      } else {
        // 一時停止状態でなければ、一時停止しクラスを削除しテキストを変更
        video.pause();
        play.textContent = 'Play';
        play.classList.remove('playing');
      }
    }

    // Back ボタンのクリックイベントのリスナー
    function handleBackBtn() {
      // ビデオが一時停止状態の場合
      if (video.paused) {
        // 先頭に戻す
        video.currentTime = 0;
      } else {
        // 一時停止状態でなければ、一時停止して先頭に戻し、クラスを削除しテキストを変更
        video.pause();
        video.currentTime = 0;
        play.textContent = 'Play';
        play.classList.remove('playing');
      }
    }

    // ビデオが終了した際に発生する ended イベントのリスナー
    function videoEnded() {
      // ビデオが終了したら、ボタンのラベルを変更し playing クラスを削除
      play.textContent = 'Play';
      play.classList.remove('playing');
    }
  });
});

参考サイト:

.js-video-wrapper {
  margin: 50px 0;
}

.js-video-wrapper video {
  aspect-ratio: 1618/1000;
  width: 100%;
  height: auto;
  max-width: 600px;
  display: block;
}

.js-video-wrapper button {
  padding: 8px 20px;
  color: #fff;
  width: 7rem;
  margin: 10px 10px 0 0;
  border: none;
}

.js-video-wrapper button.play {
  background-color: #589462;
}

.js-video-wrapper button.back {
  background-color: #5a6faf;
}

.js-video-wrapper button.play.playing {
  background-color: #dd7703;
}

video のイベント

video 要素では以下のようなイベントを利用できます。

これらのイベントを受け取るには、addEventListener() を使用するか、「onイベント名」プロパティ(onevent ハンドラー)にイベントリスナーを設定します。

HTMLMediaElement のイベント(一部抜粋)
イベント 発生するタイミング
abort リソースを完全に読み込めなかったとき(エラーが原因でない場合)
canplay 再生できる状態になったとき(途中でバッファリングのために停止する可能性あり)
canplaythrough 最後まで再生できる状態になったとき(最後まで再生するのに十分なデータが読み込まれた)
ended メディアの終わりに達した(またはそれ以上利用できるデータがない)とき
error エラー(ネットワーク接続の問題など)によりリソースが読み込めなかったとき
loadeddata メディアの1フレーム目の読み込みが終了したとき
loadedmetadata リソースのメタデータ(再生時間などのメタ情報)が読み込まれたとき
loadstart リソースの読み込みを開始したとき
pause 再生を一時停止したとき。pause() メソッドが呼び出されたとき
play 再生を開始したとき。play() メソッド、または autoplay 属性の結果として、paused プロパティが true から false に変更されたとき
progress ブラウザーがリソースを読み込む際に発生
ratechange 再生速度(再生レート)が変更されたとき
seeked シーク動作が完了したとき(現在の再生位置が変更され、論理属性の seeking が false に変更されたとき)。
seeking シーク動作が開始されたとき
stalled リソースのデータを読み込もうとしたがデータが得られなかったとき
suspend リソースの読み込みが中断されたとき
timeupdate 再生時刻を表す currentTime プロパティの値が更新されたとき
volumechange 音量を変更したとき。または mute 属性を変更したとき。
waiting 一時的なリソースのデータ不足で再生が停止したとき(データの読み込みが遅く、再生を続けられないとき)

以下は video 要素の canplaythrough イベントに addEventListener() と oncanplaythrough ハンドラでリスナーを登録する例です。

いずれも「canplaythrough:動画全体を再生できるはずです」とコンソールに出力されます。

// video 要素を取得
const video = document.querySelector('video');

// addEventListener で canplaythrough イベントにリスナーを設定
video.addEventListener('canplaythrough', (event) => {
  console.log(event.type + ':動画全体を再生できるはずです');
});

// oncanplaythrough で canplaythrough イベントにリスナーを設定
video.oncanplaythrough= (event) => {
  console.log(event.type + ':動画全体を再生できるはずです');
};

以下は autoplay 属性を指定したビデオで発生するイベントを出力する例です。

<video id="eventTarget" src="sample.mp4" controls muted autoplay playsinline poster="poster.jpg"></video>
<button type="button" id="clear-events">Clear Events</button>
<ol id="events"></ol>

ファイルの読み込みやコントロールの操作(再生ボタンや停止ボタン、シークバーのクリック、再生速度の変更)、ビデオ終了時に発生するイベントが出力されます。

但し、タイミングにより検出されるイベントが異なります(loadstart が検出されなかったり、play のみが検出されるなど)。そのため、再読込すると出力される内容が異なる場合があります。

また、Chrome や Firefox ではシークバーを操作すると canplay や canplaythrough が表示(検出)されますが、Safari では seeked のみが検出されます。

この例の場合、DOMContentLoaded を使うと、loadstart イベントを検知できなかったので以下は DOMContentLoaded を使用していません。

const video = document.getElementById('eventTarget');
const ol =  document.getElementById('events');

// 各イベントにリスナー(listEvents)を登録
video.addEventListener('loadstart', listEvents);
video.addEventListener('loadeddata', listEvents);
video.addEventListener('loadedmetadata', listEvents);
video.addEventListener('canplay', listEvents);
video.addEventListener('canplaythrough', listEvents);
video.addEventListener('play', listEvents);
video.addEventListener('pause', listEvents);
video.addEventListener('ratechange', listEvents);
video.addEventListener('seeked', listEvents);
video.addEventListener('ended', listEvents);

// リスナーの定義
function listEvents(e) {
  // li 要素を生成
  const li = document.createElement('li');
  // 生成した li 要素のテキストにイベント名(e.type)を設定
  li.textContent = e.type;
  ol.appendChild(li);
}

document.getElementById('clear-events').addEventListener('click', ()=> {
  ol.innerHTML = '';
});

以下は、video 要素の canplaythrough イベントを検知したら、ポジションのアニメーションを実行し、アニメーションが終了したら動画を再生する例です。

HTML
<div class="js-video-wrapper">
  <video src="sample.mp4" controls poster="poster.jpg"></video>
</div>

アニメーションは Web Animation API を使って、終了したら onfinish イベントハンドラを使って動画の再生を開始しています。

JavaScript
document.addEventListener('DOMContentLoaded', () => {
  // .video-wrappe を取得
  const jsVideoWrappers = document.querySelectorAll('.js-video-wrapper');
  // 取得した各 .video-wrappe で
  jsVideoWrappers.forEach((wrapper) => {
    // video 要素を取得
    const video = wrapper.querySelector('video');
    video.muted = true;
    video.setAttribute('playsinline', '');
    video.preload = 'auto';

    // video 要素に canplaythrough イベントのリスナを設定
    video.addEventListener('canplaythrough', () => {
      // ポジションを移動するアニメーション
      const slideUp = video.animate(
        {
          objectPosition: ['50% 100%', '50% 0%']
        },
        {
          duration: 1500,
          easing: 'ease-out',
        }
      );
      // アニメーションが終了したら動画を再生
      slideUp.onfinish = () => {
        video.play();
      }
    }, false);
  });
}, false);
CSS
.js-video-wrapper {
  aspect-ratio: 2/1;
  width: 100%;
}

.js-video-wrapper video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
}

Chrome や Firefox ではシークバーをクリックすと canplay や canplaythrough イベントが発生するので、再度ポジションのアニメーションが実行され、その後動画が再生されます(Safari ではなりません)。

繰り返し再生される

Chrome や Firefox では currentTime プロパティを操作すると、canplay や canplaythrough イベントが発生するため、以下を記述すると0〜5秒の間を繰り返し再生されてしまいます。

31行目で currentTime に0を設定していますが、canplaythrough イベントが発生して繰り返し再生されます。ループさせないようにするには、addEventListener() の第3引数に {once: true} を指定します。

但し、Safari では currentTime プロパティを操作しても canplay や canplaythrough イベントは発生しないので、繰り返し再生されません。

document.addEventListener('DOMContentLoaded', () => {
  const jsVideoWrappers = document.querySelectorAll('.js-video-wrapper');
  jsVideoWrappers.forEach((wrapper) => {
    const video = wrapper.querySelector('video');
    video.muted = true;
    video.setAttribute('playsinline', '');
    video.preload = 'auto';

    video.addEventListener('canplaythrough', () => {
      const slideUp = video.animate(
        {
          objectPosition: ['50% 100%', '50% 0%']
        },
        {
          duration: 1500,
          easing: 'ease-out',
        }
      );
      slideUp.onfinish = () => {
        video.play();
      }
    }, false);  //ループさせない場合は第3引数に {once: true} を指定

    // timeupdate を監視
    video.addEventListener('timeupdate', () => {
      // currentTime が5以上になったら
      if (video.currentTime >= 5) {
        // 一時停止
        video.pause();
        // currentTime に0を設定(ループする)
        video.currentTime = 0;
      }
    }, false);
  });
}, false);

サンプルを別ウィンドウで開く

指定した範囲を繰り返し再生

以下は指定した範囲を繰り返し再生する例です。

この例では、js-loop クラスを指定した video 要素に data-start-time と data-end-time(カスタム属性)で指定された範囲で繰り返し再生します。

HTML
<video class="js-loop" data-start-time="5" data-end-time="10" src="sample.mp4" controls playsinline poster="poster.jpg"></video>    

JavaScript ではカスタム属性に指定された値を dataset プロパティで取得して、それらが設定されていれば timeupdate を監視します。

currentTime が data-end-time の値より大きくなれば、currentTime を data-start-time の値に設定して再生位置を戻しています。

timeupdate イベントの頻度はシステムの稼働状況に依存するので、指定した正確な範囲を繰り返すことはできません。

また、iOS(iPhone)ではビデオをロードする前に currentTime に0以外の値を設定すると正しく動作しないので、最初に currentTime に値を設定する際は loadeddata イベントで設定しています(または、preload に metadata を設定します。iPhone で currentTime が設定できない)。

JavaScript
document.addEventListener('DOMContentLoaded', () => {
  const jsLoopVideos = document.querySelectorAll('.js-loop');
  jsLoopVideos.forEach((video) => {
    video.muted = true;
    //video.autoplay = true; // 自動再生する場合

    // カスタム属性の値を dataset プロパティで取得して数値に変換
    const startTime = parseInt(video.dataset.startTime);
    const endTime = parseInt(video.dataset.endTime);

    //カスタム属性の値が設定されていれば
    if(startTime && endTime) {
      // 開始時刻を設定(iOS でバグ?のため loadeddata で currentTime を設定)
      video.addEventListener('loadeddata', ()=> {
        video.currentTime = startTime;
      });
      // timeupdate を監視
      video.addEventListener('timeupdate',loop, false);
    }

    //リスナー関数
    function loop() {
      if( video.currentTime >= endTime ) {
        //現在の再生時刻が指定された終了時刻を超えたら開始時刻を設定
        video.currentTime = startTime;
      }
    }
  });
}, false);
CSS
.js-loop {
  aspect-ratio: 16/9;
  width: 70%;
  height: auto;
  max-width: 500px;
}

以下を再生すると、開始5秒の時点からおよそ10秒の間を繰り返します。

Media Fragments URI

再生する範囲を指定する方法として Media Fragments URI という特別な URI の指定方法があります。但し、一部のブラウザは対応してません。

<audio> または <video> 要素に対してメディアの URI を src 属性に指定する際に、再生するメディアの再生範囲を指定するための追加情報を記述することができます。

以下の書式でハッシュマーク (#) に続いてメディアフラグメントの記述を追加します。

#t=[starttime][,endtime]

例えば、以下のように #t= に時間を指定すると動画の3秒~10秒の部分を再生します。

<video src="sample.mp4#t=3,10"></video>

can i use Media Fragments

MDN 音声と動画の配信(再生範囲の指定)

iPhone で currentTime が設定できない

currentTime プロパティに値を設定すると指定された時刻にシーク(移動)するはずですが、iPhone では初期状態(ロード前)で値に 0 以外を設定すると正しく動作しません。

0を指定する場合は問題ありません(2023年4月の時点)。

<video src="sample.mp4" controls playsinline poster="poster.jpg"></video>

以下は currentTime プロパティに値に 0 以外を設定する例です。

JavaScript
const video = document.querySelector('video');
video.currentTime = 13;  // currentTime に 0 以外を設定

iPhone 以外では currentTime プロパティに指定した時刻から動画を開始(再生)することができます。

iPhone の場合は、 currentTime プロパティの設定は無視され、最初(0の位置)から再生されてしまい、2回目以降は再生できません(再生するとシークバーの時刻のみは13になっている)。

また、以下を iPhone で見ると、poster 属性に代替画像を設定しているにも関わらす、再生ボタンのみが表示され正常に動作しません。

解決策

ビデオが最初にロードされたときに、フレームがまだロードされていないと、iPhone の場合、currentTime の(0 以外への)変更を許可しないようです。

解決策の1つは前述の例同様、loadeddata イベントを使って currentTime を設定する方法です。

const video = document.querySelector('video');

//loadeddata イベントで currentTime を設定
video.addEventListener('loadeddata', ()=> {
  video.currentTime = 13;
});

上記の場合、iPhone でも currentTime で指定した13秒の位置から再生でき、また、 poster 属性に指定したポスター画像も表示されます。

preload="metadata" を追加

もっと、簡単な方法は video 要素の preload 属性に "metadata" を設定するだけです。

<video src="sample.mp4" preload="metadata" controls playsinline poster="poster.jpg"></video><!-- preload="metadata" を追加 -->

HTML の属性ではなく、JavaScript で設定しても同じです。

const video = document.querySelector('video');

// preload プロパティに  "metadata" を設定
video.preload = 'metadata';
video.currentTime = 13;

preload="metadata" を追加した場合、以下のいずれで currentTime を設定しても正常に動作しました。

JavaScript
// preload="metadata" を追加していれば、単に以下でOK
video.currentTime = 13;

//loadedmetadata イベントで currentTime を設定(preload="metadata" の追加が必要)
video.addEventListener('loadedmetadata', ()=> {
  video.currentTime = 13;
});

//loadeddata イベントで currentTime を設定(preload="metadata" の追加は不要)
video.addEventListener('loadeddata', ()=> {
  video.currentTime = 13;
});

HTML5 Video - currentTime not setting properly on iPhone」を参考にさせていただきました。

他のビデオの再生を停止

以下はそのページで1つの動画だけを再生する例です。動画の再生ボタンをクリックすると、その動画は再生されますが、他に再生中の動画があれば全て一時停止されます。

addEventListener でドキュメントの play イベントにリスナーを設定し、第3引数(useCapture)を true に設定します。リスナーでは全ての video 要素を取得して、play イベントが発生した要素が自身でなければ pause() メソッドで一時停止させます。

document.addEventListener('DOMContentLoaded', () => {
  // ドキュメントの play イベント
  document.addEventListener('play', (e) => {
    // 全ての video 要素を取得
    const videos = document.querySelectorAll('video');
    videos.forEach((video) => {
      // play イベントが発生した要素が自身でなければ一時停止
      if(video !== e.target) {
        video.pause();
      }
    });
  }, true); // addEventListener()の第3引数(useCapture)を true に
}, false);

以下はそのページの exv クラスが指定された video 要素を対象にする場合の例です(このページでは一部の動画に対して以下を設定しています)。

document.addEventListener('DOMContentLoaded', () => {
  document.addEventListener('play', (e) => {
    // 全ての exv クラスが指定された video 要素を取得
    const exclusiveVideos = document.querySelectorAll('.exv');
    exclusiveVideos.forEach((exv) => {
      if(exv !== e.target) {
        exv.pause();
      }
    });
  }, true); // useCapture を true に
}, false);

動画の軽量化

動画のファイルサイズが大きいと読み込みに時間がかかるため軽量化してファイルサイズを小さくする必要があります。

動画ファイルを軽量化するソフト(ツール)は色々ありますが、HandBrake という無料のソフトを使えば、比較的簡単にファイルを軽量化したり、動画形式を mp4 や webm に変換することができます。

HandBrake を使った動画の軽量化の方法は以下のページを御覧ください。