2026年9月16日

2026年9月16日

WordPressに動画背景とアニメーションを実装する方法|表示速度とアクセシビリティを両立

WordPressで動画背景を入れるなら、手軽さを優先する場合はカバーブロック、細かく制御したい場合はテーマに <video> タグを書く方法が向いています。どちらの場合も、動画を短く軽く圧縮すること、ポスター画像を用意すること、動きを止める手段を用意することの3点で、表示速度と使いやすさが大きく変わります。この記事では、動画ファイルの作り方から、ブロックエディタでの設定、テーマへの組み込み、スクロールに合わせたアニメーションの実装と確認方法までを順に説明します。

先に動画ファイルを軽くする

動画背景で表示が重くなる原因の大半は、実装方法ではなくファイルそのものの大きさです。スマートフォンで撮った数十MBの動画をそのままアップロードすると、どんな書き方をしても読み込みに時間がかかります。背景用の動画は次の方針で作り直すのが基本です。

  • 長さ:5〜15秒程度のループ素材にする。背景は見続けるものではないので、短くても違和感はあまり出ません。
  • 解像度とフレームレート:横1280px前後、24〜30fpsで多くの場面に足ります。全画面でもぼかしや暗いオーバーレイを重ねるなら、高解像度は不要です。
  • 音声:背景動画は消音で再生するため、音声トラックは削除します。
  • 形式:互換性の高い MP4(H.264)を基本に、より小さくできる WebM(VP9)を併用します。

変換には無料のコマンドラインツール ffmpeg が使えます。

# MP4(H.264)。-an で音声を削除、+faststart で先頭から再生を始めやすくする
ffmpeg -i input.mov -an -vf "scale=1280:-2,fps=24" -c:v libx264 -crf 28 -preset slow -pix_fmt yuv420p -movflags +faststart hero.mp4

# WebM(VP9)。-b:v 0 と -crf の組み合わせで画質基準のエンコードにする
ffmpeg -i input.mov -an -vf "scale=1280:-2,fps=24" -c:v libvpx-vp9 -crf 38 -b:v 0 -row-mt 1 hero.webm

# ポスター画像(動画の1フレーム目を書き出す)
ffmpeg -i hero.mp4 -frames:v 1 -q:v 3 hero-poster.jpg

-crf は数字が大きいほど小さく粗くなります。まず書き出して実際に再生し、背景として気にならない範囲でファイルサイズを詰めていくのが手早い方法です。目安として、背景動画は数MB以内に収めると扱いやすくなります。

ポスター画像は、動画の読み込み中や、自動再生が止められた環境で代わりに表示されます。iPhoneの低電力モードなど、自動再生が行われない環境は珍しくないため、ポスター画像だけでもデザインとして成立するものを選んでください。

ブロックエディタのカバーブロックで設定する

コードを書かずに動画背景を作るなら、カバーブロックが最も手軽です。

  1. 投稿や固定ページの編集画面でカバーブロックを追加する
  2. 「アップロード」またはメディアライブラリから動画ファイルを選ぶ
  3. オーバーレイの色と不透明度を調整し、上に載せる文字が読めるか確認する
  4. ブロックの中に見出しやボタンを配置する

カバーブロックで動画を選ぶと、自動再生・消音・ループ・インライン再生の属性が付いた <video> タグが出力されます。スマートフォンのブラウザは、消音かつインライン再生の指定がない動画を自動再生しないため、この点はブロック側で面倒を見てくれます。

一方で、WebMとMP4の両方を指定する、画面幅によって動画を読み込まないようにする、といった細かい制御はカバーブロックの設定だけでは難しくなります。そうした要件がある場合は、次のようにテーマ側で実装します。

テーマに動画背景を組み込む

HTMLとCSS

子テーマのテンプレート(トップページ用のテンプレートパーツなど)に次のマークアップを書きます。親テーマを直接編集すると、テーマの更新で消えてしまうので避けてください。

