【Next.js】背景動画のヒーローの作り方を解説|自動再生・軽量化・スマホ対応

公開日: 2026年9月12日 · 読了目安 13 分

Next.js のファーストビューに背景動画(ヒーロー動画)を置く方法をコード付きで解説。自動再生に必要な属性(muted・playsInline など)、ffmpeg での軽量化、再生前の静止画と表示速度、スマホや省データ設定で静止画に切り替える分岐、文字が読めるオーバーレイまで。

背景動画ヒーローが自動再生されない・重いときの答え

Next.js で LP を作っていて、ファーストビューの背景に動画を流したい。けれど動画を置いてみると、次のようなつまずきがよく起きます。

  • 自動再生されない

  • 読み込み中に黒い画面が出る

  • ページが重くなった

答えはシンプルです。動画のタグに、muted と playsInline を含む5つの指定をそろえて付けます。

動画のファイルは、10 秒前後・音声なしに圧縮します。

スマホや省データ設定の人には、再生前に表示する静止画だけを見せます。見出しの下には暗いオーバーレイを敷きます。

この記事で分かることは次のとおりです。

  • 背景動画のヒーローが向いているサイトと、向いていないサイト

  • そのまま使える Next.js のヒーロー動画コンポーネント

  • 自動再生される条件と、されないときの対処

  • 動画ファイルの軽量化と、再生前に見せる静止画の作り方

  • スマホ・省データ・動きを減らす設定のときに静止画へ切り替える方法

背景動画のヒーローが向いているサイト・向かないサイト

背景動画が力を発揮するのは、映像そのものが商品の魅力になる場合です。たとえば次のようなものは、静止画より動画の方が多くを伝えます。

  • 飲食店や宿泊施設の雰囲気

  • イベントの熱気

  • 映像制作の実績

  • ハードウェア製品の質感

一方、SaaS や業務ツールの LP では、動画が見出しと CTA から視線を奪いがちです。

この場合は、短い入場アニメーションを付けた静止画ヒーローの方が成果につながりやすくなります。作り方は https://design-layer.com/ja/articles/nextjs-animated-hero-section-guide で説明しています。

迷ったときは、まず静止画ヒーローで公開し、映像素材がそろってから動画に差し替えても遅くありません。

後から差し替えやすいよう、ヒーローの背景部分を1つのコンポーネントに分けておくと楽です。

Next.js の背景動画ヒーロー:基本のコンポーネント

まずは一番シンプルな形です。動画のタグ(video 要素)は、ブラウザの機能だけで再生されます。

そのため、この部品はサーバーで組み立てる部品(Server Component)のままで動きます。

動画ファイルと、再生前に表示する静止画(poster)は public/videos/ に置く想定です。

components/VideoHero.tsx
export function VideoHero() {
    return (
      <section className="relative isolate flex min-h-[100svh] items-end overflow-hidden px-6 pb-20 text-white md:px-12">
        <video
          className="absolute inset-0 -z-10 h-full w-full object-cover"
          autoPlay
          muted
          loop
          playsInline
          poster="/videos/hero-poster.jpg"
          aria-hidden="true"
        >
          <source src="/videos/hero.webm" type="video/webm" />
          <source src="/videos/hero.mp4" type="video/mp4" />
        </video>

        {/* 文字を読みやすくするための暗いグラデーション */}
        <div
          aria-hidden="true"
          className="absolute inset-0 -z-10 bg-gradient-to-t from-black/75 via-black/35 to-black/10"
        />

        <div className="max-w-2xl">
          <h1 className="text-4xl font-semibold leading-tight md:text-6xl">
            海辺の一棟貸し、週末の予約受付中
          </h1>
          <p className="mt-5 text-base text-white/80 md:text-lg">
            朝は波の音で目覚め、夜はテラスで焚き火を囲む。
          </p>
          <a
            href="#reserve"
            className="mt-8 inline-flex rounded-full bg-white px-6 py-3 font-medium text-zinc-950 transition hover:bg-white/90"
          >
            空室を確認する
          </a>
        </div>
      </section>
    );
  }

背景動画は5つの属性をセットで付ける(自動再生の条件は muted と playsInline)

