video and audio
controls, autoplay rules, muted and playsinline, posters, multiple sources — the markup that decides whether your video plays at all.
You drop a <video> in your page. It does not play. You add autoplay. It still does not play. You add muted. Now it plays — but only on desktop, not on iPhone. You add playsinline. Now it plays everywhere except the network is too slow and shows a white box. You add a poster. Done.
This lesson is the choreography that turns a <video> tag into a video that actually plays for every user. Same story for <audio>, with fewer attributes.
video basics
The minimal embed: a single source file, with the user-controllable browser controls.
<video src="bake.mp4" controls width="800" height="450" poster="bake-still.jpg"> Your browser does not support the video tag. </video>
The text inside the <video> is a fallback for ancient browsers that do not understand the tag — vanishingly few in 2026, but the convention sticks.
The attributes that earn their place:
src— the video file URL. (Or use multiple<source>children — covered later.)controls— show the browser's built-in play/pause/scrubber/volume UI. Without it, the video loads but you cannot start it.widthandheight— pixel dimensions. Reserve space (same CLS argument as<img>from lesson 1).poster— a still image to show until the user presses play. The first frame of the video is the default if you skip it; a deliberate poster is almost always better.preload—"none"(don't pre-fetch),"metadata"(fetch enough to know duration and dimensions),"auto"(fetch as much as possible). Default is browser-dependent."metadata"is a polite default for non-critical videos.
<video src="kneading.mp4" controls preload="metadata" poster="kneading-still.jpg" width="800" height="450"> </video>
That five-attribute set covers most embedded videos: controls work, the page reserves space, the poster shows immediately, the bytes don't load until the user is interested.
Why autoplay won't
autoplay tells the browser to start playing as soon as the video is ready. In practice, browsers refuse to honor autoplay on videos with sound — too many bad-actor sites used it to hijack attention.
The two rules to know:
- Autoplay works only when the video is
muted. No exceptions. Even on desktop. Even on a user gesture. - Some browsers also require
playsinline(covered below) for the autoplay to not become a fullscreen takeover.
<!-- An auto-playing decorative loop on the homepage --> <video src="bg-loop.mp4" autoplay muted loop playsinline width="1920" height="1080"> </video>
The four attributes you need for a decorative auto-playing video: autoplay, muted, loop, playsinline. Drop any one of these and the video will not play on at least one browser.
If your video has audio that matters — a tutorial, a testimonial — do not autoplay it. Show a poster, let the user click play. Forcing audio playback is the surest way to lose them.
Autoplay with sound is blocked by every modern browser unless the user has previously interacted with the site or given an explicit autoplay permission. Build for the assumption that autoplay only works with muted — design around that, do not fight it.
<video src="bake.mp4" autoplay> to your homepage hero. The video has no audio track. On Chrome desktop, does it autoplay?audio
<audio> is the same idea, simpler. No video frame, no poster, no playsinline. Just a play/pause/scrubber strip.
<audio src="podcast.mp3" controls preload="none"> Your browser does not support the audio tag. </audio>
The attributes mirror <video>: src, controls, preload, autoplay (subject to the same muted-only rule), loop. There is no poster — visual rendering is the controls strip and nothing else.
For longer audio (podcasts, music), preload="none" saves bandwidth — fetch only when the user clicks play.
Multiple sources and formats
Like <picture> for images, <video> and <audio> accept multiple <source> children — the browser picks the first format it can decode.
<video controls width="800" height="450" poster="cover.jpg"> <source src="bake.av1.webm" type="video/webm; codecs=av01.0.05M.08"> <source src="bake.h265.mp4" type="video/mp4; codecs=hvc1"> <source src="bake.h264.mp4" type="video/mp4; codecs=avc1"> </video>
Reading: AV1 first (the smallest, supported by recent browsers), HEVC next, H.264 last (the universal floor — every device decodes it).
The type attribute carries both the container (video/mp4, video/webm) and the codec (codecs="..."). The browser uses the type to decide before fetching, the same way <picture> does for images.
If you only have one format ready, set src directly on the <video> and skip the <source> chain. Most teams ship MP4-with-H.264 as the universal floor and add modern codecs as a <source> chain when the encoding pipeline supports it.
<audio controls preload="none"> <source src="podcast.opus" type="audio/ogg; codecs=opus"> <source src="podcast.mp3" type="audio/mpeg"> </audio>
Same pattern for audio: try Opus (small and high-quality) first, fall back to MP3 (universal).
playsinline and mobile
By default, mobile Safari plays inline videos fullscreen. The user clicks play; the video takes over the screen. That is fine for some videos and terrible for others — a small product video does not need a fullscreen takeover.
playsinline tells the browser "play me right here in the page, do not go fullscreen". It is the magic attribute for any video that is part of the layout, not a media-watching experience.
<video src="product-loop.mp4" autoplay muted loop playsinline width="600" height="400"> </video>
Without playsinline, that decorative loop might fullscreen on iPhone. With it, the video stays in its layout box. Always include playsinline on autoplaying or background videos.
For full-screen-intended videos (a tutorial, a film), leave playsinline off — the fullscreen takeover may be exactly what the user wants.
The four-attribute autoplay incantation — autoplay muted loop playsinline — is the standard for decorative background videos. Memorize it. Skip any one and the video breaks on at least one browser.
<video src="tour.mp4" controls preload="auto"> to a long page with 12 videos below the fold. What happens on first load?