Lesson 11 of 12

HTML Audio and Video

Not long ago, playing a video on a web page needed a browser plug-in. Today HTML audio and video work out of the box: two built-in elements, <audio> and <video>, give you a working media player with a single line of markup. In this lesson you will learn how to use them, which file formats to provide, and how to make media accessible. It continues from HTML Semantic Elements and uses the same path rules as HTML Images.

The audio element

The simplest audio player looks like this: <audio src="sounds/temple-bells.mp3" controls></audio>. The controls attribute is a boolean attribute that shows the browser’s play button, timeline and volume control. Without it, the audio element is invisible and can only be played by JavaScript.

The Try it editor cannot load sound files, so the example below uses a short script to create a one-second tone and give it to the player. You do not need to understand the script yet – focus on the <audio> element.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Audio player</title>
</head>
<body>
  <h1>Notification sound</h1>
  <audio id="player" controls>
    Your browser does not support the audio element.
  </audio>
  <p>Press play to hear a one-second tone.</p>

  <script>
    // Builds a tiny WAV file in memory so this demo needs no external file.
    const rate = 8000, samples = rate;
    const bytes = new Uint8Array(44 + samples * 2);
    const view = new DataView(bytes.buffer);
    const text = (pos, str) => [...str].forEach((c, i) => view.setUint8(pos + i, c.charCodeAt(0)));
    text(0, 'RIFF'); view.setUint32(4, 36 + samples * 2, true); text(8, 'WAVEfmt ');
    view.setUint32(16, 16, true); view.setUint16(20, 1, true); view.setUint16(22, 1, true);
    view.setUint32(24, rate, true); view.setUint32(28, rate * 2, true);
    view.setUint16(32, 2, true); view.setUint16(34, 16, true);
    text(36, 'data'); view.setUint32(40, samples * 2, true);
    for (let i = 0; i < samples; i++) {
      const fade = 1 - i / samples;
      view.setInt16(44 + i * 2, Math.sin(2 * Math.PI * 440 * i / rate) * 8000 * fade, true);
    }
    let binary = '';
    bytes.forEach(b => binary += String.fromCharCode(b));
    document.getElementById('player').src = 'data:audio/wav;base64,' + btoa(binary);
  </script>
</body>
</html>

Any text placed between the opening and closing tags is fallback content. It is only shown by very old browsers that do not understand the element, so keep it short – a sentence and perhaps a download link.

The video element

Video works the same way, with a few extra attributes:

AttributeWhat it does
controlsShows the built-in player controls. Include it unless you build your own.
width / heightReserve space, like with images, to avoid layout shift.
posterAn image shown before the video starts playing.
preloadA hint: none, metadata (just duration and size) or auto. metadata is a sensible choice for most pages.
loopStarts again from the beginning when the video ends.
mutedStarts with the sound off.
autoplayTries to start playing as soon as possible – see the warning below.
playsinlinePlays inside the page on iPhones instead of switching to full screen.

Offering HTML audio and video in more than one format

