Basic <video>
The <video> element embeds a video player directly in the page.
Like <audio>, it can hold one or more <source>
children that list the video file in different formats — the browser picks the first
one it can play. Three attributes are worth setting on almost every video element:
controls— renders the browser's native playback UI (play/pause, seek bar, volume, fullscreen). Without it, the element renders a black rectangle with no way for the user to interact.poster— a URL pointing to an image displayed in the video viewport before the user presses play (or while the video is loading). Without a poster, the browser shows the very first frame of the video, which can be a blank or partially decoded frame. A good poster is a representative screenshot or a branded thumbnail.widthandheight— pixel dimensions that the browser reserves in the layout before the video file arrives. Omitting them causes a layout shift when the file's intrinsic size is discovered, which hurts Cumulative Layout Shift (CLS) scores and feels jarring to the user. The CSS rule.tutorial-content video { max-width: 100%; height: auto; }on this page then scales the video down responsively without distorting it.
The fallback text is shown only if the browser does not recognise
<video> at all — essentially never in a modern browser, but it is
good defensive practice. A more helpful fallback can include a direct download link.
Attributes
<video> shares many attributes with <audio> and
adds a few video-specific ones. Here is a concise reference, followed by the one
rule that trips up almost every developer who first encounters the autoplay API.
| Attribute | Type | What it does |
|---|---|---|
controls |
boolean | Shows the browser's native play/pause, seek, volume, and fullscreen controls. |
poster |
URL | Image shown in the video area before playback starts. Prevents a blank or partially loaded first frame. |
width / height |
integer (px) | Reserves layout space before the file loads, preventing Cumulative Layout Shift. |
autoplay |
boolean | Starts playback immediately on load. Blocked by browsers unless muted is also set. |
muted |
boolean | Starts the video with the audio track silenced. Required for autoplay to work in all browsers. |
loop |
boolean | Restarts playback from the beginning when the video ends. |
playsinline |
boolean | On iOS/iPadOS, plays the video inline within the page instead of launching the system full-screen player. Essential for decorative or background videos on mobile. |
preload |
none | metadata | auto |
Hints how much data to fetch before the user presses play. metadata is a good default — it downloads only the duration and dimensions, not the full video. |
The autoplay rule
Every modern browser enforces an autoplay policy: media with an
audible track cannot play without a user gesture (click, tap, or key press). The
policy protects visitors from unexpected noise when a page loads. If you set
autoplay alone on a video that has audio, the browser silently ignores
it — the video just sits there waiting.
Rule: autoplay must always be paired with
muted. The only acceptable autoplay pattern is
autoplay muted loop playsinline, used for decorative, background-style
clips where sound is not the point.
The demo below shows that exact pattern — a short clip that starts playing silently the moment it is loaded, loops seamlessly, and plays inline on mobile. This is appropriate for a background video or a short decorative animation. It is not appropriate when the video carries information the user needs to hear.
Notice there are no playback controls on this version — that is intentional for a
background clip. The user is not expected to interact with it. If you want users to
be able to pause or unmute, add controls.
Multiple sources and fallback
No single video format is universally supported across every browser and operating
system, so it is best practice to offer the same video encoded in two formats.
The browser scans the <source> list in document order, checks
the type attribute against what it can decode, and uses the first
match. Crucially, the type attribute lets the browser
skip unsupported formats without making a network request for each file
— include it whenever possible.
Recommended source order
List the more efficient or newer format first. WebM with the VP9 or AV1 codec typically produces smaller files than MP4/H.264 at the same quality, and all major desktop browsers support it. List MP4 second as the widely compatible fallback, including Safari on older iOS.
The fallback paragraph is only rendered when the browser does not understand
<video> at all. A download link inside the fallback is a
courteous last resort. For a full explanation of format trade-offs — H.264, VP9,
AV1, HEVC, and when to use each — see
Tutorial 04: Formats and Codecs.
Video vs. animated GIF
A common pattern on the web is using an animated GIF for short, looping, silent
clips — think reaction memes, UI demos, or product micro-animations. GIF is a poor
choice for this: it has no compression for motion content, supports only 256 colours,
and a two-second animation can easily reach several megabytes. A muted, looping
<video> encoding the same clip as WebM or MP4 is typically
5 to 20 times smaller because modern video codecs exploit
inter-frame similarity rather than storing every frame independently.
The correct drop-in replacement for an animated GIF is:
Note that the <img> element has an alt attribute
describing the animation; the equivalent <video> has no built-in
alt text mechanism. If the clip conveys meaning that a screen reader user should
understand, add a visible caption below it or use aria-label on the
element. For purely decorative clips, no description is necessary.
For a deep dive into file size optimisation strategies across all media types, see Images Tutorial 11: Optimisation and Delivery.