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

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (1)

Collapse
 
quriosapien profile image
Kumar Gaurav

can we implement seek functionality ourselves ?

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay