How to Add a Video Background to a Website Without Killing Page Speed
A video background website looks great in a design mockup and terrible in a Lighthouse report, at least when it is built the lazy way. Drop a 40 MB MP4 into a hero section, hit publish, and you have just traded 1.5 seconds of Largest Contentful Paint for a bit of motion that most mobile users will never see. It does not have to work that way. This is a practical, performance-first tutorial: the exact HTML5 markup, the encoding commands, the poster image strategy, the mobile fallback, the Express server headers, and the measurements that prove the whole thing did not hurt your Core Web Vitals. We will also cover the part most tutorials skip: when a looping video is the wrong tool and a CSS animation or an animated image is smarter. Dynamic Websites: 5 Excellent Examples of Video Backgrounds covers this in more depth. What a video background website really costs Before writing a line of code, put a number on the decision. A hero video is a bandwidth purchase, and you should know the price. Approach Typical weight (10s loop) Risk to LCP Unoptimised 1080p MP4 straight from the camera or stock site 20 MB to 60 MB Severe Properly encoded H.264 MP4 + WebM, 1280px wide, no audio 700 KB to 2 MB Low if deferred Animated GIF 5 MB to 20 MB Severe (blocking image decode) CSS or SVG animation 2 KB to 30 KB None Rule of thumb: the video file should never be the first thing the browser downloads, and it should never exceed roughly 2 MB for a desktop hero. If your creative concept cannot survive that budget, change the concept, not the budget. Step 1: Decide whether you actually need video Most of the sites you find in a “best video background websites” gallery use footage that carries real meaning: a product in motion, a place, a process, people. If your loop is an abstract gradient, drifting particles, or slow-moving smoke, you are paying megabytes for something a few lines of CSS can fake. If the content is… Use Why Real footage: product, location, people, manufacturing HTML5 <video> loop Only video reproduces real-world detail credibly Abstract motion: gradients, blobs, grain, waves CSS animation, canvas or animated SVG Kilobytes instead of megabytes, resolution independent Short 2 to 3 second UI demo Muted MP4 or animated AVIF/WebP Far smaller than GIF at the same quality Anything on a page whose only job is conversion speed Static image Fastest paint, zero autoplay edge cases And one hard rule: never ship a GIF for a background. A silent MP4 or WebM is roughly ten to twenty times smaller for the same visual result, and the browser can decode it on the GPU. Step 2: Cut and prepare the source clip Editing decisions matter more than encoder settings. Before you touch ffmpeg: Keep it between 6 and 12 seconds. Longer loops rarely get watched and multiply file size linearly. Choose low-motion footage. Slow pans, shallow depth of field and static camera positions compress dramatically better than handheld shots with fast movement or falling confetti. Strip the audio track entirely. A background video must be muted to autoplay anyway, so an audio track is pure waste. Make the loop seamless. Cut on a matching frame, or add a short cross-dissolve between the end and the start so the jump is invisible. Design for the overlay. If text sits over the video, pick footage with a calm area, then darken it with a CSS gradient so contrast ratios stay accessible. Check the licence. Free libraries such as Pexels, Pixabay, Coverr and Mixkit are fine for commercial use, but read the terms for logos, faces and trademarks visible in the frame. Step 3: Encode the video properly Two files cover the whole modern browser landscape: an MP4 (H.264) for universal support and a WebM (VP9 or AV1) that is typically 25 to 50 percent smaller where supported. Recommended output targets Setting Desktop hero Tablet / small viewport Width 1600 to 1920 px 1280 px Frame rate 24 to 25 fps 24 fps Audio None None File size ceiling 2 MB 1 MB Pixel format yuv420p yuv420p ffmpeg commands you can copy H.264 MP4, with the moov atom moved to the front so playback can start before the file finishes downloading: ffmpeg -i source.mov -an \ -vf “scale=1600:-2,fps=25” \ -c:v libx264 -profile:v high -pix_fmt yuv420p \ -crf 27 -preset slow -g 50 \ -movflags +faststart \ hero-1600.mp4 VP9 WebM (broad support, good ratio): ffmpeg -i source.mov -an \ -vf “scale=1600:-2,fps=25” \ -c:v libvpx-vp9 -crf 36 -b:v 0 -row-mt 1 \ hero-1600.webm AV1 WebM if your toolchain has SVT-AV1 (smallest files, slower encode): ffmpeg -i source.mov -an \ -vf “scale=1600:-2,fps=25″ \ -c:v libsvtav1 -crf 40 -preset 6 -pix_fmt yuv420p \ hero-1600-av1.webm Raise the CRF value until you see artefacts, then step back one. Because the video sits behind a dark overlay and moving text, you can usually push CRF several points higher than you would for a video the user is meant to study. Generate the poster image from the first frame ffmpeg -i hero-1600.mp4 -ss 00:00:00.5 -frames:v 1 poster.png cwebp -q 72 poster.png -o hero-poster.webp avifenc –min 24 –max 34 poster.png hero-poster.avif Extracting the poster from the encoded video, not from the raw source, guarantees the still frame and the first video frame match. No flash, no colour shift when playback starts. Step 4: The HTML5 markup Every attribute below is there for a reason. <section class=”hero”> <video class=”hero__video” poster=”/media/hero-poster.avif” muted loop playsinline preload=”none” disablepictureinpicture aria-hidden=”true” tabindex=”-1″> <source data-src=”/media/hero-1600.webm” type=”video/webm”> <source data-src=”/media/hero-1600.mp4″ type=”video/mp4″> </video> <div class=”hero__overlay”></div> <div class=”hero__content”> <h1>Ship your Express app faster</h1> <p>Minimal, unopinionated, production ready.</p> <a class=”btn” href=”/get-started”>Get started</a> </div> </section> What each attribute does muted: mandatory. Chrome, Safari and Firefox all block autoplay with sound. playsinline: prevents iOS from opening the video full screen. Without it, your background becomes a takeover on iPhone. loop: continuous playback, no manual restart logic. preload=”none”: the browser fetches nothing until
How to Add a Video Background to a Website Without Killing Page Speed Read More »









