Problem Solved

HTML · video & audio

Home › Courses › HTML › Problems › Video & audio
📄 Concept · 4 min read

Video and audio elements.
Controls, sources, captions.

<video> and <audio> embed media without a plugin. The element itself is simple — a src and controls and you have a player. But the details matter: multiple sources for browser compatibility, captions for accessibility, muted autoplay for browser policy, and preload for performance. This page covers the full picture.

Short answer: Use <video src="clip.mp4" controls></video>. Add width, height, poster. For multiple formats, use <source> elements inside. For captions, add <track> with a .vtt file. Autoplay requires muted — the browser blocks sound autoplay. For below-fold videos, use loading="lazy" + preload="none" + a poster.

✅ Basic video

The minimum for a working player.

basic-video.html
<video
src="clip.mp4"
controls
width="640"
height="360"
poster="thumb.jpg">
Your browser doesn't support video.
</video>
controls → play/pause, volume, seek, fullscreen
width/height → layout space reserved (no shift)
poster → image shown before playback
fallback → text for browsers without video

⚠️ Always include width and height.
Without them, the page shifts when the video loads.

✅ Multiple sources

Different formats for different browsers.

multiple-sources.html
<video controls width="640" height="360" poster="thumb.jpg">
<source src="clip.webm" type="video/webm">
<source src="clip.mp4" type="video/mp4">
Your browser doesn't support video.
</video>
Browsers check sources in order:

1. clip.webm (video/webm) → modern browsers
2. clip.mp4 (video/mp4) → fallback for all

Chrome, Firefox, Edge → WebM (smaller file)
Safari, older browsers → MP4 (universal)

⚠️ Order matters: put the smallest/modern format first.
The browser stops at the first source it can play.

⚠️ The type attribute is optional but recommended.
It lets the browser skip a source without downloading
a byte — faster than downloading to find out it can't play.

✅ Captions with track

Required for accessibility. Not optional.

video-with-captions.html
<video controls width="640" height="360" poster="thumb.jpg">
<source src="clip.mp4" type="video/mp4">

<track
kind="subtitles"
src="captions-en.vtt"
srclang="en"
label="English"
default>

<track
kind="subtitles"
src="captions-es.vtt"
srclang="es"
label="Español">

Your browser doesn't support video.
</video>
// captions-en.vtt — WebVTT format
WEBVTT

00:00:00.000 --> 00:00:03.000
Welcome to the product demo.

00:00:03.000 --> 00:00:07.500
Today we're showing the new dashboard.

00:00:07.500 --> 00:00:12.000
Let's start with the overview panel.

⚠️ kind="captions" → includes sound effects
kind="subtitles" → dialogue translation
kind="descriptions" → audio description for blind users

⚠️ default shows captions enabled by default.
Only one track should have default.

✅ Autoplay — muted is required

Browsers block unmuted autoplay.

autoplay-video.html
<!-- ✅ Autoplay works (muted) -->
<video
src="clip.mp4"
autoplay muted loop playsinline
width="640" height="360">
</video>

<!-- ❌ Autoplay blocked (unmuted) -->
<video src="clip.mp4" autoplay controls></video>
Browsers block autoplay with sound. That's the rule.

muted → allows autoplay
playsinline → iOS: play in place, not fullscreen
loop → replays when done

For sound: wait for user gesture, then call video.play():
button.addEventListener('click', () => {
video.muted = false;
video.play();
});

⚠️ Even muted autoplay can be blocked by iOS Low Power Mode.

✅ Audio element

Same pattern, no visual content.

audio.html
<audio controls>
<source src="podcast.webm" type="audio/webm">
<source src="podcast.mp3" type="audio/mpeg">
Your browser doesn't support audio.
</audio>
audio has the same attributes as video:
controls, autoplay, loop, muted, preload, src

No width/height (no visual content).
No poster (no video frame).

⚠️ Add captions via track for deaf/hard-of-hearing users.
Audio without transcript = inaccessible.

⚠️ Prefer a transcript page for long podcasts.
Captions inside the audio player are harder to follow.

Don't autoplay with sound. Browsers block it — Chrome, Safari, Firefox, and Edge all prevent autoplay with audio unless the user has interacted with the page. If you try, the video shows the first frame but never plays. The fix is not to disable the policy or use JavaScript tricks — those get patched. Use muted autoplay, or wait for a user click before unmuting. Muted autoplay is the supported pattern; sound autoplay is not.

⚠️ Common mistakes

The video/audio mistakes that cost real time.

1. Autoplay without muted

The browser blocks it. Fix: autoplay muted, or wait for user gesture.

2. Forgetting playsinline

iOS opens fullscreen on autoplay. Fix: add playsinline.

3. No width/height

Page shifts when video loads. Fix: set dimensions — same as images.

4. No poster image

Black or blank first frame. Fix: add a poster.

5. Single format only

Some browsers can't play it. Fix: <source> elements for MP4 + WebM.

6. No captions

WCAG failure. Fix: <track> with a .vtt file.

7. Preload="auto" on below-fold video

Downloads the whole file on page load. Fix: preload="none" + loading="lazy".

8. Large MP4 without compression

A 50 MB MP4 for a 10-second clip. Fix: compress with FFmpeg, offer multiple resolutions.

❓ Frequently asked

How do I embed a video in HTML?

Use the video element with a src attribute and the controls attribute for the play/pause UI. Add width and height for layout stability, and a poster image for the first frame. Example: video src='clip.mp4' controls width='640' height='360' poster='thumb.jpg'. For multiple formats, use source elements inside the video — the browser picks the first one it can play. Always include fallback text between the tags for very old browsers.

Why does autoplay not work on my video?

Modern browsers block autoplay with sound. Autoplay only works if the video is muted OR the user has interacted with the page. Fix: add the muted attribute alongside autoplay. The browser treats muted videos as non-intrusive and allows autoplay. If you need sound, you must wait for a user gesture (click, tap, key press) and call video.play() in that event handler. iOS Safari is strictest — even muted autoplay may require playsinline and may fail on low-power mode.

What is the poster attribute on video?

The poster attribute is the image shown before the video starts playing. It replaces the black or blank frame that would otherwise display. Use it for: (1) a thumbnail that previews the content, (2) a branded splash image, (3) the video's own first frame as a still. Without poster, the browser shows either black or the first frame (browser-dependent). For marketing pages, a poster is a design win — it looks intentional instead of broken.

How do I add captions to a video?

Add a track element inside the video, with kind='subtitles' (or captions/descriptions), src pointing to a WebVTT file, srclang for the language, and label for the name shown in the UI. The video needs controls for users to toggle captions. WebVTT files end in .vtt and contain timestamped text. Captions are required by WCAG 1.2.2 for prerecorded video with audio. They are not optional for accessibility — they are the standard.

What are the supported video and audio formats?

Video: MP4 (H.264) is universal, WebM (VP9) is modern and smaller, Ogg is rare. Audio: MP3 is universal, Ogg and WAV are alternatives, AAC inside MP4 is common. Use source elements to provide multiple formats — MP4 first for compatibility, WebM second for size. The browser picks the first format it can play. For maximum reach, always include MP4. For modern browsers, include WebM for smaller files. Do not use a single format and hope it works.

Does video support lazy loading?

Yes. Add loading='lazy' to the video element — but only for videos below the fold. For videos above the fold, lazy loading delays playback and hurts LCP. For large videos below the fold, also consider preload='none' so the browser doesn't download the file until the user clicks play. Combine with a poster image for a good UX. The combination loading='lazy' + preload='none' + poster means the user sees a static image until they interact.

🔗 Related

← All HTML problems
Problem solved · HTML