Introduction to HTML5 Media
HTML5 introduced native support for audio and video content through the <audio> and <video> elements, eliminating the need for plugins like Flash. These elements provide built-in controls and can be customized with JavaScript for enhanced user experiences.
The <audio> Element
The <audio> element embeds sound content in web pages with support for multiple audio formats.
Basic Audio Implementation
html
<!-- Simple audio with controls -->
<audio controls>
  <source src="audio/music.mp3" type="audio/mpeg">
  <source src="audio/music.ogg" type="audio/ogg">
  Your browser does not support the audio element.
</audio>
<!-- Audio with additional attributes -->
<audio controls autoplay loop muted preload="auto">
  <source src="audio/background-music.mp3" type="audio/mpeg">
  <source src="audio/background-music.wav" type="audio/wav">
  <p>Your browser doesn't support HTML5 audio. 
     <a href="audio/background-music.mp3">Download the audio file</a>.</p>
</audio>
Audio Attributes
html
<audio controls <!-- Show browser's default controls --> autoplay <!-- Start playing automatically (use carefully) --> loop <!-- Repeat playback --> muted <!-- Start muted --> preload="auto" <!-- auto, metadata, or none --> volume="0.5" <!-- Set initial volume (0.0 to 1.0) --> src="audio.mp3"> <!-- Direct source (alternative to <source>) --> </audio>
The <video> Element
The <video> element embeds video content with similar functionality to audio.
Basic Video Implementation
html
<!-- Simple video with controls -->
<video controls width="640" height="360">
  <source src="video/movie.mp4" type="video/mp4">
  <source src="video/movie.webm" type="video/webm">
  <source src="video/movie.ogg" type="video/ogg">
  Your browser does not support the video tag.
</video>
<!-- Video with poster and additional attributes -->
<video 
  controls 
  width="800" 
  height="450" 
  poster="images/video-thumbnail.jpg"
  preload="metadata">
  <source src="video/tutorial.mp4" type="video/mp4">
  <source src="video/tutorial.webm" type="video/webm">
  <track kind="subtitles" src="subtitles/english.vtt" srclang="en" label="English" default>
  <track kind="subtitles" src="subtitles/spanish.vtt" srclang="es" label="Español">
  <p>Your browser doesn't support HTML5 video. 
     <a href="video/tutorial.mp4">Download the video</a>.</p>
</video>
Video Attributes
html
<video controls <!-- Show playback controls --> autoplay <!-- Auto-start (requires muted in most browsers) --> loop <!-- Repeat playback --> muted <!-- Start muted --> preload="auto" <!-- Loading strategy --> poster="thumb.jpg" <!-- Thumbnail image --> width="640" <!-- Display width --> height="360" <!-- Display height --> playsinline <!-- Play inline on mobile (iOS) --> crossorigin="anonymous"> <!-- CORS settings --> </video>
Multiple Source Formats
Different browsers support different media formats. Use multiple sources for maximum compatibility:
html
<!-- Audio format compatibility --> <audio controls> <source src="audio/song.mp3" type="audio/mpeg"> <!-- Chrome, Safari, IE --> <source src="audio/song.ogg" type="audio/ogg"> <!-- Firefox, Chrome --> <source src="audio/song.wav" type="audio/wav"> <!-- Fallback --> </audio> <!-- Video format compatibility --> <video controls width="640" height="360"> <source src="video/movie.mp4" type="video/mp4"> <!-- Most browsers --> <source src="video/movie.webm" type="video/webm"> <!-- Chrome, Firefox --> <source src="video/movie.ogv" type="video/ogg"> <!-- Firefox, older versions --> </video>
Subtitles and Captions with <track>
The <track> element provides text tracks for accessibility:
html
<video controls width="640" height="360"> <source src="video/lecture.mp4" type="video/mp4"> <!-- Subtitles in multiple languages --> <track kind="subtitles" src="tracks/en.vtt" srclang="en" label="English" default> <track kind="subtitles" src="tracks/es.vtt" srclang="es" label="Español"> <track kind="subtitles" src="tracks/fr.vtt" srclang="fr" label="Français"> <!-- Captions for accessibility --> <track kind="captions" src="tracks/captions-en.vtt" srclang="en" label="English Captions"> <!-- Chapter navigation --> <track kind="chapters" src="tracks/chapters.vtt" srclang="en" label="Chapters"> <!-- Additional descriptions --> <track kind="descriptions" src="tracks/descriptions.vtt" srclang="en" label="Audio Descriptions"> </video>
WebVTT Format Example
vtt
WEBVTT 00:00:00.000 --> 00:00:03.000 Welcome to our HTML tutorial series. 00:00:03.000 --> 00:00:06.000 Today we'll learn about media elements. 00:00:06.000 --> 00:00:10.000 Let's start with the audio and video tags.
Custom Media Controls with JavaScript
Create custom controls for better design integration:
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Custom Video Player</title>
  <style>
    .video-container {
      position: relative;
      max-width: 800px;
      margin: 20px auto;
      background: #000;
      border-radius: 8px;
      overflow: hidden;
    }
    
    video {
      width: 100%;
      height: auto;
      display: block;
    }
    
    .custom-controls {
      position: absolute;
      bottom: 0;
      left: 0;
      right: 0;
      background: linear-gradient(transparent, rgba(0,0,0,0.7));
      padding: 20px;
      opacity: 0;
      transition: opacity 0.3s;
    }
    
    .video-container:hover .custom-controls {
      opacity: 1;
    }
    
    .controls-row {
      display: flex;
      align-items: center;
      gap: 15px;
      color: white;
    }
    
    .play-btn {
      background: none;
      border: none;
      color: white;
      font-size: 24px;
      cursor: pointer;
      padding: 5px;
    }
    
    .progress-container {
      flex: 1;
      height: 6px;
      background: rgba(255,255,255,0.3);
      border-radius: 3px;
      cursor: pointer;
      position: relative;
    }
    
    .progress-bar {
      height: 100%;
      background: #007bff;
      border-radius: 3px;
      width: 0%;
      transition: width 0.1s;
    }
    
    .time-display {
      font-size: 14px;
      min-width: 80px;
    }
    
    .volume-container {
      display: flex;
      align-items: center;
      gap: 5px;
    }
    
    .volume-slider {
      width: 60px;
    }
    
    .fullscreen-btn {
      background: none;
      border: none;
      color: white;
      font-size: 18px;
      cursor: pointer;
      padding: 5px;
    }
  </style>
