Shufaf LogoShufaf
Tutorials··6 min read

How to Use a Video Background in a Next.js Hero Section

Learn how to implement, optimize, and test responsive hero video backgrounds using modern HTML/CSS and Next.js, including accessibility and performance best practices.

How to Use a Video Background in a Next.js Hero Section

Try it directly in Shufaf

No signup required to preview

Try it out →

Implementing a video background in your website's hero section can create an immediate visual impact. However, done incorrectly, it can degrade page performance, destroy mobile user experience, and violate accessibility standards.

This guide covers how to write production-ready video hero code, optimize assets for performance, maintain accessibility, and handle mobile edge cases.


Technical Implementation: Pure HTML & CSS

To create a video background, place a native <video> element behind your foreground content using absolute positioning.

HTML Structure

<section className="hero-container">
  <video
    autoPlay
    muted
    loop
    playsInline
    preload="metadata"
    poster="/images/hero-poster.webp"
    aria-hidden="true"
    className="hero-video"
  >
    <source src="/videos/hero.webm" type="video/webm" />
    <source src="/videos/hero.mp4" type="video/mp4" />
    <!-- Fallback for browsers that don't support the video element -->
    <img src="/images/hero-poster.webp" alt="Background fallback visual" />
  </video>
 
  <div className="hero-overlay"></div>
 
  <div className="hero-content">
    <h1>Automate Your Workflow</h1>
    <p>Build faster with pre-configured pipeline assets.</p>
    <a href="/docs" className="cta-button">Get Started</a>
  </div>
</section>
 

Video Attribute Breakdown

  • autoPlay: Begins playback automatically. Most modern browsers will block unmuted autoplay.
  • muted: Silences audio output. Required for autoPlay to function across mobile and desktop browsers.
  • loop: Replays the video infinitely upon reaching the end.
  • playsInline: Prevents iOS Safari from automatically opening the video in full-screen media player mode on mobile.
  • preload="metadata": Tells the browser to download only video metadata initially, reducing bandwidth consumption during the initial render.
  • poster: Defines a static image shown while the video streams or if video playback fails/is disabled.
  • aria-hidden="true": Hides purely decorative video content from screen readers.

CSS Styling

.hero-container {
  position: relative;
  width: 100%;
  min-height: 80vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
 
.hero-video {
  position: absolute;
  top: 50%;
  left: 50%;
  min-width: 100%;
  min-height: 100%;
  width: auto;
  height: auto;
  transform: translate(-50%, -50%);
  object-fit: cover;
  z-index: 0;
}
 
/* Semi-transparent overlay to guarantee text legibility */
.hero-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 1;
}
 
.hero-content {
  position: relative;
  z-index: 2;
  color: #ffffff;
  text-align: center;
}
 

Next.js Implementation

In a Next.js (App Router or Pages Router) environment, you can encapsulate this logic into a reusable Server Component.

import Image from 'next/image';
 
interface HeroSectionProps {
  title: string;
  subtitle: string;
  videoWebm: string;
  videoMp4: string;
  posterSrc: string;
}
 
export function HeroSection({
  title,
  subtitle,
  videoWebm,
  videoMp4,
  posterSrc,
}: HeroSectionProps) {
  return (
    <section className="relative w-full min-h-[80vh] flex items-center justify-center overflow-hidden">
      {/* Background Video */}
      <video
        autoPlay
        muted
        loop
        playsInline
        preload="metadata"
        poster={posterSrc}
        aria-hidden="true"
        className="absolute top-1/2 left-1/2 min-w-full min-h-full w-auto h-auto -translate-x-1/2 -translate-y-1/2 object-cover z-0"
      >
        <source src={videoWebm} type="video/webm" />
        <source src={videoMp4} type="video/mp4" />
        <Image alt="Hero background fallback" className="object-cover" fill priority src="{posterSrc}"/>
      </video>
 
      {/* Dark overlay for contrast */}
      <div className="absolute inset-0 bg-black/50 z-[1]" />
 
      {/* Content Container */}
      <div className="relative z-[2] text-center text-white px-4 max-w-4xl">
        <h1 className="text-4xl sm:text-6xl font-bold tracking-tight">{title}</h1>
        <p className="mt-4 text-lg sm:text-xl text-gray-200">{subtitle}</p>
      </div>
    </section>
  );
}
 

Accessibility & Motion Preferences

For users sensitive to motion, continuous video loops can trigger vestibular disorders or motion sickness. Respect the user's OS-level accessibility setting using the prefers-reduced-motion media query.

CSS Solution

Hide the video and show a static background image when reduced motion is preferred:

@media (prefers-reduced-motion: reduce) {
  .hero-video {
    display: none;
  }
  
  .hero-container {
    background-image: url('/images/hero-poster.webp');
    background-size: cover;
    background-position: center;
  }
}
 

Contrast and Readability

Never display light text directly over raw video without an explicit contrast layer. Video frames shift continuously, making static text unreadable across varying light levels.

To maintain WCAG AA contrast compliance:

  1. Apply a solid or gradient overlay using rgba() or backdrop-filter.
  2. Apply filter: blur(2px) to the background video to soften visual clutter.

Performance & Optimization Guidelines

Large video files destroy Core Web Vitals, specifically Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS).

Target Video Specifications

  • Format: Supply both WebM (modern, higher compression) and MP4 (universal compatibility).
  • Resolution: Cap video resolution at 1080p (1920x1080). 4K backgrounds consume unnecessary bandwidth.
  • Frame Rate: Export at 24fps or 30fps. 60fps files double the file size without noticeable UI benefits.
  • Audio Track: Strip audio channels completely during export to reduce payload size.
  • Target File Size: Keep the total video size under 5 MB (ideally 1–3 MB).

FFmpeg Compression Command

Run this terminal command to re-encode an MP4 video, strip audio, and optimize it for web streaming:

ffmpeg -i input.mp4 -vcodec libx264 -crf 28 -an -preset slow -movflags +faststart output.mp4
 
  • -an: Removes all audio tracks.
  • -crf 28: Controls quality (higher values mean more compression; 23–28 is ideal for web background videos).
  • -movflags +faststart: Moves metadata to the beginning of the file so video playback begins before full download.

When to Avoid Hero Video Backgrounds

Video backgrounds are not universally suitable. Consider alternative hero designs if:

  • Mobile-First Audience: High data usage and cellular latency can cause video buffering on mobile connections.
  • Data Density: If your hero section requires complex forms, multiple CTAs, or interactive tables, a background video creates excessive visual competition.
  • Low Contrast Branding: Brand identity guidelines with soft pastel typography can be difficult to make readable over moving video layers.

Hero Background Trade-offs

Background StrategyAdvantagesDisadvantages
Static ImageFastest LCP, predictable contrast, zero motion frictionLower visual dynamics
Video BackgroundRich visual narrative, high immediate engagementHigher payload (1–5MB), potential mobile battery/data impact
CSS Gradient / Animated VectorsMinimal payload (< 10KB), hardware acceleratedLimited to geometric or procedural visuals

Rapid Visual Testing with Shufaf

Before coding your video hero layout, you can instantly test video options, background opacity, and blur parameters using the Shufaf Studio Playground.

Instead of tweaking CSS rules and re-deploying local builds:

  1. Drop Your Assets: Drag your product mockups, typography, or UI screenshots into Shufaf Studio.
  2. Attach Video Clips: Test raw MP4/WebM files as live looping backdrops.
  3. Adjust Parameters: Use interactive sliders to dial in optimal Opacity and Blur values to ensure your foreground text remains fully visible before writing any layout code.