DEV Community

Cover image for How to build an audio player with HTML5 and the Progress element
Luke Duncan
Luke Duncan

Posted on

2

How to build an audio player with HTML5 and the Progress element

HTML5 introduces built-in media support with the audio tag, which makes it very easy to embed media straight into any HTML document with limited code. It comes with built in browser controls, if you specify and plays audio nice and effectively.

This is typically what it will look like in your browser.

Standard Browser HTML5 Audio Player

You might be thinking: “Well what if I wanted to style my own audio player with it’s own buttons and scroll bar?”

With the audio element, the progress element and a few buttons, you can build your own audio player in no time! The progress element is mainly used to track the completion of a task and can be manipulated easily with Javascript. In our case, it would be to keep track of the length of a song. And the great thing is, HTML5 and browser capabilities make it easy to grab song lengths, current time and more.

If you’d like to play with the code, go for it! Unfortunately Codepen embeds aren't working for me so the link is below.

View on Codepen here!

And below is the code. Note that their are two separate functions. One that keeps track of the audio player actually playing audio (initPlayers function) and the other that is keeping track of the audio for the progress element (initProgressBar function). I tried to keep jQuery to a minimum but used it to actually call the function, sorry, i’m not sorry JS purists.

<div class="audio-player">
<div id="play-btn"></div>
<div class="audio-wrapper" id="player-container" href="javascript:;">
<audio id="player" ontimeupdate="initProgressBar()">
<source src="https://dl-web.dropbox.com/get/Oslo.mp3?_subject_uid=199049471&w=AABuDNt9BDJnaZOelVFws9FXTufkXCvAPS5SYpy_gRZ2GQ&duc_id=dropbox_duc_id" type="audio/mp3">
</audio>
</div>
<div class="player-controls scrubber">
<p>Oslo <small>by</small> Holy Esque</p>
<span id="seek-obj-container">
<progress id="seek-obj" value="0" max="1"></progress>
</span>
<small style="float: left; position: relative; left: 15px;" id="start-time"></small>
<small style="float: right; position: relative; right: 20px;" id="end-time"></small>
</div>
<div class="album-image" style="background-image: url(https://img.discogs.com/smajEDf4MJk3Le7gG9oi-cke6e4=/fit-in/600x598/filters:strip_icc():format(jpeg):mode_rgb():quality(90)/discogs-images/R-7859768-1452996483-9325.jpeg.jpg)"></div>
</div>
function initProgressBar() {
var player = document.getElementById('player');
var length = player.duration
var current_time = player.currentTime;
// calculate total length of value
var totalLength = calculateTotalValue(length)
document.getElementById("end-time").innerHTML = totalLength;
// calculate current value time
var currentTime = calculateCurrentValue(current_time);
document.getElementById("start-time").innerHTML = currentTime;
var progressbar = document.getElementById('seek-obj');
progressbar.value = (player.currentTime / player.duration);
progressbar.addEventListener("click", seek);
if (player.currentTime == player.duration) {
document.getElementById('play-btn').className = "";
}
function seek(event) {
var percent = event.offsetX / this.offsetWidth;
player.currentTime = percent * player.duration;
progressbar.value = percent / 100;
}
};
function initPlayers(num) {
// pass num in if there are multiple audio players e.g 'player' + i
for (var i = 0; i < num; i++) {
(function() {
// Variables
// ----------------------------------------------------------
// audio embed object
var playerContainer = document.getElementById('player-container'),
player = document.getElementById('player'),
isPlaying = false,
playBtn = document.getElementById('play-btn');
// Controls Listeners
// ----------------------------------------------------------
if (playBtn != null) {
playBtn.addEventListener('click', function() {
togglePlay()
});
}
// Controls & Sounds Methods
// ----------------------------------------------------------
function togglePlay() {
if (player.paused === false) {
player.pause();
isPlaying = false;
document.getElementById('play-btn').className = "";
} else {
player.play();
document.getElementById('play-btn').className = "pause";
isPlaying = true;
}
}
}());
}
}
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60),
seconds_int = length - minutes * 60,
seconds_str = seconds_int.toString(),
seconds = seconds_str.substr(0, 2),
time = minutes + ':' + seconds
return time;
}
function calculateCurrentValue(currentTime) {
var current_hour = parseInt(currentTime / 3600) % 24,
current_minute = parseInt(currentTime / 60) % 60,
current_seconds_long = currentTime % 60,
current_seconds = current_seconds_long.toFixed(),
current_time = (current_minute < 10 ? "0" + current_minute : current_minute) + ":" + (current_seconds < 10 ? "0" + current_seconds : current_seconds);
return current_time;
}
initPlayers(jQuery('#player-container').length);
view raw audio-player.js hosted with ❤ by GitHub
.audio-player {
border: 1px solid lighten(#acacac, 20%);
text-align: center;
display: flex;
flex-flow: row;
margin: 4rem 0 4rem 0;
width: 600px;
.album-image {
min-height: 100px;
width: 100px;
background-size: cover;
}
.player-controls {
align-items: center;
justify-content: center;
margin-top: 2.5rem;
flex: 3;
progress {
width: 90%;
}
progress[value] {
-webkit-appearance: none;
appearance: none;
background-color: white;
color: blue;
height: 5px;
}
progress[value]::-webkit-progress-bar {
background-color: white;
border-radius: 2px;
border: 1px solid lighten(#acacac, 20%);
color: blue;
}
progress::-webkit-progress-value {
background-color: blue;
}
p {
font-size: 1.6rem;
}
}
#play-btn {
background-image: url('http://imgur.com/JzQP8td.png');
background-size: cover;
width: 75px;
height: 75px;
margin: 2rem 0 2rem 2rem;
&.pause {
background-image: url('http://imgur.com/MbJn41l.png');
}
}
}
view raw main.scss hosted with ❤ by GitHub

If you have any questions or suggestions, i’m all ears! Email me at luke.will.duncan@gmail.com or hit me up on twitter @luke__duncan

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (1)

Collapse
 
quriosapien profile image
Kumar Gaurav

can we implement seek functionality ourselves ?