Tutorial

Video & Multimedia on the web

Put real sound and motion on a page. Learn the native <video> and <audio> tags, how to embed YouTube the responsive way, and how <picture> serves the right image to every screen — each with a live, playable demo and copy-paste code.

Overview

The four multimedia building blocks

"Multimedia" just means more than text and links — sound, video, and rich images. HTML gives you four tools for it. You'll use each one in this tutorial.

<video>

Plays video files you host yourself — .mp4, .webm — with built-in controls.

<audio>

Plays sound — podcasts, music, voiceovers — from .mp3 or .ogg files.

<iframe> embeds

Drops in a YouTube or Vimeo player so you don't host huge video files yourself.

<picture>

Serves different image files by screen size or format — smaller files, sharper results.

Host it or embed it? Short clips you own (a product demo, an intro reel) → use <video>. Long videos, or anything already on YouTube → embed an <iframe> so their servers handle the bandwidth, not yours.
Step 1

The <video> tag

The <video> element plays a video file right on your page. Add the controls attribute and the browser draws the play button, scrubber, volume, and fullscreen for you. Below is a real video playing through the native player.

Live demo — native player

Press play · drag the scrubber · go fullscreen — all built in, no JavaScript

The markup

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Native video player</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

  <!-- The frame just centres + rounds the player -->
  <div class="video-frame">
    <!-- controls = show the play/scrub/volume bar -->
    <video controls preload="metadata" playsinline poster="cover.jpg">
      <!-- The browser plays the first source it understands -->
      <source src="clip.mp4" type="video/mp4">
      <source src="clip.webm" type="video/webm">
      <!-- Fallback text for very old browsers -->
      Your browser doesn't support the video tag.
    </video>
  </div>
  <p class="media-caption">Press play · drag the scrubber · go fullscreen — all built in, no JavaScript</p>