autoPlay だけでは足りません。主要なブラウザは、音が出る動画の自動再生をブロックします。

muted で無音にすると、自動再生が許可されます。

iPhone の Safari では、動画が全画面プレーヤーに切り替わることがあります。これを防ぐのが playsInline です。

残りの2つは、繰り返し再生する loop と、再生が始まるまで表示する静止画の poster です。

自動再生の条件になるのは muted と playsInline です。この5つはセットで覚えてください。

WebM と MP4 を両方用意する

source は上から順に試されます。圧縮率の高い WebM を先に、対応範囲の広い MP4 を後に並べます。

WebM を用意する時間がなければ、MP4(H.264)1本でもほとんどのブラウザで再生できます。

装飾の背景動画には aria-hidden を付ける

背景動画が雰囲気づくりだけなら、aria-hidden="true" でスクリーンリーダーから隠します。伝えたい情報は、動画の中ではなく見出しと本文に文字で書きます。

背景動画が自動再生されないときの確認ポイント

コードが正しくても、端末の設定で自動再生が止まることがあります。代表的なのは、iPhone の低電力モードです。

この状態では動画が再生されず、再生前の静止画だけが表示されます。だからこそ、静止画だけでも成り立つヒーローにしておく必要があります。

自分の環境で再生されないときは、次の順で確認します。

  • 無音の指定(muted)と、全画面にしない指定(playsInline)が付いているか

  • 動画に音声トラックが残っていないか(muted がない場合に効く。ファイルも軽くなる)

  • 動画ファイルのパスが正しいか

  • 動画の圧縮形式(コーデック)が H.264 か

  • iPhone の低電力モードがオンになっていないか

音声トラックは、ffmpeg の -an で消せます。

パスは、public/ 以下のファイルなら / から書きます。

H.265 で書き出した MP4 は、ブラウザによって再生できないことがあります。

それでも再生が始まらない場合は、ブラウザで動く部品(Client Component)から再生を始める方法があります。

具体的には、動画の要素を直接さわって無音に設定し直し、play() を呼びます。

次の章のコードで、その形を紹介します。

背景動画を ffmpeg で軽量化する方法

背景動画で一番多い失敗は、ファイルが大きすぎることです。撮影したままの動画は数十 MB になることも珍しくありません。

ヒーロー用の動画は、次の目安まで削ります。

  • 長さは 6〜15 秒。ループのつなぎ目が目立たない場面を選ぶ

  • 横幅は 1280px 程度。全画面でも、暗いオーバーレイの下なら粗さは目立ちにくい

  • 音声トラックは削除する

  • ファイルサイズは数 MB 以内を目安にする

変換には、動画変換ツールの ffmpeg が使えます。

次のコマンドで、MP4・WebM・再生前に表示する静止画の3つを作れます。

bash
# MP4(H.264): 10 秒・横 1280px・音声なし・先頭から再生しやすい配置
  ffmpeg -i source.mov -t 10 -an -vf "scale=1280:-2,fps=30" -c:v libx264 -crf 28 -preset slow -pix_fmt yuv420p -movflags +faststart public/videos/hero.mp4

  # WebM(VP9): 同じ条件でより小さく
  ffmpeg -i source.mov -t 10 -an -vf "scale=1280:-2,fps=30" -c:v libvpx-vp9 -crf 38 -b:v 0 public/videos/hero.webm

  # poster 画像: MP4 の最初のフレームを書き出す
  ffmpeg -i public/videos/hero.mp4 -frames:v 1 -q:v 3 public/videos/hero-poster.jpg

crf の数値で背景動画の画質とサイズを調整する

crf は数値が大きいほど圧縮が強くなり、ファイルが小さくなります。

まず上の値で書き出し、粗さが気になれば数値を2〜3ずつ下げます。オーバーレイを敷く前提なら、思ったより強めに圧縮しても目立ちません。

再生前の静止画は表示速度にも関わる

再生前に表示する静止画は、LCP(ページの主要な内容が表示されるまでの時間)の対象になります。

この静止画が重いと、動画を軽くしても表示速度の評価は上がりません。

静止画も圧縮し、動画の1コマ目と同じ絵にしておきます。そうすれば、再生が始まる瞬間に画面が切り替わって見えません。