</head>
<body>
  <div class="video-container">
    <video id="custom-video" preload="metadata">
      <source src="video/sample.mp4" type="video/mp4">
      <source src="video/sample.webm" type="video/webm">
    </video>
    
    <div class="custom-controls">
      <div class="controls-row">
        <button class="play-btn" id="play-pause">▶</button>
        
        <div class="progress-container" id="progress-container">
          <div class="progress-bar" id="progress-bar"></div>
        </div>
        
        <div class="time-display" id="time-display">0:00 / 0:00</div>
        
        <div class="volume-container">
          <button id="mute-btn">🔊</button>
          <input type="range" class="volume-slider" id="volume-slider" min="0" max="100" value="100">
        </div>
        
        <button class="fullscreen-btn" id="fullscreen-btn">⛶</button>
      </div>
    </div>
  </div>
  
  <script>
    const video = document.getElementById('custom-video');
    const playPauseBtn = document.getElementById('play-pause');
    const progressContainer = document.getElementById('progress-container');
    const progressBar = document.getElementById('progress-bar');
    const timeDisplay = document.getElementById('time-display');
    const muteBtn = document.getElementById('mute-btn');
    const volumeSlider = document.getElementById('volume-slider');
    const fullscreenBtn = document.getElementById('fullscreen-btn');
    
    // Play/Pause functionality
    playPauseBtn.addEventListener('click', () => {
      if (video.paused || video.ended) {
        video.play();
        playPauseBtn.textContent = '⏸';
      } else {
        video.pause();
        playPauseBtn.textContent = '▶';
      }
    });
    
    // Update progress bar
    video.addEventListener('timeupdate', () => {
      const progress = (video.currentTime / video.duration) * 100;
      progressBar.style.width = progress + '%';
      
      // Update time display
      const current = formatTime(video.currentTime);
      const duration = formatTime(video.duration);
      timeDisplay.textContent = `${current} / ${duration}`;
    });
    
    // Seek functionality
    progressContainer.addEventListener('click', (e) => {
      const rect = progressContainer.getBoundingClientRect();
      const clickX = e.clientX - rect.left;
      const width = rect.right - rect.left;
      const newTime = (clickX / width) * video.duration;
      video.currentTime = newTime;
    });
    
    // Volume control
    volumeSlider.addEventListener('input', (e) => {
      video.volume = e.target.value / 100;
      updateVolumeIcon();
    });
    
    muteBtn.addEventListener('click', () => {
      video.muted = !video.muted;
      updateVolumeIcon();
    });
    
    function updateVolumeIcon() {
      if (video.muted || video.volume === 0) {
        muteBtn.textContent = '🔇';
      } else if (video.volume < 0.5) {
        muteBtn.textContent = '🔉';
      } else {
        muteBtn.textContent = '🔊';
      }
    }
    
    // Fullscreen functionality
    fullscreenBtn.addEventListener('click', () => {
      if (document.fullscreenElement) {
        document.exitFullscreen();
      } else {
        document.querySelector('.video-container').requestFullscreen();
      }
    });
    
    // Format time helper
    function formatTime(seconds) {
      if (isNaN(seconds)) return '0:00';
      
      const minutes = Math.floor(seconds / 60);
      const secs = Math.floor(seconds % 60);
      return `${minutes}:${secs.toString().padStart(2, '0')}`;
    }
    
    // Keyboard shortcuts
    document.addEventListener('keydown', (e) => {
      if (e.target.tagName.toLowerCase() !== 'input') {
        switch(e.code) {
          case 'Space':
            e.preventDefault();
            playPauseBtn.click();
            break;
          case 'KeyM':
            muteBtn.click();
            break;
          case 'KeyF':
            fullscreenBtn.click();
            break;
          case 'ArrowLeft':
            video.currentTime -= 10;
            break;
          case 'ArrowRight':
            video.currentTime += 10;
            break;
        }
      }
    });
  </script>
