For your own files use the video element: <video src="clip.mp4" controls playsinline preload="metadata" poster="still.jpg">. Autoplay works only together with muted. For YouTube or Vimeo use an iframe with loading="lazy", a title and aspect-ratio: 16 / 9 for responsive sizing. The builder below writes either one for you.
| Attribute | Effect |
|---|---|
| controls | Shows the browser's play, volume and full screen controls |
| autoplay muted | Starts playing on load; most browsers require muted for this |
| playsinline | Plays inside the page on iPhone instead of full screen |
| loop | Restarts at the end |
| poster | Image shown before playback starts |
| preload | none, metadata or auto: how much to fetch early |
Updated
Choose a source in the embed builder, flip the toggles and copy markup that already includes the attributes people forget: playsinline for iPhones, a title on the iframe for screen readers, privacy-enhanced YouTube and a 16:9 box that never squashes. The sections below cover captions, background videos, sandboxing and a click-to-load facade that keeps heavy players off the first paint.
The browser plays the first source it supports, so list the smaller, newer format first. The paragraph inside only shows in browsers with no video support at all.
<video controls playsinline preload="metadata"
width="1280" height="720" poster="/media/tour-poster.jpg">
<source src="/media/tour.webm" type="video/webm">
<source src="/media/tour.mp4" type="video/mp4">
<p>Your browser cannot play this video. <a href="/media/tour.mp4">Download it</a>.</p>
</video>kind="captions" includes sound effects and speaker names; kind="subtitles" is for translation. default turns the first one on.
<video controls playsinline src="/media/tour.mp4">
<track kind="captions" src="/media/tour.en.vtt" srclang="en" label="English" default>
<track kind="subtitles" src="/media/tour.fr.vtt" srclang="fr" label="Français">
</video>The file starts with WEBVTT, then cues of start and end time followed by text. Serve it with the text/vtt content type.
WEBVTT
00:00:00.000 --> 00:00:03.500
Welcome to the studio.
00:00:03.500 --> 00:00:07.000
[kettle whistles]
This is where every order is packed by hand.The poster and the hero background share one image, so the hero looks right before the video loads and when it is hidden for reduced motion.
<section class="hero">
<video class="hero-video" autoplay muted loop playsinline
poster="/media/hero.jpg" preload="auto" aria-hidden="true">
<source src="/media/hero.webm" type="video/webm">
<source src="/media/hero.mp4" type="video/mp4">
</video>
<div class="hero-text">
<h1>Handmade ceramics</h1>
<a href="/shop">Shop the collection</a>
</div>
</section>
<style>
.hero { position: relative; min-height: 70vh; display: grid; place-items: center;
background: #111 url("/media/hero.jpg") center / cover; color: #fff; }
.hero-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.hero::after { content: ""; position: absolute; inset: 0; background: rgb(0 0 0 / .45); }
.hero-text { position: relative; z-index: 1; text-align: center; }
@media (prefers-reduced-motion: reduce) { .hero-video { display: none; } }
</style>| Attribute | Example | Purpose |
|---|---|---|
| title | title="Store location map" | Accessible name for the frame |
| loading | loading="lazy" | Defers off-screen frames until the user scrolls near them |
| sandbox | sandbox="allow-scripts allow-forms" | Restricts what the framed page may do |
| allow | allow="autoplay; fullscreen; picture-in-picture" | Grants browser features to the frame |
| allowfullscreen | allowfullscreen | Lets the player go full screen (older equivalent of allow="fullscreen") |
| referrerpolicy | referrerpolicy="strict-origin-when-cross-origin" | Limits what the embedded site learns about the page URL |
| width / height | width="560" height="315" | Reserves space before load; override with CSS |
aspect-ratio keeps the frame in shape at any width. The nocookie domain is YouTube's privacy-enhanced mode.
<iframe
src="https://www.youtube-nocookie.com/embed/VIDEO_ID"
title="How we glaze our mugs"
loading="lazy"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
style="width: 100%; height: auto; aspect-ratio: 16 / 9; border: 0"></iframe>Only scripts and form submission are allowed back. The frame cannot open popups or navigate your page.
<iframe src="https://widgets.example.com/booking"
title="Book a table"
sandbox="allow-scripts allow-forms"
loading="lazy"
style="width: 100%; height: 520px; border: 0"></iframe>Until someone clicks, the page loads one thumbnail image instead of the full player. The button keeps it keyboard accessible.
<button class="yt" data-id="VIDEO_ID" aria-label="Play: How we glaze our mugs"
style="position: relative; width: 100%; aspect-ratio: 16 / 9; border: 0; padding: 0; cursor: pointer;
background: #000 url('https://i.ytimg.com/vi/VIDEO_ID/hqdefault.jpg') center / cover">
<span aria-hidden="true" style="font-size: 48px; color: #fff">▶</span>
</button>
<script>
document.querySelectorAll(".yt").forEach((btn) => {
btn.addEventListener("click", () => {
const f = document.createElement("iframe");
f.src = "https://www.youtube-nocookie.com/embed/" + btn.dataset.id + "?autoplay=1";
f.title = btn.getAttribute("aria-label").replace("Play: ", "");
f.allow = "autoplay; encrypted-media; picture-in-picture; fullscreen";
f.style.cssText = "width:100%;aspect-ratio:16/9;border:0";
btn.replaceWith(f);
});
});
</script>| Container and codec | Support | Use it for |
|---|---|---|
| MP4, H.264 video, AAC audio | Every current major browser | The safe default and fallback source |
| WebM, VP9 | All current major browsers | Smaller files at similar quality; list before MP4 |
| MP4 or WebM, AV1 | Recent releases of the major browsers; check caniuse | Smallest files, slower to encode |
| Animated GIF | Everywhere | Avoid for anything longer than a second or two; a muted MP4 is far smaller |
Our working targets: 720p or 1080p, no audio, under ten seconds, and a few megabytes at most. -an drops the audio, -movflags +faststart lets playback begin before the file finishes downloading.
ffmpeg -i hero-raw.mov -vf "scale=-2:720" -an -c:v libx264 -crf 26 -preset slow -movflags +faststart hero.mp4
ffmpeg -i hero-raw.mov -vf "scale=-2:720" -an -c:v libvpx-vp9 -crf 34 -b:v 0 hero.webm
A YouTube or Vimeo iframe loads its own scripts, styles and fonts as soon as it renders, before anyone presses play. On a page with several embeds that weight lands on every visitor, most of whom never watch.
A facade shows the thumbnail and a play button, and swaps in the real iframe only on click. Lighthouse lists this pattern under its third-party facades audit. The code below does it in a few lines with no library.
Keep the clip short, silent and compressed, set a poster so something shows at once, and lay text over a dark overlay so contrast does not depend on the frame. Hide the video for readers who ask for reduced motion and let the poster carry the design.
Browsers block autoplay with sound. Add muted alongside autoplay, and playsinline for iPhones. Data saver modes and some user settings can still block it, so design the page to work with the poster image alone.
Remove the fixed width and height styling and give the iframe width: 100%; height: auto; aspect-ratio: 16 / 9. The aspect-ratio property keeps the height in step with the width at every screen size, replacing the old padding-bottom: 56.25% wrapper.
It is YouTube's privacy-enhanced mode. According to YouTube, viewing information is not used to personalise the viewer's browsing until they play the video. The embed works the same way otherwise; swap the domain in the src.
An empty sandbox attribute applies every restriction: no scripts, no forms, no popups, no top navigation and a unique origin. You then add back only what the frame needs with tokens such as allow-scripts or allow-forms. Avoid combining allow-scripts with allow-same-origin for untrusted content.
Write a WebVTT file with timed cues and add <track kind="captions" src="captions.vtt" srclang="en" label="English" default> inside the video element. The browser adds a captions menu to its controls. The file must be served from the same origin or with CORS.
Related: HTML embed code generator, Aspect ratio calculator, HTML images, aspect-ratio and object-fit, Website accessibility checklist.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.