動画ファイルが大きくなる場合は、public/ に置かず、CDN やストレージサービスから配信することも検討してください。

スマホと省データ設定では背景動画を静止画にする

スマホのモバイル通信で背景動画を毎回読み込ませると、通信量とバッテリーを消費します。

次の人には、再生前の静止画だけを見せるのが現実的です。

  • 画面の小さい端末の人

  • 動きを減らす設定(prefers-reduced-motion)の人

  • 省データ設定の人

CSS の hidden で動画を隠すだけでは、動画のダウンロードが止まらないことがあります。

そこで、条件を満たしたときだけ動画ファイル(source)を追加する、ブラウザで動く部品にします。

そうすれば、不要な読み込みが発生しません。一時停止ボタンも付けておきます。

components/HeroVideo.tsx
"use client";

  import { useEffect, useRef, useState } from "react";

  type HeroVideoProps = {
    mp4: string;
    webm?: string;
    poster: string;
  };

  type NavigatorWithConnection = Navigator & {
    connection?: { saveData?: boolean };
  };

  export function HeroVideo({ mp4, webm, poster }: HeroVideoProps) {
    const ref = useRef<HTMLVideoElement>(null);
    const [enabled, setEnabled] = useState(false);
    const [playing, setPlaying] = useState(false);

    // 画面幅・動きを減らす設定・省データ設定を見て、動画を使うか決める
    useEffect(() => {
      const isWide = window.matchMedia("(min-width: 768px)").matches;
      const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
      const saveData = (navigator as NavigatorWithConnection).connection?.saveData === true;
      setEnabled(isWide && !reduceMotion && !saveData);
    }, []);

    // source を追加したあとに読み込みと再生を始める
    useEffect(() => {
      const video = ref.current;
      if (!enabled || !video) return;
      video.muted = true;
      video.load();
      video
        .play()
        .then(() => setPlaying(true))
        .catch(() => setPlaying(false)); // ブロックされたら poster のまま
    }, [enabled]);

    function togglePlayback() {
      const video = ref.current;
      if (!video) return;
      if (video.paused) {
        video.play().then(() => setPlaying(true)).catch(() => {});
      } else {
        video.pause();
        setPlaying(false);
      }
    }

    return (
      <>
        <video
          ref={ref}
          className="absolute inset-0 -z-10 h-full w-full object-cover"
          poster={poster}
          muted
          loop
          playsInline
          aria-hidden="true"
        >
          {enabled && webm ? <source src={webm} type="video/webm" /> : null}
          {enabled ? <source src={mp4} type="video/mp4" /> : null}
        </video>
        {enabled ? (
          <button
            type="button"
            onClick={togglePlayback}
            className="absolute bottom-6 right-6 rounded-full bg-black/50 px-4 py-2 text-sm text-white backdrop-blur"
          >
            {playing ? "動画を停止" : "動画を再生"}
          </button>
        ) : null}
      </>
    );
  }

動画ヒーローの本体はサーバー側の部品のまま使う

HeroVideo は、背景部分だけのブラウザで動く部品です。

見出しやボタンを含むヒーロー本体は、サーバーで組み立てる部品のままにします。

基本形の動画タグの代わりに、HeroVideo を置きます。

見出しの HTML はサーバーで出力されるので、検索エンジンにもそのまま伝わります。

tsx
<section className="relative isolate flex min-h-[100svh] items-end overflow-hidden px-6 pb-20 text-white">
    <HeroVideo mp4="/videos/hero.mp4" webm="/videos/hero.webm" poster="/videos/hero-poster.jpg" />
    <div aria-hidden="true" className="absolute inset-0 -z-10 bg-gradient-to-t from-black/75 via-black/35 to-black/10" />
    {/* 見出し・本文・CTA */}
  </section>

背景動画に一時停止ボタンを付ける理由

Web アクセシビリティの基準である WCAG 2.2 では、自動で始まり 5 秒より長く続く動きには、止める手段が求められています(達成基準 2.2.2)。

ループする背景動画はこれに当たるため、小さな停止ボタンを置いておきます。

背景動画の上でも見出しが読めるオーバーレイ

