Custom HTML5 Video Controls

Custom HTML5 Video Controls with jQuery and CSS

Written by Kenny on March 11, 2012 HTML5
This post will teach you how to build own custom HTML5 video controls using jQuery rather than using native browser HTML5 video controls.

Custom HTML5 Video Controls with jQuery and CSS

HTML5 video element, one of the most popular features in HTML5. It is now already supported by most modern browsers, and even so for IE9. However, each browser provides native browser video controls. In order to have a consistent HTML5 video controls across all browsers, we have to integrate own custom HTML5 video controls rather than using default controls.

Custom HTML5 Video Controls

Actually, it is not hard to have custom HTML5 video controls. In this post I’m going to show you the way to build your own custom HTML5 video controls using jQuery. Hope you will find it useful!

 

HTML5 Video Element Basic Markup

Before we get started, let’s recall for HTML5 video basic markup.

<video id="myVideo" controls poster="video.jpg" width="600" height="400" >
	<source src="video.mp4" type="video/mp4" />
	<source src="video.webm" type="video/webM" />
	<source src="video.ogv" type="video/ogg" />
	<p>Your browser does not support the video tag.</p>
</video>

It is best practice to include three video formats – MP4, WebM, and Ogg as source elements in order to have your HTML5 video works cross browsers. It is also advisable to put some text as fallback inside video element, in case user browser doesn’t support HTML5 video. Of course, you might use Flash as fallback as well!

If you having problem to encode your video to the HTML5 formats mentioned above, try Miro Converter, it support for both Window and Mac.

#Tips: Due to a bug in the iPad, you have to put MP4 format as the first source if you wish HTML5 video works in iPad.

 

Get Started with Custom HTML5 Video Controls

Luckily, HTML5 media elements (audio and video) support for media elements API, which we can access using JavaScript and use them to wire up our HTML5 video controls.

Before get started with coding, let me briefly explain about jQuery video element targeting.

In JavaScript we use getElementById('videoID') to target the video element. As result, we will get a DOM object. However, this is not equivalent to jQuery $('#videoID') targeting which will return a jQuery object, not a DOM object. That’s why we can’t directly using jQuery selector to call/use HTML5 video DOM attributes and functions before convert it to DOM object.

//return a DOM object
var video = document.getElementById('videoID'); //or
var video = $('#videoID').get(0); //or
var video = $('#videoID')[0];

//return a jQuery object
var video = $('#videoID');

 

Video Play/Pause Controls

OK, that’s all for introduction. Let’s start the coding right now. First, we’ll create a simple Play/Pause control over our video.

<div class="control">
	<a href="#" class="btnPlay">Play/Pause</a>
</div>

We can easily control video status using HTML5 video DOM functions, which are .play() and .pause().

//Play/Pause control clicked
$('.btnPlay').on('click', function() {
	if(video[0].paused) {
		video[0].play();
	}
	else {
		video[0].pause();
	}
	return false;
};

 

Display Video Current Playback Time and Duration

HTML5 video also support for video playback. Hereby we are going to display video current playback time and duration.

<div class="progressTime">
	Current play time: <span class="current"></span>
	Video duration: <span class="duration"></span>
</div>

In order to get HTML5 video duration, we have to make sure the video metadata is loaded. We could easily detect it using HTML5 video loadedmetadata event.

As for current video playback time, we can use HTML5 video timeupdate events to keep tracks of it.

//get HTML5 video time duration
video.on('loadedmetadata', function() {
	$('.duration').text(video[0].duration);
});

//update HTML5 video current play time
video.on('timeupdate', function() {
	$('.current').text(video[0].currentTime);
});

 

Video Progress Bar

Since we are able to get video current playback time and video duration, why not convert these data into great looking video progress bar?

<style>
.progressBar
{
	position: relative;
	width: 100%;
	height: height:10px;
	backgroud-color: #000;
}
.timeBar
{
	position: absolute;
	top: 0;
	left: 0;
	width: 0;
	height: 100%;
	background-color: #ccc;
}
</style>
<div class="progressBar">
	<div class="timeBar"></div>
</div>

Below shown the formula for conversion of video duration and video current playback time into progress bar with help of JavaScript.

//get HTML5 video time duration
video.on('loadedmetadata', function() {
	$('.duration').text(video[0].duration));
});

