1. Home
  2. Blog
  3. Loops

Website Background Video: Size, Format, Loops and iPhone Autoplay

The specs, the file-size arithmetic and the five attributes that make a hero loop autoplay on iPhone without wrecking your load time.

ASFARI Lab5 min readOctober 2026

A glass browser window on an ink-black ground with a slow coral-lit liquid chrome wave flowing behind it

A good website background video is a short, silent, seamless loop: 6 to 12 seconds, H.264 MP4 (plus an optional WebM), roughly 2 to 4 Mbps, no audio track, with a poster image and the attributes autoplay muted loop playsinline. That autoplays on iPhone, stays under about 5 MB, and paints a poster before the first frame arrives.

Website background video specs at a glance

Setting Our default Why
Length 6–12 s Not repetitive, still light
Resolution 1080p desktop, 720p mobile Overlays hide fine detail anyway
Codec H.264 MP4 + optional VP9/AV1 WebM MP4 plays everywhere; WebM is often smaller
Bitrate 2–4 Mbps Clean for soft motion
Audio None (strip the track) Required for reliable muted autoplay
Frame rate 24 or 30 fps 60 fps adds bytes, not beauty
Poster WebP/JPEG of frame 1, under ~150 KB Shows instantly and counts toward LCP

Working defaults, not a standard: fine detail (spray, film grain) needs more bitrate, fog and gradients less.

Background video size: the arithmetic

File size is just bitrate times duration. Divide megabits by 8 to get megabytes.

Bar chart showing file size of a 10-second background video at 2, 4 and 8 Mbps
File size = bitrate × duration. A 10 s loop is about 2.5 MB at 2 Mbps, 5 MB at 4 Mbps and 10 MB at 8 Mbps.

A 10-second loop at 2 Mbps is 20 megabits, about 2.5 MB. Cut it to 6 seconds at 3 Mbps and you are near 2.25 MB.

Handed a 45 MB hero file? The fix is a shorter loop at a sane bitrate, not a better CDN. For phones we aim for 1.5–3 MB at 720p.

Video also beats GIF by a wide margin: in web.dev's own example, a 3.7 MB GIF became a 551 KB MP4 and a 341 KB WebM.

Make the website background video loop invisible

The last frame must flow into the first, so choose cyclical motion (drifting smoke, a slow turntable) and check the seam before export. Method and seam checks are in how to make a seamless loop video with AI.

Animated demo of a seamless video loop with no visible jump at the seam
A true loop: the end frame lands exactly on the start frame, so the eye never sees the cut.

Background video not playing on iPhone? Check these five things

WebKit's iOS video policy allows autoplay without a tap only when the video is muted or has no audio track, and it plays inline only with playsinline. Most failures are one of these:

  1. Missing muted or playsinline. Both are required. Without playsinline, iPhone tries to go fullscreen.
  2. An audio track that gets unmuted by script. WebKit pauses the video if it gains audio without a user gesture. Strip audio at export.
  3. The element is hidden. Videos with display: none or visibility: hidden, or scrolled out of view, will not autoplay or will pause.
  4. Low Power Mode. iOS can block autoplay entirely in Low Power Mode; WebKit's tracker has a long-running report titled "Low Power mode is disabling video autoplay". You can't override it, so make the poster look good on its own.
  5. No byte-range support on the server. Safari requests video in ranges; most CDNs handle this, some CMS endpoints don't.

The snippet we start from

<section class="hero">
  <video id="hero-video" autoplay muted loop playsinline
         preload="auto" poster="/media/hero-poster.webp"
         aria-hidden="true">
    <source src="/media/hero-loop.webm" type="video/webm">
    <source src="/media/hero-loop.mp4" type="video/mp4">
  </video>
  <button id="hero-toggle" type="button">Pause background video</button>
</section>

<script>
  const v = document.getElementById('hero-video');
  const btn = document.getElementById('hero-toggle');
  const reduce = matchMedia('(prefers-reduced-motion: reduce)');

  function setPaused(paused) {
    paused ? v.pause() : v.play().catch(() => {});
    btn.textContent = paused ? 'Play background video' : 'Pause background video';
  }

  btn.addEventListener('click', () => setPaused(!v.paused));

  if (reduce.matches) {
    setPaused(true);                          // respect the OS setting
  } else {
    v.play().catch(() => setPaused(true));    // e.g. Low Power Mode: poster stays
  }
</script>

Browsers pick the first <source> they support, which is why WebM goes first (web.dev). If you see problems on older iPhones, put the MP4 first.

For the MP4, an export like ffmpeg -i master.mov -an -c:v libx264 -pix_fmt yuv420p -b:v 3M -maxrate 4M -bufsize 6M -movflags +faststart hero-loop.mp4 strips audio (-an), caps the bitrate and moves the index to the front so playback starts before the file finishes downloading.

Performance and accessibility

LCP. Google counts a video's poster load time or first frame, whichever is earlier, as the Largest Contentful Paint candidate. "Good" LCP is 2.5 s or less (web.dev). A small, preloaded poster is the cheapest LCP win on a video hero. For the wider picture of motion and speed, see do animations slow down websites.

Pause control. Under WCAG 2.2 success criterion 2.2.2 (Level A), moving content that starts automatically, lasts more than five seconds and sits alongside other content needs a way to pause, stop or hide it. An infinite hero loop qualifies, so the button in the snippet is not optional.

Reduced motion. Honor prefers-reduced-motion by showing the poster instead. More patterns in our accessible website animation guide.

Hosting. For a 3 MB loop, a plain file on a CDN with long cache headers beats a video platform embed or a page builder's media pipeline.

Questions people ask

Sources

LET’S OPEN A NEW TAB

What are you
thinking?

What’s on your mind?

This prepares an email to lab@asfari.studio. You review and send it from your email app.