<?php
$hero_dir = get_stylesheet_directory_uri() . '/assets/video/';
?>
<section class="hero">
	<video class="hero__video" muted loop playsinline preload="none"
		poster="<?php echo esc_url( $hero_dir . 'hero-poster.jpg' ); ?>"
		data-src-webm="<?php echo esc_url( $hero_dir . 'hero.webm' ); ?>"
		data-src-mp4="<?php echo esc_url( $hero_dir . 'hero.mp4' ); ?>"
		aria-hidden="true"></video>
	<div class="hero__overlay"></div>
	<div class="hero__content">
		<h2 class="hero__title"><?php echo esc_html( get_bloginfo( 'name' ) ); ?></h2>
	</div>
	<button type="button" class="hero__toggle" aria-pressed="false" hidden>背景動画を停止</button>
</section>

ポイントは、<source> をHTMLに直接書かず、data- 属性にURLを置いている点です。こうすると、ページを開いた時点では動画のダウンロードが始まりません。どの画面幅で再生するか、動きを減らす設定になっていないかをJavaScriptで判定してから読み込むためです。動画は装飾なので aria-hidden="true" を付け、意味のある情報は見出しなどのテキストで伝えます。

.hero {
	position: relative;
	min-height: 70vh;
	display: grid;
	place-items: center;
	overflow: hidden;
	background: #1a1a1a url("assets/video/hero-poster.jpg") center / cover no-repeat;
}
.hero__video,
.hero__overlay {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}
.hero__video {
	object-fit: cover;
}
.hero__overlay {
	background: rgba(0, 0, 0, 0.45);
}
.hero__content {
	position: relative;
	color: #fff;
	text-align: center;
	padding: 2rem 16px;
}
.hero__toggle {
	position: absolute;
	right: 16px;
	bottom: 16px;
}

背景色とポスター画像をセクション自体にも指定しているのは、動画を読み込まない場合でも見た目が崩れないようにするためです。この CSS を子テーマの style.css に書く場合、画像のパスは style.css から見た相対パスになります。オーバーレイの濃さは、白文字とのコントラストが十分取れる値にしてください。

JavaScriptで条件付きで読み込み、停止ボタンを付ける

document.addEventListener( 'DOMContentLoaded', function () {
	var video  = document.querySelector( '.hero__video' );
	var toggle = document.querySelector( '.hero__toggle' );
	if ( ! video ) {
		return;
	}

	var reduceMotion = window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches;
	var wideScreen   = window.matchMedia( '(min-width: 768px)' ).matches;

	// 動きを減らす設定の人と狭い画面では読み込まない(ポスター画像のみ)
	if ( reduceMotion || ! wideScreen ) {
		return;
	}

	[ [ 'webm', 'video/webm' ], [ 'mp4', 'video/mp4' ] ].forEach( function ( item ) {
		var src = video.dataset[ 'src' + item[0].charAt( 0 ).toUpperCase() + item[0].slice( 1 ) ];
		if ( src ) {
			var source  = document.createElement( 'source' );
			source.src  = src;
			source.type = item[1];
			video.appendChild( source );
		}
	} );
	video.load();

	var playPromise = video.play();
	if ( playPromise && playPromise.catch ) {
		playPromise.catch( function () {
			// 自動再生が拒否された環境ではポスター画像のまま
		} );
	}

	if ( toggle ) {
		toggle.hidden = false;
		toggle.addEventListener( 'click', function () {
			if ( video.paused ) {
				video.play();
				toggle.textContent = '背景動画を停止';
				toggle.setAttribute( 'aria-pressed', 'false' );
			} else {
				video.pause();
				toggle.textContent = '背景動画を再生';
				toggle.setAttribute( 'aria-pressed', 'true' );
			}
		} );
	}
} );

停止ボタンは飾りではありません。ウェブアクセシビリティの指針(WCAG)では、自動で始まり5秒を超えて続く動きには、一時停止や停止の手段を用意することが求められています。動きで気分が悪くなる人や、集中を妨げられる人への配慮でもあります。OSの「視差効果を減らす」「アニメーションを減らす」設定は prefers-reduced-motion で判定できるので、その場合は最初から動画を読み込まない作りにしています。

このスクリプトは functions.php で読み込みます。WordPress 6.3 以降では、wp_enqueue_script() の第5引数で defer を指定できます。

add_action( 'wp_enqueue_scripts', function () {
	if ( ! is_front_page() ) {
		return;
	}
	wp_enqueue_script(
		'hero-video',
		get_stylesheet_directory_uri() . '/assets/js/hero-video.js',
		array(),
		'1.0.0',
		array(
			'in_footer' => true,
			'strategy'  => 'defer',
		)
	);
} );