</body>
</html>
Audio Player with Playlist
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Custom Audio Player with Playlist</title>
  <style>
    .audio-player {
      max-width: 400px;
      margin: 20px auto;
      background: #f8f9fa;
      border-radius: 12px;
      padding: 20px;
      box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    }
    
    .now-playing {
      text-align: center;
      margin-bottom: 20px;
    }
    
    .track-info h3 {
      margin: 0 0 5px 0;
      color: #333;
    }
    
    .track-info p {
      margin: 0;
      color: #666;
      font-size: 14px;
    }
    
    .audio-controls {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 15px;
      margin: 20px 0;
    }
    
    .control-btn {
      background: #007bff;
      border: none;
      border-radius: 50%;
      width: 50px;
      height: 50px;
      color: white;
      font-size: 18px;
      cursor: pointer;
      transition: background-color 0.3s;
    }
    
    .control-btn:hover {
      background: #0056b3;
    }
    
    .play-pause-btn {
      width: 60px;
      height: 60px;
      font-size: 24px;
    }
    
    .progress-section {
      margin: 15px 0;
    }
    
    .progress-bar {
      width: 100%;
      height: 6px;
      background: #e9ecef;
      border-radius: 3px;
      cursor: pointer;
      position: relative;
    }
    
    .progress-fill {
      height: 100%;
      background: #007bff;
      border-radius: 3px;
      width: 0%;
      transition: width 0.1s;
    }
    
    .time-info {
      display: flex;
      justify-content: space-between;
      font-size: 12px;
      color: #666;
      margin-top: 5px;
    }
    
    .playlist {
      max-height: 200px;
      overflow-y: auto;
      margin-top: 20px;
    }
    
    .playlist-item {
      display: flex;
      align-items: center;
      padding: 10px;
      border-radius: 6px;
      cursor: pointer;
      transition: background-color 0.3s;
    }
    
    .playlist-item:hover {
      background: #e9ecef;
    }
    
    .playlist-item.active {
      background: #007bff;
      color: white;
    }
    
    .playlist-item .track-number {
      width: 30px;
      text-align: center;
      font-weight: bold;
    }
    
    .playlist-item .track-details {
      flex: 1;
      margin-left: 10px;
    }
    
    .playlist-item .track-title {
      font-weight: bold;
      margin-bottom: 2px;
    }
    
    .playlist-item .track-artist {
      font-size: 12px;
      opacity: 0.8;
    }
  </style>