Instead of a single src, you can list several <source> elements. The browser checks them in order and plays the first one it supports. The type attribute lets it skip unsupported files without downloading them.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Video player</title>
  <style>
    video { max-width: 100%; height: auto; background: #000; }
  </style>
</head>
<body>
  <h1>Train journey</h1>
  <video controls width="480" height="270" preload="metadata"
         poster="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='480'%20height='270'%3E%3Crect%20width='100%25'%20height='100%25'%20fill='%231d3557'/%3E%3Ctext%20x='50%25'%20y='52%25'%20font-family='sans-serif'%20font-size='26'%20text-anchor='middle'%20fill='white'%3EPoster:%20Chennai%20Central%3C/text%3E%3C/svg%3E">
    <source src="media/chennai-central.webm" type="video/webm">
    <source src="media/chennai-central.mp4" type="video/mp4">
    <p>Your browser cannot play this video.
       <a href="media/chennai-central.mp4">Download the video</a> instead.</p>
  </video>
  <p>There is no real video file in this editor, so you only see the poster image.
     On your own site, point the sources at your video files.</p>
</body>
</html>
FormatNotes
MP4 (H.264 video, AAC audio)Plays in every modern browser – the safest single choice.
WebM (VP9 or AV1 video, Opus audio)Open formats, often smaller files; list it first if you have it.
MP3Universal choice for audio.
AAC / OpusEfficient audio formats with wide modern support.

Autoplay: use it carefully

Sound that starts on its own is one of the most disliked things on the web, and it is a real accessibility problem: it can drown out a screen reader. For this reason, browsers block autoplay with sound until the user has interacted with the site. Autoplay is generally allowed only when the media is muted.

Watch out: If you need a silent background video, use autoplay muted loop playsinline together and keep controls or another visible way to pause it. Moving content that plays for more than five seconds must be pausable to meet WCAG.

Captions, subtitles and transcripts

People who are deaf or hard of hearing, people watching in a noisy train, and people learning a language all rely on captions. Add them with the <track> element, which points to a WebVTT (.vtt) text file containing timed text.

<video controls width="640" height="360">
  <source src="media/kolam-tutorial.mp4" type="video/mp4">
  <track src="media/kolam-tutorial.en.vtt" kind="captions"
         srclang="en" label="English" default>
  <track src="media/kolam-tutorial.ta.vtt" kind="subtitles"
         srclang="ta" label="தமிழ்">
</video>

A WebVTT file is plain text. It starts with the word WEBVTT, followed by cues: a time range such as 00:00:01.000 --> 00:00:04.000 and the text to show. Use kind="captions" when the text includes sounds as well as speech, and kind="subtitles" for translations. Note that track files must come from the same site as the page unless the server allows cross-origin requests.

For audio-only content such as podcasts, provide a written transcript on the page. Transcripts help users who cannot hear, and they also give search engines text to index.

Embedding videos from other sites

Video hosting services usually give you an <iframe> embed code. An iframe displays another web page inside yours. Always add a title attribute describing the content, such as title="Video: How to draw a kolam", so screen reader users know what the frame contains, and consider loading="lazy" for embeds further down the page.

HTML audio and video players can also be controlled with JavaScript, for example to build custom play buttons – the techniques are in JavaScript Events. In the final lesson of this track, HTML Head, Meta Tags and SEO, you will return to the <head> and prepare your pages for search engines and social sharing.

Further reading

Key takeaways

  • <audio> and <video> embed media; add controls to show the player.
  • List several <source> elements with type so each browser picks a format it supports; MP4 is the safest single choice.
  • Use poster, width, height and preload="metadata" for a better loading experience.
  • Browsers block autoplay with sound; autoplay only muted media and always let users pause it.
  • Add captions with <track> and WebVTT files, provide transcripts for audio, and give iframes a title.

Quick quiz

Check what you learned – pick an answer.

1. Which attribute shows the built-in play, pause and volume buttons?

2. Which combination is most likely to autoplay in modern browsers?

3. Which element adds captions to a video?

Practice exercise

Write the markup for a video of a Bharatanatyam performance: show controls, set width 640 and height 360, a poster image "dance-poster.jpg", WebM and MP4 sources, English captions from "dance.en.vtt", and a fallback download link.

Show a hint

Put the <source> elements first, then <track>, then the fallback text.

Show the solution
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Dance video</title>
</head>
<body>
  <video controls width="640" height="360" preload="metadata" poster="dance-poster.jpg">
    <source src="dance.webm" type="video/webm">
    <source src="dance.mp4" type="video/mp4">
    <track src="dance.en.vtt" kind="captions" srclang="en" label="English" default>
    <p>Your browser cannot play this video. <a href="dance.mp4">Download the video</a>.</p>
  </video>
</body>
</html>

Progress is saved in this browser only.