トップページだけで使う処理なので、is_front_page() で読み込むページを限定しています。

スクロールに合わせたアニメーション

動画以外の動き、たとえば要素が画面に入ったときにふわっと表示する演出は、Intersection Observer で実装するのが一般的です。スクロールのたびに位置を計算する方式より負荷が軽く済みます。

.js .reveal {
	opacity: 0;
	transform: translateY(24px);
	transition: opacity 0.6s ease, transform 0.6s ease;
}
.js .reveal.is-visible {
	opacity: 1;
	transform: none;
}
@media (prefers-reduced-motion: reduce) {
	.js .reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}
}
document.documentElement.classList.add( 'js' );

document.addEventListener( 'DOMContentLoaded', function () {
	var targets = document.querySelectorAll( '.reveal' );
	if ( ! ( 'IntersectionObserver' in window ) ) {
		targets.forEach( function ( el ) { el.classList.add( 'is-visible' ); } );
		return;
	}
	var observer = new IntersectionObserver( function ( entries ) {
		entries.forEach( function ( entry ) {
			if ( entry.isIntersecting ) {
				entry.target.classList.add( 'is-visible' );
				observer.unobserve( entry.target );
			}
		} );
	}, { rootMargin: '0px 0px -10% 0px' } );
	targets.forEach( function ( el ) { observer.observe( el ); } );
} );

非表示の状態を .js クラスの下にだけ書いているのは、スクリプトが読み込めなかったときに要素が見えないまま残るのを防ぐためです。このスクリプトを defer で読み込むと、js クラスが付くまでの一瞬だけ要素が見えてから消える「ちらつき」が出ることがあります。気になる場合は、js クラスを付ける1行だけを wp_head で <head> 内に出力してください。アニメーションさせるプロパティは opacity と transform に限ると、レイアウトの再計算が起きにくく滑らかに動きます。top や height を動かすと、ページ全体の再配置が走って重くなります。ブロックエディタでは、対象のブロックの「高度な設定」にある「追加 CSS クラス」に reveal と入れれば適用できます。

なお、CSSだけでスクロール連動のアニメーションを書ける animation-timeline という仕様もありますが、ブラウザごとの対応に差があります(2026年10月現在)。使う場合は @supports で対応ブラウザだけに適用し、非対応でも内容が普通に表示されるようにしてください。

表示速度とアクセシビリティの確認

実装したら、次の点を確認します。

  • ファイルサイズと読み込みタイミング:開発者ツールのネットワークタブで、ページを開いた直後に動画のダウンロードが始まっていないか、狭い画面では動画が読み込まれていないかを見ます。
  • LCP:ファーストビューを覆う動画背景では、ポスター画像が最大コンテンツの描画(LCP)の対象になることがあります。PageSpeed Insights で計測し、ポスター画像も圧縮しておきます。
  • 文字の読みやすさ:動画の最も明るい場面でも見出しが読めるか、一時停止して確かめます。
  • 動きを減らす設定:OSの設定を切り替えて、動画が読み込まれず、アニメーションも止まることを確認します。
  • キーボード操作:Tabキーで停止ボタンにたどり着け、押して動画が止まるかを確かめます。

YouTubeやVimeoの埋め込みを背景に使う方法もありますが、外部のプレーヤーとスクリプトを丸ごと読み込むため、自前の動画ファイルより重くなりやすく、ロゴや操作UIの制御にも制約があります。背景用途なら、圧縮した動画ファイルを自サイトから配信するほうが扱いやすいでしょう。

まとめ

  • 動画背景の重さは主にファイルサイズで決まる。短いループ・低めの解像度・音声なしで、MP4とWebMを用意する
  • 手軽さ重視ならカバーブロック、読み込み条件や複数形式を制御したいならテーマに <video> を書く
  • ポスター画像を用意し、自動再生されない環境でもデザインが成立するようにする
  • 停止ボタンと prefers-reduced-motion への対応で、動きが苦手な人にも配慮する
  • スクロールアニメーションは Intersection Observer と opacity・transform で実装し、JavaScriptが動かなくても内容が見えるようにする
  • 実装後はネットワークタブと PageSpeed Insights で読み込みとLCPを確認する

お気軽にご相談ください

お見積りへ お問い合わせへ
▲