</head>
<body>
  <div class="audio-player">
    <audio id="audio-element" preload="metadata"></audio>
    
    <div class="now-playing">
      <div class="track-info">
        <h3 id="current-title">Select a track</h3>
        <p id="current-artist">No track selected</p>
      </div>
    </div>
    
    <div class="audio-controls">
      <button class="control-btn" id="prev-btn">⏮</button>
      <button class="control-btn play-pause-btn" id="play-pause-btn">▶</button>
      <button class="control-btn" id="next-btn">⏭</button>
    </div>
    
    <div class="progress-section">
      <div class="progress-bar" id="progress-bar">
        <div class="progress-fill" id="progress-fill"></div>
      </div>
      <div class="time-info">
        <span id="current-time">0:00</span>
        <span id="total-time">0:00</span>
      </div>
    </div>
    
    <div class="playlist" id="playlist">
      <!-- Playlist items will be generated by JavaScript -->
    </div>
  </div>
  
  <script>
    const audio = document.getElementById('audio-element');
    const playPauseBtn = document.getElementById('play-pause-btn');
    const prevBtn = document.getElementById('prev-btn');
    const nextBtn = document.getElementById('next-btn');
    const progressBar = document.getElementById('progress-bar');
    const progressFill = document.getElementById('progress-fill');
    const currentTimeEl = document.getElementById('current-time');
    const totalTimeEl = document.getElementById('total-time');
    const currentTitle = document.getElementById('current-title');
    const currentArtist = document.getElementById('current-artist');
    const playlistEl = document.getElementById('playlist');
    
    // Sample playlist data
    const playlist = [
      {
        title: "Sample Track 1",
        artist: "Demo Artist",
        src: "audio/track1.mp3"
      },
      {
        title: "Sample Track 2", 
        artist: "Demo Artist",
        src: "audio/track2.mp3"
      },
      {
        title: "Sample Track 3",
        artist: "Demo Artist", 
        src: "audio/track3.mp3"
      }
    ];
    
    let currentTrackIndex = 0;
    let isPlaying = false;
    
    // Initialize playlist
    function initPlaylist() {
      playlistEl.innerHTML = '';
      playlist.forEach((track, index) => {
        const item = document.createElement('div');
        item.className = 'playlist-item';
        item.innerHTML = `
          <div class="track-number">${index + 1}</div>
          <div class="track-details">
            <div class="track-title">${track.title}</div>
            <div class="track-artist">${track.artist}</div>
          </div>
        `;
        item.addEventListener('click', () => playTrack(index));
        playlistEl.appendChild(item);
      });
    }
    
    // Play specific track
    function playTrack(index) {
      currentTrackIndex = index;
      const track = playlist[index];
      
      audio.src = track.src;
      currentTitle.textContent = track.title;
      currentArtist.textContent = track.artist;
      
      // Update active playlist item
      document.querySelectorAll('.playlist-item').forEach((item, i) => {
        item.classList.toggle('active', i === index);
      });
      
      audio.load();
    }
    
    // Play/pause functionality
    playPauseBtn.addEventListener('click', () => {
      if (isPlaying) {
        audio.pause();
      } else {
        if (!audio.src) {
          playTrack(0);
        }
        audio.play();
      }
    });
    
    // Audio event listeners
    audio.addEventListener('play', () => {
      isPlaying = true;
      playPauseBtn.textContent = '⏸';
    });
    
    audio.addEventListener('pause', () => {
      isPlaying = false;
      playPauseBtn.textContent = '▶';
    });
    
    audio.addEventListener('timeupdate', () => {
      const progress = (audio.currentTime / audio.duration) * 100;
      progressFill.style.width = progress + '%';
      
      currentTimeEl.textContent = formatTime(audio.currentTime);
      totalTimeEl.textContent = formatTime(audio.duration);
    });
    
    audio.addEventListener('ended', () => {
      // Auto-play next track
      nextTrack();
    });
    
    // Previous/Next track
    prevBtn.addEventListener('click', () => {
      currentTrackIndex = (currentTrackIndex - 1 + playlist.length) % playlist.length;
      playTrack(currentTrackIndex);
      if (isPlaying) audio.play();
    });
    
    nextBtn.addEventListener('click', nextTrack);
    
    function nextTrack() {
      currentTrackIndex = (currentTrackIndex + 1) % playlist.length;
      playTrack(currentTrackIndex);
      if (isPlaying) audio.play();
    }
    
    // Progress bar seeking
    progressBar.addEventListener('click', (e) => {
      const rect = progressBar.getBoundingClientRect();
      const clickX = e.clientX - rect.left;
      const width = rect.right - rect.left;
      const newTime = (clickX / width) * audio.duration;
      audio.currentTime = newTime;
    });
    
    // Format time helper
    function formatTime(seconds) {
      if (isNaN(seconds)) return '0:00';
      const minutes = Math.floor(seconds / 60);
      const secs = Math.floor(seconds % 60);
      return `${minutes}:${secs.toString().padStart(2, '0')}`;
    }
    
    // Initialize
    initPlaylist();
  </script>
</body>
</html>
Media Accessibility Best Practices
- Always provide fallback content for browsers that don't support HTML5 media
- Include captions and subtitles for video content
- Provide audio descriptions for visually impaired users
- Use appropriate ARIA labels for custom controls
- Ensure keyboard navigation works for all controls
- Provide transcripts for audio content
Browser Compatibility and Format Support
FormatChromeFirefoxSafariEdgeMP3✅✅✅✅OGG✅✅❌❌WAV✅✅✅✅MP4✅✅✅✅WebM✅✅❌✅