Topic 5.3
Audio and Video
In one line
<audio> and <video> play sound and film right in the page; attributes control the player, <source> offers formats in order, and browsers only autoplay when the sound is off.
Think of it like this
A TV in a shop window. It can play on its own only with the sound off, otherwise it would annoy everyone walking past. If you want sound, you walk in and press play yourself. Browsers follow the same rule: video may start by itself only when it is muted.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Media element
<audio>or<video>: an element the browser can play, with a built-in player.- Boolean attribute
- An attribute that is on when written and off when left out, like
mutedorcontrols. - Autoplay
- Starting playback without the user pressing play.
- User gesture
- A real action by the person, such as a click, tap or key press.
- Poster
- A still image shown in a video player before the video starts.
- MIME type
- A standard name for a file format, like
video/mp4oraudio/mpeg. - Codec
- The method used to compress video or audio (H.264, VP9, AV1, AAC, Opus). A browser must support it to play the file.
- Fallback content
- Content inside an element that is shown only by browsers that don't support the element.
- Promise
- A JavaScript object for a result that arrives later: it either succeeds or fails (is rejected).
Step by step
01The smallest player
One element and one attribute. Without controls, a user would see the first frame and have no way to start it.
<video src="intro.mp4" controls width="640" height="360"></video>02Add a poster and choose preload
The poster appears until the video starts, so the box isn't black. preload="metadata" fetches only enough to show the length on the timeline.
<video src="intro.mp4" controls width="640" height="360"
poster="intro-poster.jpg" preload="metadata"></video>03Offer formats in order
Put the smallest modern format first and the one that plays everywhere last. The browser checks type and skips what it can't play, so it never downloads a file it can't use.
The text at the end is for very old browsers and also good practice: it gives a download link.
<video controls width="640" height="360" poster="intro-poster.jpg" preload="metadata">
<source src="intro.av1.mp4" type='video/mp4; codecs="av01.0.05M.08"'>
<source src="intro.webm" type="video/webm">
<source src="intro.mp4" type="video/mp4">
<p>Your browser can't play this video. <a href="intro.mp4">Download it</a>.</p>
</video>04A silent background loop
For a decorative loop (no speech, no information), all four attributes together: it starts at once on every browser because it is muted, repeats forever and stays inline on iPhones.
Remember people who are sensitive to motion: give them a way to pause it, and consider the prefers-reduced-motion media query (CSS course).
<video src="waves.mp4" autoplay muted loop playsinline
width="1280" height="720" aria-hidden="true"></video>05Start with sound from a click
Playback with sound must come from a user gesture. Call play() inside a click handler and handle the promise, because playback can still fail (for example, the file is missing).
const video = document.querySelector("video");
document.querySelector("#play").addEventListener("click", async () => {
try {
video.muted = false;
await video.play();
} catch (err) {
console.log("Could not play:", err.name); // NotAllowedError or NotSupportedError
}
});06Audio works the same way
<audio> has the same attributes (except poster, width, height and playsinline). Without controls it is invisible, so keep controls unless you build your own buttons.
<audio controls preload="none">
<source src="episode-12.opus" type="audio/ogg; codecs=opus">
<source src="episode-12.mp3" type="audio/mpeg">
<a href="episode-12.mp3">Download episode 12 (MP3)</a>
</audio>Try it yourself
- 1
Unmute the first example
Predict: if you remove
mutedfrom the first video, will it still start by itself? The stream has no sound track, but the browser judges by themutedflag. Run it and read the line under the player. - 2
Press play yourself
In the audio example, if the line says "Blocked", press the player's play button. It works now: your click is a user gesture.
- 3
Remove controls
Delete
controlsfrom the first video. The picture still moves (it is muted autoplay), but there's no way to pause it. That's why silent loops still need a pause control for accessibility.
Code & diagrams
There's no video file here: JavaScript paints a canvas and streams it into the player. Use the controls to pause, and try the full-screen button.
Preview
Console
Nothing logged yet.Expected console output
muted: true | loop: true | paused: true
readyState before any media: 0The page tries to play sound without a click. Most browsers block it (NotAllowedError); pressing the play button is a user gesture, so that always works.
Preview
Console
Nothing logged yet.Expected console output
Duration in seconds: 1`canPlayType` answers "" (no), "maybe" or "probably". Unknown types are skipped without downloading, and the fallback text stays hidden because the browser does support video.
Preview
Console
Nothing logged yet.Expected console output
Can play video/x-future-one? ""
Skipped source: video/x-future-one
Skipped source: video/x-future-two
networkState: 3 (NETWORK_NO_SOURCE)
Fallback paragraph visible? falseBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Autoplay with sound
Write <video src="promo.mp4" autoplay></video> (no muted) and call video.play() on page load.
Break #2
Wrong MIME type on the source
List an MP4 file as <source src="intro.mp4" type="video/mpeg4"> (a made-up type).
Myth vs fact
Myth
Fallback text inside <video> shows when the file can't play.
Fact
It shows only in browsers that don't support <video> at all. A failed file fires an error event; you must handle that yourself.
Myth
autoplay makes a video play.
Fact
It is a request. Browsers ignore it for unmuted media until the user interacts with the page, and data-saver modes may ignore it entirely.
Myth
preload="auto" downloads the whole video.
Fact
It is a hint. The browser decides how much to buffer, and mobile browsers often load little or nothing until play.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Chrome's autoplay policy allows unmuted autoplay after a user gesture on the page or when the site's Media Engagement Index (how much this user has watched media there) is high enough. Cross-origin iframes also need
allow="autoplay"from the embedding page (Topic 5.5). - ▸
For long videos, sites use adaptive streaming (HLS or MPEG-DASH): the video is cut into small chunks at several qualities, and JavaScript (Media Source Extensions) switches quality as bandwidth changes. A single MP4 can't adapt.
- ▸
Servers must support HTTP range requests (
Accept-Ranges: bytes, status206 Partial Content) so the browser can seek without downloading everything; it also letspreload="metadata"fetch only the header. (See the System Design course for how CDNs serve this.) - ▸
HTMLMediaElement.canPlayType()returns"probably","maybe"or""; the vague answers exist because a container type alone (likevideo/mp4) doesn't say which codecs are inside.
Remember this
- 1
<video>and<audio>are media elements: the browser downloads the file, decodes it and plays it with its own built-in player. You don't need plugins (the old Flash player is gone). The simplest form is<video src="talk.mp4" controls></video>. The **controls** attribute shows the browser's play button, timeline, volume and full-screen buttons; without it the player has no buttons at all, and only JavaScript can start it. - 2
Other on/off attributes (called boolean attributes: present means on, absent means off): **
mutedstarts with the sound off,loopstarts again at the end,autoplayasks to start playing as soon as possible, andplaysinlineasks iPhones to play inside the page instead of jumping to full screen.poster** (video only) is an image shown before playback starts, like a cover. Always give a videowidthandheighttoo, for the same layout-shift reason as images (Topic 5.2). - 3
Autoplay rules. Browsers block videos that start with sound by themselves. Muted autoplay is allowed everywhere. Unmuted playback needs a user gesture (a click or tap on the page) or, in Chrome, a history of the user watching media on that site. When blocked, JavaScript's
video.play()returns a promise that is rejected with aNotAllowedError. So:autoplay muted playsinlinefor silent background loops; a play button for anything with sound. - 4
**
<source>fallbacks.** Instead of onesrc, you can list several<source src="…" type="…">children. The browser goes down the list and uses the **first one whosetypeit can play**, without downloading the others.typeis a MIME type (a standard label for a file's format), such asvideo/mp4orvideo/webm, optionally with codecs:video/webm; codecs="vp9, opus". Today, MP4 with H.264 video and AAC audio plays everywhere; WebM and AV1 can be smaller. For audio, MP3 and AAC (in.m4a) play everywhere, and Opus is widely supported. - 5
Text placed inside
<video>(after the sources) is fallback content for browsers that don't support the element at all. It is not shown when the browser supports video but can't play your file. That case fires anerrorevent instead; handle it, or always include a format that plays everywhere. - 6
**
preload** hints how much to download before the user presses play:none(nothing),metadata(only duration and size, the usual default) orauto(as much as the browser thinks wise). It's a hint, not an order: phones on mobile data often treat everything asnone.autoplayoverrides it, since the video must load to play.
Explain it without notes
What are the browser's autoplay rules, and how do you design around them?
How does the browser choose between several <source> elements, and why include type?
When is the content inside <video> displayed, and what should you do when a file fails to play?
What do preload values none, metadata and auto mean?
Practice
Write a video player for lesson.mp4 (1280×720) with controls, a poster lesson.jpg, no preloading, and a WebM version lesson.webm offered first.
Write a silent hero background video bg.mp4 that starts by itself, repeats and plays inline on iPhones.
Write JavaScript that starts an <audio id="song"> when a button #play is clicked and logs the error name if it fails.
Trade-offs
- ↔
Self-hosted
<video>gives you full control and no third-party tracking, but you pay for bandwidth and must encode formats yourself; a video platform embed (Topic 5.5) is free to host but adds heavy scripts and its own branding. - ↔
Autoplaying background video is eye-catching but costs data and battery and can distract; a poster image is often enough.
Done when you can
I can add a video or audio player with
controls.I know what
muted,loop,autoplay,playsinline,posterandpreloaddo.I can explain the autoplay rules and handle the
play()promise.I can offer several formats with
<source>and correcttypevalues.I know when fallback content shows and how to detect a failed source.