HTML Media Elements Table
| Piece | What it does | Field note |
|---|---|---|
<video> / <audio> | Embed media with a native UI option | Always add playsinline or iOS plays fullscreen |
<source> | Multiple format candidates | Browser takes the FIRST it understands - list modern codecs first |
<track> | Subtitles and captions | kind=captions; a default track must exist for accessibility |
controls | Show the native UI | Without it the element is invisible and only script-driven |
muted + autoplay | The only autoplay combo browsers allow | Unmuted autoplay is blocked by policy everywhere |
playsinline | Play inside the page box | Without it iOS hijacks the screen |
poster | Preview frame before play | Also hides the first-frame flash while metadata loads |
preload="metadata" | Fetch only duration and dimensions | none = nothing, auto = browser decides - metadata is the polite default |
loop | Restart automatically | Combine with muted for ambient backgrounds |
play() / pause() | Script control | play() returns a promise - autoplay refusal rejects it, catch it |
currentTime / duration | Seek and total length | duration is NaN until loadedmetadata fires |
volume / muted property | Level and mute state | Volume is 0.0-1.0, not percent |
Native HTML media is more capable than its reputation: one <video> element covers formats, captions, previews, and script control - the plugins died a decade ago. The table below is the working twelve: the elements, the attributes that decide playback behavior, and the script surface that everything else builds on.
Bottom line: the autoplay policy is the landscape everything else adapts to. Browsers allow automatic playback only when the media is muted (or after the user has interacted with the page), which is why every background-video pattern on the web is the same trio: autoplay + muted + playsinline. Unmuted autoplay is blocked by every major browser, and the muted trio is not a workaround - it is the supported path.
The honest part: iOS Safari is its own chapter. Without playsinline, a playing video takes over the whole screen; preload is advisory, not binding; and duration stays NaN until loadedmetadata fires. Testing on one engine is testing on half the market - the table's notes carry the per-engine landmines.
How to use
- Compose from the top: the video or audio element, one or more source children, a captions track, the behavior attributes.
- Order source elements modern-codec-first - the browser takes the first one it can play and never looks back.
- Control from script via the API rows: play() (catch its rejection - it is the autoplay policy speaking), currentTime for seeking, volume between 0 and 1.
Frequently asked questions
Why won't my video autoplay?
Because it has sound. Browser autoplay policy allows automatic playback only for muted media, or after the user has interacted with the page (a click anywhere counts). The fix for background and ambient video: autoplay muted playsinline loop together. For content video, the answer is not to fight the policy - show a poster frame with your own play button, and the click both satisfies the interaction requirement and is what the user wanted anyway.
What does the preload attribute actually control?
How eagerly the browser fetches the media before play: none downloads nothing until play, metadata fetches just enough for duration and dimensions, auto lets the browser decide (usually a chunk). The catch in the name: it is a hint, not a command - iOS Safari historically ignores it, and browsers on metered connections downgrade it themselves. preload="metadata" is the polite default: it makes duration and poster work without pulling megabytes.
How do I add subtitles or captions to a video?
With a <track kind="captions" src="subtitles.vtt" srclang="en" label="English"> child inside the video element - WebVTT format, one track per language, and exactly one with the default attribute for the starting language. Captions are not optional polish: they serve deaf viewers, sound-off social feeds, and SEO in one move. The common bug is a track that loads but stays empty - the VTT file needs the WEBVTT header as its first line, and the server needs a text/vtt content type.
Why does my video play fullscreen on iPhones?
Missing playsinline. Without it, iOS Safari plays video in fullscreen theater mode by default - the page disappears. playsinline keeps playback inside the layout box, which is what every embedded and background video needs. The complete quiet-play recipe is autoplay muted loop playsinline; drop any one of the four and some device class will behave differently than your desktop test did.