//update HTML5 video current play time
video.on('timeupdate', function() {
	var currentPos = video[0].currentTime; //Get currenttime
	var maxduration = video[0].duration; //Get video duration
	var percentage = 100 * currentPos / maxduration; //in %
	$('.timeBar').css('width', percentage+'%');
});

Done!!? Not yet! We have to make this progress bar seekable and dragable. In this case, we have to use mousedown, mouseup and mousemove listeners and bind them to progress bar. Of couse, if you want, you might replace it with slider as well!

var timeDrag = false;	/* Drag status */
$('.progressBar').mousedown(function(e) {
	timeDrag = true;
	updatebar(e.pageX);
});
$(document).mouseup(function(e) {
	if(timeDrag) {
		timeDrag = false;
		updatebar(e.pageX);
	}
});
$(document).mousemove(function(e) {
	if(timeDrag) {
		updatebar(e.pageX);
	}
});

//update Progress Bar control
var updatebar = function(x) {
	var progress = $('.progressBar');
	var maxduration = video[0].duration; //Video duraiton
	var position = x - progress.offset().left; //Click pos
	var percentage = 100 * position / progress.width();

	//Check within range
	if(percentage > 100) {
		percentage = 100;
	}
	if(percentage < 0) {
		percentage = 0;
	}

	//Update progress bar and video currenttime
	$('.timeBar').css('width', percentage+'%');
	video[0].currentTime = maxduration * percentage / 100;
};

Done!

 

Showing Buffering Bar

Yet, we can have a buffering bar for our HTML5 video. HTML5 video progress event will be fired when user browser loads data. It will come in handy in order to create video buffering bar. However, latest Chrome seems to have bug with progress event. Therefore, we will replace it with JavaScript setTimeout() function.

<style>
.progressBar {
	position: relative;
	width: 100%;
	height: height:10px;
	backgroud-color: #000;
}
.bufferBar {
	position: absolute;
	top: 0;
	left: 0;
	width: 0;
	height: 100%;
	background-color: #ccc;
}
</style>
<div class="progressBar">
	<div class="bufferBar"></div>
</div>

HTML5 video buffered attributes will return an object of ranges which are already buffered. Hence, we will use the last value of buffered data.

//loop to get HTML5 video buffered data
var startBuffer = function() {
	var maxduration = video[0].duration;
	var currentBuffer = video[0].buffered.end(0);
	var percentage = 100 * currentBuffer / maxduration;
	$('.bufferBar').css('width', percentage+'%');

	if(currentBuffer < maxduration) {
		setTimeout(startBuffer, 500);
	}
};
setTimeout(startBuffer, 500);

 

Volume Controls for Video

Now, we will include volume controls to our video as well. There are two different volume controls will be added, which are mute button control and volume bar control.

<a href="#" class="muted" >Mute/Unmute</a>
<div class="volumeBar">
	<div class="volume"></div>
</div>

Here, we will change the video’s volume and volume bar’s width when user click on the volume bar control. And mute the video when mute control clicked. Well, you might make your volume bar dragable also!


//Mute/Unmute control clicked
$('.muted').click(function() {
	video[0].muted = !video[0].muted;
	return false;
});

//Volume control clicked
$('.volumeBar').on('mousedown', function(e) {
	var position = e.pageX - volume.offset().left;
	var percentage = 100 * position / volume.width();
	$('.volumeBar').css('width', percentage+'%');
	video[0].volume = percentage / 100;
});

 

Fast Forward, Slow Motion, and Rewind Controls

Yes, HTML5 video supports change of playback speed. We can change the video playback speed by changing the video playbackrate attribute.

<div class="control">
	<a href="#" class="ff">Fast Forward</a>
	<a href="#" class="rw">Rewind</a>
	<a href="#" class="sl">Slow Motion</a>
</div>

Unfortunately, Firefox doesn’t support for playbackrate attribute yet. But partly for Chrome (doesn’t support negative value, which is rewind). So far only Safari fully supported.


//Fast forward control
$('.ff').on('click', function() {
	video[0].playbackrate = 3;
	return false;
});

//Rewind control
$('.rw').on('click', function() {
	video[0].playbackrate = -3;
	return false;
});

//Slow motion control
$('.sl').on('click', function() {
	video[0].playbackrate = 0.5;
	return false;
});

 

What’s More in HTML5 Video?

What’s more? HTML5 video have lots more of events and attributes which can be used to control video playback. I would not cover all but useful HTML5 video events here. Still, you can check out the HTML5 video DOM attributes and events list.

HTML5 video ended Event
- Event fired when video has ended.

HTML5 video canplay Event
- Event fired when video can be played, but the buffering process still ongoing.

HTML5 video canplaythrough Event
- Event fired when whole video can be played.

HTML5 video seeking Event
- Event fired when browser seeks for a position of video.

HTML5 video waiting Event
- Event fired when waiting for more data to play the video.

 

What Else?

What else? Other than main controls, you could have some extra controls over your video. In below are some extra cool controls which can be added to your video as well.

First, a fullscreen control for video.


$('.fullscreen').on('click', function() {
	//For Webkit
	video[0].webkitEnterFullscreen();

	//For Firefox
	video[0].mozRequestFullScreen();

	return false;
});

Next will be light off/on control.


$('.btnLight').click(function() {
	if($(this).hasClass('on')) {
		$(this).removeClass('on');
		$('body').append('<div class="overlay"></div>');
		$('.overlay').css({
			'position':'absolute',
			'width':100+'%',
			'height':$(document).height(),
			'background':'#000',
			'opacity':0.9,
			'top':0,
			'left':0,
			'z-index':999
		});
		$('#myVideo').css({
			'z-index':1000
		});
	}
	else {
		$(this).addClass('on');
		$('.overlay').remove();
	}
	return false;
});

 

Your Turn!

It is your turn now! You could have more controls such as video expandable control, HD video control, and etc. Since the possibility is infinity with jQuery. Just to be creative. =)

If you feel lazy to create custom video controls, still you can get existing jQuery plugins for HTML5 video to do the rest for you!


» This Might Interest You «

