When you display video in HTML5, you have may want to display a set of controls to the user. The HTML5 video tag has a control attribute that lets you display the controls that come with the browser.
But you may want to build custom controls using its media API, and the media events. Play, pause, and seek in the entire video, change the volume, mute, change the playback rate (including going into negative values).
This post shows how you can build a custom media player using different the media API attributes, events, and methods.
Getting Started
To get started, you begin with a video element.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Popeye for President</title> | |
</head> | |
<body> | |
<video width="320" height="240" controls> | |
<source src="video/PopeyeForPresident_qtp.mp4" type="video/mp4"> | |
<source src="video/PopeyeForPresident_qtp.ogv" type="video/ogg"> | |
Your browser does not support HTML5 MPG4 video. | |
</video> | |
</body> | |
</html> |
The controls attributes remains for the use case of when a user has JavaScript turned off, your user will still work with the browser’s default control set.
So we will need to turn off the video. Once the page has been loaded, you can turn off the controls by setting the controls attribute to false.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Turn off the default controls | |
cartoon.controls = false; |
Play and Pause
Let’s add a button to play and pause.
<https://gist.github.com/devdays/7c3a869c884e7fa316e4
And then you can toggle the button to show Play or Pause and to set the video to play or pause.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
playpause.addEventListener("click", function () { | |
if (cartoon.paused || cartoon.ended) { | |
playpause.title = "Pause"; | |
playpause.innerHTML = "Pause"; | |
cartoon.play(); | |
} | |
else { | |
playpause.title = "Play"; | |
playpause.innerHTML = "Play"; | |
cartoon.pause(); | |
} | |
}); |
The button’s default text is “play.” When the button is clicked for the first time, the video will start playing and the button’s text will be changed to “pause.” Subsequently, when the pause button is clicked, the video will pause and the button’s text will be changed back to “play.”
The Pattern
The remaining functionality that you can add follows the same basic format:
- Listen for an event from the
video
element. - Check the element’s status.
- Then act on it via API methods.
Volume and Mute
To add a volume control, you’ll use one of the new HTML5 input types: range
. This input type is usually rendered by the browser as a slider, which your user can move.
You specify the minimum and maximum values for the range input via the min
and max
attributes. You use the step
attribute to set the amount you want the slider’s value to change when the slider’s position changes. To create a volume control slider with a range between 0 and 1, and a step size of 0.1.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<input id="volume" min="0" max="1" step="0.1" type="range" /> |
And then provide an event handler for the slider’s change event.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
volume.addEventListener("change", function () { | |
cartoon.volume = volume.value; | |
}, false); |
And then a button to mute.
With code to perform the mute.
This listens for the mut button’s click event, and then responds by setting the video
element’s (Boolean) muted
attribute to be the opposite of its current value.
Progress Bar
Next we define a progress bar. You can create a progress bar using a span that we will color using CSS.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="progressBar"> | |
<span id="progress"></span> | |
</div> |
With some CSS to shade it in as the video plays.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#progressBar { | |
border: 1px solid #aaa; | |
color: #fff; | |
width: 295px; | |
height: 20px; | |
} | |
#progress { | |
background-color: maroon; | |
height:20px; | |
display: inline-block; | |
} |
Finally, we add some script that listens to the video’s timeupdate event.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cartoon.addEventListener("timeupdate", function () { | |
var value = 0; | |
if (cartoon.currentTime > 0) { | |
value = Math.floor((100 / cartoon.duration) * cartoon.currentTime); | |
} | |
progress.style.width = value + "%"; | |
}, false); |
It checks the value of the video
element’s currentTime
attribute, which defines the current playback position, in seconds. If currentTime
is greater than 0
, and therefore the video has advanced, it calculates the current progress as a percentage using the video
element’s duration
attribute, which contains the video’s total length in seconds. Finally, it sets the CSS width
of the progress span
to this calculated value.
Best Practice
The media element API defines a number of events that you can use in implementing a media player. For a complete list, see the W3C’s summary of media element API events.
When you’re adding custom controls, it’s a best practice to listen for some of the available events to make sure your controls are always synchronized with the state of the video.
A user might reenable the brower’s default controls and use them to interact with the video. For example, in Firefox, a user can right-click the video, select Show Controls, and click Play or Pause. If a user did this and started a video playing, the text on the play/pause button that you created would no longer be correct.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cartoon.addEventListener('play', function () { | |
playpause.title = "Pause"; | |
playpause.innerHTML = "Pause"; | |
}, false); | |
cartoon.addEventListener('pause', function () { | |
playpause.title = "Play"; | |
playpause.innerHTML = "Play"; | |
}, false); |
Completed Sample Code
Here’s a listing of the completed video sample code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Popeye for President</title> | |
<style> | |
#progressBar { | |
border: 1px solid #aaa; | |
color: #fff; | |
width: 295px; | |
height: 20px; | |
} | |
#progress { | |
background-color: maroon; | |
height: 20px; | |
display: inline-block; | |
} | |
</style> | |
<script> | |
window.addEventListener("load", function () { | |
// Turn off the default controls | |
cartoon.controls = false; | |
playpause.addEventListener("click", function () { | |
if (cartoon.paused || cartoon.ended) { | |
playpause.title = "Pause"; | |
playpause.innerHTML = "Pause"; | |
cartoon.play(); | |
} | |
else { | |
playpause.title = "Play"; | |
playpause.innerHTML = "Play"; | |
cartoon.pause(); | |
} | |
}, false); | |
volume.addEventListener("change", function () { | |
cartoon.volume = volume.value; | |
}, false); | |
mute.addEventListener("click", function () { | |
cartoon.muted = !cartoon.muted; | |
}, false); | |
cartoon.addEventListener("timeupdate", function () { | |
var value = 0; | |
if (cartoon.currentTime > 0) { | |
value = Math.floor((100 / cartoon.duration) * cartoon.currentTime); | |
} | |
progress.style.width = value + "%"; | |
}, false); | |
cartoon.addEventListener('play', function () { | |
playpause.title = "Pause"; | |
playpause.innerHTML = "Pause"; | |
}, false); | |
cartoon.addEventListener('pause', function () { | |
playpause.title = "Play"; | |
playpause.innerHTML = "Play"; | |
}, false); | |
}); | |
</script> | |
</head> | |
<body> | |
<video id="cartoon" width="320" height="240" controls> | |
<source src="video/PopeyeForPresident_qtp.mp4" type="video/mp4"> | |
<source src="video/PopeyeForPresident_qtp.ogv" type="video/ogg"> | |
Your browser does not support HTML5 MPG4 video. | |
</video> | |
<div id="controls"> | |
<button id="playpause" title="play">Play</button> | |
<input id="volume" min="0" max="1" step="0.1" type="range" /> | |
<button id="mute">Mute</button> | |
</div> | |
<div id="progressBar"><span id="progress"></span></div> | |
</body> | |
</html> |
Even More Events and API
There are more elements and settings. For a demo, see HTML5 Video Events and API
Here are some commonly used properties.
- currentTime. Returns the official playback position, in seconds. Can be set, to seek to the given time.
- playbackRate. Returns the current rate playback, where 1.0 is normal speed. Can be set, to change the rate of playback.
- volume. Returns the current playback volume multiplier, as a number in the range 0.0 to 1.0, where 0.0 is the quietest and 1.0 the loudest. Can be set, to change the volume multiplier.
- duration. Returns the difference between the earliest playable moment and the latest playable moment (not considering whether the data in question is actually buffered or directly seekable, but not including time in the future for infinite streams). Will return zero if there is no media
Here are some commonly used events.
- playing. Occurs when playback of media is ready to start after having been previously paused ended and when the media has stopped playing as it has finished.
- timeupdate. Occurs when the media’s current playback position has changed.
- play. Occurs when the media that was previously paused is no longer paused and playback has resumed.
- pause. Occurs when the
pause()
method has returned and the media has been paused. - volumechange. Occurs when the media’s
volume
ormuted
attribute has changed.
Full Screen Support
Ok. We know you want to empower your user to make the video go full screen.
As of the time of the writing of this post, HTML 5 does not provides a way to make a video full screen. But there is the a new Full Screen specification that includes requestFullScreen function that allows arbitrary elements (including <video>
elements) to be made full screen.
See caniuse.com to see if the browser you are targeting supports Full Screen API.
References
- Video on the Web
- Working with HTML5 multimedia components – Part 3: Custom controls
- HTML5 Video Events and API
- HTML5 Multimedia Develop and Design
Sample Code
Sample code is available in the DevDays GitHub repository. See https://github.com/devdays/html5-tutorials