動画は明るい場面と暗い場面が入れ替わるため、ある瞬間だけ見出しが読めなくなることがあります。

動画の上に半透明の黒を敷き、どのコマでも白い文字が読める状態にします。

見出しを下寄せにするなら、下から上に薄くなるグラデーション(bg-gradient-to-t from-black/75)が自然です。中央に置くなら、全体に bg-black/40 程度を敷きます。

明るい動画で白文字がまだ弱いときは、文字に影を付けるよりオーバーレイを濃くする方が読みやすくなります。

最後に、動画の一番明るいコマで止めて見出しを確認してください。ここで読めれば、どの瞬間でも読めます。

動画ヒーローでよくある失敗と直し方

  • poster がなく、読み込み中に黒い四角が表示される

  • muted を付け忘れたうえに音声トラックが残っていて、自動再生がブロックされる

  • 撮影したままの数十 MB の動画を置いている

  • ヒーローの高さが決まっておらず、動画の読み込み後にレイアウトがずれる(min-h で高さを先に確保する)

  • ループのつなぎ目で画面が跳ねる

  • 点滅や激しいフラッシュを含む映像を使っている

YouTube の埋め込みを背景に使う方法もあります。ただ、背景全面には向きません。

プレーヤーの読み込みが重く、操作ボタンや余白も出やすいためです。

短いループ動画を自分で用意する方が、見た目も表示速度も整えやすくなります。

完成した動画ヒーローをコピーして使う方法

ヒーローで絞り込んだ DesignLayer のコンポーネント一覧
ヒーローで絞り込んだ DesignLayer のコンポーネント一覧

ここまでの内容で、背景動画のヒーローは作れます。

ただ、次の点まで整えるには、試行錯誤の時間がかかります。

  • 映像の切り替わりと見出しの入場タイミング

  • 文字の大きさと余白のバランス

DesignLayer は、人が組んだ React + Tailwind CSS のモーション付きセクションを、ブラウザでライブプレビューしてからコピーできるカタログです。

ヒーローの動きを実際に見て選び、映像の URL と見出しだけを差し替えて使えます。

閲覧は無料で、カード登録も要りません。https://design-layer.com/ja/components

Copy for Cursor を押すと、統合の指示・ライブプレビューの URL・本体の TSX・npm 依存がまとめてコピーされます。Cursor や Claude にそのまま渡せます。

無料アカウントでは、無料サンプル10個を無料アカウントで回数制限なくコピーでき、動画プロンプトは月1回です。Free では MCP に接続できません。カタログ全体は30日ビルドパス($19の1回払い、自動更新なし)、Lifetime Access(先着100名の$79の1回払い)、Plus(月額 $9、いつでも解約可)です。公開前に、音が出る設定になっていないかだけは必ず確認してください。

見出しの入場アニメーションを Motion(旧 Framer Motion)で付けたい場合は、https://design-layer.com/ja/articles/nextjs-framer-motion-guide を参考にしてください。

背景動画のヒーローについてよくある質問

  • 背景全面には向きません。プレーヤーの読み込みが重く、操作ボタンや黒い余白が出やすいためです。

    背景用には、自分で書き出した短い MP4 や WebM を使います。説明用の長い動画を見せたい場合は、ヒーローの下に別のセクションとして埋め込みます。

まとめ:Next.js で背景動画ヒーローを作る手順

  • 背景動画は、映像が商品の魅力になるサイトで使う。SaaS などは静止画ヒーローも検討する

  • 動画のタグに5つの指定(無音・自動再生・繰り返し・全画面にしない・再生前の静止画)をそろえる。自動再生に欠かせないのは無音と全画面にしない指定

  • 動画は 10 秒前後・横 1280px 程度・音声なしに圧縮し、静止画も軽くする

  • スマホ・省データ・動きを減らす設定では動画を読み込まず、静止画にする

  • オーバーレイで見出しを読めるようにし、一時停止ボタンを置く

まずは手元の素材を ffmpeg で圧縮し、基本形の VideoHero に入れて表示を確かめてみてください。

ヒーロー全体の動きまで整った形から始めたい場合は、DesignLayer のカタログでライブプレビューしてから選べます。https://design-layer.com/ja/components

関連ガイド