User Feedbacks (28) Share Your!

  • Iron Hoang

    Greate tutorial !

    I have a question.
    How about subtitle and Resolution?
    How can i control them?

    3 weeks ago! Reply
  • Nathan

    Thanks for the article.

    I noticed that some of the CSS in the video progress bar section is incorrect in your tut.

    height: height:10px;
    backgroud-color: #000; (background spelt incorrectly)

    2 months ago! Reply
  • Arnaud

    Hi guys,

    i am having an issue and i don’t get why…

    here is the line in my console
    Uncaught IndexSizeError: Failed to execute ‘end’ on ‘TimeRanges’: The index provided (0) is greater than or equal to the maximum bound (0).

    tks in advance

    ab

    3 months ago! Reply
    • eleen

      window.onload = function(){
      alert(video.duration);
      }

      3 weeks ago! Reply
  • Carey

    I really appreciate you sharing the HTML5 custom controls scripts.

    I’m having one problem with making use of them though. It works great on a desktop computer, but when displaying the same webpage on a touch screen mobile device, after pressing the play icon the controls never fade away to reveal the video screen. As if the pointer was being left in the center of the video.

    Is there any way to solve this so the controls will fade away to reveal the video on a touch screen mobile device?

    Thanks.

    7 months ago! Reply
    • Kev

      Im not sure what the best practice is, but you could set up a function to sniff out what the browser/OS is, and if its mobile to execute a fade() function when its full screened.

      I dont know jQuery so i cant tell you the exact code. Sorry.

      7 months ago! Reply
  • Kev

    Your custom controls do not appear when the video is full screened because you are using the video object’s full screen function and it does not apply to the controls element.

    9 months ago! Reply
  • Mensah Hughes Samuel

    can it play multiple videos e.g. Youtube Video Playlist. With Next and Previous butons

    11 months ago! Reply
  • Mensah Hughes Samuel

    can u play multiple videos e.g. Youtube Video Playlist.

    11 months ago! Reply
  • Tim

    Awesome Tutorial, thanks! I am trying to use the slow motion and fast forward to create controls which allow for a next frame and previous frame stepper options. I have been trying to slow it down based on the FPS, which I am calculating manually at 30 (0.03) but I cant seem to get it to work, and it is a continue play back instead of a stepper. Do you have any other ideas on how I could get this to work.

    Any help would be much appreciated!!

    Thanks heaps
    Tim

    12 months ago! Reply
  • Brian

    Awesome tutorial, thank you for sharing!!!

    1 year ago! Reply
  • Great tutorial! Maybe it functions in the context of a bigger code block, but I think there is a typo on this line

    $(‘.duration’).text(video[0].duration));

    and it should lose 1 closinig paren?

    $(‘.duration’).text(video[0].duration);

    b.

    2 years ago! Reply
    • Hi Bradley,

      Thanks and corrected!

      2 years ago! Reply
  • rinku

    thanks brother its very helpful for me

    2 years ago! Reply
  • Great; but doesn’t work on iPad :(

    2 years ago! Reply
  • Nice Bro ….

    2 years ago! Reply
  • Ashish KHokhar

    Hi There,

    I am trying to capture the current video frame with the help of the canvas but its working on the onclick event not on the mouseover event .Any help would be appreciated.

    Thanks

    2 years ago! Reply
  • Pablo

    So much errors on tutorial code, so much missing code and the example demo is so much different, bad tutorial, nice try.

    2/5 grade.

    2 years ago! Reply
  • We have downloaded html5-video.zip. After unzip, we use demo1 and demo2 on I-pad. Video does not play on I-Pad. Please provide the resolution. This is very urgent.

    2 years ago! Reply
  • We download html5-video.zip. After unzip, we use demo1 and demo2 on I-pad. Video does not play. Please provide the resolution. I need very urgent.

    2 years ago! Reply
  • Peter

    I have tried to view your 2 demos in IE9 but get nothing but the loading gif. All other browsers are fine – Firefox, Safar and Opera. The videos will not play in Internet Explorer which is strange because a standard html5 video without custom controls plays just fine, and other html5 video libraries I have tried do not have this problem with Internet Explorer at all. So can you please fix it? I am using version 9.0.8112.16421 of IE. Thanks

    2 years ago! Reply
  • tonjo

    Kenny,

    Great work !

    Thoughts on enabling rtmp with FMS for this above?

    2 years ago! Reply
  • Thanks Kenny. I am using the video.js file included in the zip folder, and I’ve tried adding your selected element targeting code to the top of the script document, and removing the line:

    var video = $(‘#myVideo’);

    but keeping:

    $(document).ready(function(){

    This doesn’t seem to work, removing those two lines (or that var) altogether doesn’t seem to work for me either.

    Could you tell me where inside the video.js file your selected element code should go possibly? I am linking to the video.js file in the of my HTML document just as I would for any JQuery plug-in.

    Forgive my confusion, I’m still learning as I mentioned!

    Thanks again.

    2 years ago! Reply
    • Hi Brad, it’s not as easy as just by replacing few lines of script to have the video.js works for multiple videos, since the way I code the fundamental of video.js is more for tutorial-based, not in plugin-based.

      In order to have video.js works for multiple videos, a lot of changes needed. One of the parts is to get the targeted video element inside control’s functions/events itself. As I mentioned in previous comment, is the way of getting targeted video element for ‘Play/Pause‘ control. Of course, you have to do the same thing for other video controls as well.

      Anyway, I will try to make another Demo for multiple videos targeting. Let’s stay connected!

      Meanwhile, this article worth checking out -> http://dev.opera.com/articles/view/custom-html5-video-player-with-css3-and-jquery/

      2 years ago! Reply
  • Great job on these! I am not sure I understand if it’s possible to have multiple videos on the same web page using the Demo 1 skin, as I’m a bit new to JQuery scripting. I think I understand the lack of JQuery being able to call an ElementID in the DOM, being the issue – if that’s correct/makes sense.

    Could you explain how someone could use this video skin/player more than once on a page? I don’t see the DOM conversion part (top) in the Javascript file?

    I assume you have to create different “myVideo” ID’s and then reference each one in the markup – again excuse my ignorance here.

    Thanks for the great stuff!

    2 years ago! Reply
    • Hi Brad, thanks for comment! Yes, it is possible to have multiple videos on the same page with custom controls, but not from the script in Demo, since the demo script is more for reference purposes.

      Still, you can use them for multiple videos but require some amendments to the script.

      1. Add the video controls using script. (Of course you can still add the controls one by one for each video XD)
      2. Get rid of using global variable targeting. Instead we should use selected element targeting. For example:

      //Play/Pause control clicked
      $('.btnPlay').on('click', function() {
      	//get video element based on selected control, no more global variable
      	var video = $(this).parents('.videoContainer').find('.myVideo');
      	
      	//conversion of jQuery object to DOM object using video[0]
      	if(video[0].paused) {
      		video[0].play();
      	}
      	else {
      		video[0].pause();
      	}
      	return false;
      };
      

      Have fun!

      2 years ago! Reply

Leave a Feedback

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>