</body>
</html>
body {
  background: #0a0a0a;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Centred, rounded frame with a soft drop shadow */
.video-frame {
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 16px 40px rgba(0,0,0,.5);
  background: #000;
}
.video-frame video {
  width: 100%;
  height: auto;
  display: block;
}
/* Caption under the player */
.media-caption {
  text-align: center;
  font-size: 0.82rem;
  color: #71717a;
  margin-top: 12px;
}

The attributes you'll actually use

AttributeWhat it does
controlsShows the play bar, scrubber, volume, and fullscreen button.
posterAn image shown before the video plays — like a thumbnail.
autoplayStarts playing on load. Browsers only allow this if muted is also set.
mutedStarts with no sound. Required for autoplay to work.
loopReplays from the start when it ends — good for ambient background clips.
preloadmetadata loads just the length/dimensions; none waits until play; auto loads the whole file.
playsinlinePlays inside the page on iPhone instead of forcing fullscreen.
Always provide a poster. Without one, a paused video shows a black box (or a random first frame). A poster image makes the player look intentional before anyone hits play.
Step 2

The <audio> tag

Same idea as <video>, just for sound. Add controls and you get a play button, scrubber, and volume slider. Perfect for podcast episodes, music previews, or narrated walkthroughs. Two real audio tracks are wired up below.

Live demo — two audio players
Light the WayTrack 1
What I LearnedTrack 2

The markup

<div class="audio-row">

  <!-- Track 1 -->
  <div class="audio-card">
    <div class="audio-art"><i class="ph-fill ph-music-note"></i></div>
    <div class="audio-body">
      <div class="audio-meta"><strong>Light the Way</strong><span>Track 1</span></div>
      <audio controls preload="metadata">
        <source src="Light%20the%20Way.mp3" type="audio/mpeg">
        Your browser doesn't support the audio element.
      </audio>
    </div>
  </div>

  <!-- Track 2 -->
  <div class="audio-card">
    <div class="audio-art"><i class="ph-fill ph-microphone"></i></div>
    <div class="audio-body">
      <div class="audio-meta"><strong>What I Learned</strong><span>Track 2</span></div>
      <audio controls preload="metadata">
        <source src="What%20I%20Learned.mp3" type="audio/mpeg">
        Your browser doesn't support the audio element.
      </audio>
    </div>
  </div>

</div>
/* Stack the two cards in a column */
.audio-row {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 540px;
  margin: 0 auto;
}
.audio-card {
  display: flex;
  align-items: center;
  gap: 16px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 12px;
  padding: 16px 18px;
}
/* The pink-to-purple gradient square with the icon */
.audio-art {
  width: 52px;
  height: 52px;
  border-radius: 10px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  color: #fff;
  background: linear-gradient(135deg, #f43f5e, #a855f7);
}
.audio-body {
  flex: 1;
  min-width: 0;
}
.audio-meta strong {
  display: block;
  font-size: 0.95rem;
  color: #fff;
}
.audio-meta span {
  font-size: 0.8rem;
  color: #a1a1aa;
}
.audio-card audio {
  width: 100%;
  margin-top: 10px;
}
Filenames with spaces? A space in My Song.mp3 must be written as My%20Song.mp3 in the src (that's what %20 means). The safest habit is to rename media files with hyphens: my-song.mp3.
Step 3

Embedding YouTube & Vimeo

For videos already online, don't download and re-host them — embed an <iframe>. On YouTube, click Share → Embed and copy the code. The trick is making it responsive: wrap it in a 16:9 box so it scales on phones instead of overflowing.

The responsive 16:9 frame
Your embedded player goes here This dashed box keeps a perfect 16:9 ratio at any width — paste your iframe inside it

Resize the window — the frame keeps its 16:9 shape and never overflows

The code

<!-- The 16:9 ratio box. Drop a real <iframe> inside -->
<!-- and it fills the frame; the placeholder below   -->
<!-- just shows the empty shape until you do.        -->
<div class="embed-16x9">

  <!-- Placeholder shown while the box is empty -->
  <div class="embed-placeholder">
    <i class="ph-duotone ph-youtube-logo"></i>
    <strong>Your embedded player goes here</strong>
    <small>This dashed box keeps a perfect 16:9 ratio at any width — paste your iframe inside it</small>
  </div>

  <!-- When ready, replace the placeholder with: -->
  <iframe src="https://www.youtube.com/embed/VIDEO_ID"
          title="YouTube video player" allowfullscreen></iframe>

</div>
body { background: #0a0a0a; }

/* The ratio box: keeps 16:9 at any width.       */
/* Dashed border + striped fill show it's empty.  */
.embed-16x9 {
  position: relative;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  overflow: hidden;
  background:
    repeating-linear-gradient(45deg, #18181b, #18181b 14px, #141417 14px, #141417 28px);
  border: 1px dashed rgba(244,63,94,.4);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
/* A real iframe drops in and fills the box completely */
.embed-16x9 iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
/* The "drop your player here" placeholder */
.embed-placeholder {
  color: #a1a1aa;
  padding: 20px;
}
.embed-placeholder i {
  font-size: 2.4rem;
  color: #f43f5e;
  display: block;
  margin-bottom: 10px;
}
.embed-placeholder strong {
  color: #fff;
  display: block;
  margin-bottom: 4px;
}
.embed-placeholder small {
  font-size: 0.8rem;
}
Replace VIDEO_ID with the part after watch?v= in a YouTube URL. For youtube.com/watch?v=dQw4w9WgXcQ the embed src becomes youtube.com/embed/dQw4w9WgXcQ.
Step 4

Rich images with <picture>

Images are multimedia too. The <picture> element lets you ship a small image to phones and a large one to desktops, or a modern .webp with a .jpg fallback — the browser picks the best one and never downloads the rest.

Swap by screen size

<picture>
  <!-- Phone: load the small image -->
  <source media="(max-width: 600px)" srcset="hero-small.jpg">
  <!-- Tablet and up: the big image -->
  <source media="(min-width: 601px)" srcset="hero-large.jpg">
  <!-- Fallback & required alt text -->
  <img src="hero-large.jpg" alt="Sunset over the city">
</picture>

Modern format with a fallback

<picture>
  <source srcset="photo.webp" type="image/webp">
  <img src="photo.jpg" alt="Team photo" width="800" height="500">
</picture>
The <img> inside is not optional. It's the fallback and the place where alt text lives. A <picture> with no inner <img> shows nothing.
Step 5

Captions & accessibility

Media that only works with sound and sight shuts people out. A <track> element adds captions to video; a transcript helps everyone. Here's what to get right.

<video controls>
  <source src="talk.mp4" type="video/mp4">
  <!-- Captions load from a .vtt text file -->
  <track kind="captions" src="talk.vtt"
         srclang="en" label="English" default>
</video>

Do

  • Add a <track> with captions for spoken video
  • Give every <img> meaningful alt text
  • Keep controls visible so users can pause
  • Set width & height to prevent layout shift
  • Compress files — a hero video should be a few MB, not 70
  • Offer a text transcript for podcasts & talks

Don't

  • Autoplay video with sound — it startles users (and is blocked)
  • Re-host someone else's YouTube video — embed it instead
  • Ship a 100 MB uncompressed .mov straight from your phone
  • Hide controls with no other way to pause
  • Rely on color or sound alone to carry meaning
  • Forget the fallback text between the media tags
Cheat Sheet

Everything at a glance

The four patterns condensed. Copy what you need into any project.

<video controls poster="cover.jpg" width="640">
  <source src="clip.mp4" type="video/mp4">
</video>
<audio controls>
  <source src="episode.mp3" type="audio/mpeg">
</audio>
<div class="embed-16x9">
  <iframe src="https://www.youtube.com/embed/VIDEO_ID"
          title="Video" allowfullscreen></iframe>
</div>
<picture>
  <source srcset="photo.webp" type="image/webp">
  <img src="photo.jpg" alt="Description">
</picture>