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✅✅❌✅