Making Custom CSS3 Video Players With HTML5 and Javascript

The Media Element API

The media element API is a simple API that allows you to manipulate videos with simple Javascript commands. For example, normally when using the HTML5 video tags we type something like this:

?
1
2
3
4
< video id = "our-video" width = "600" height = "400" controls>
     < source src = "movie.mp4" type = "video/mp4" >
     < source src = "movie-hd.mp4" type = "video/mp4" >
</ video >

We have set controls in the video tag so this particular video will have controls (play, pause, etc). This is all well and good but sometimes we want to control the video with another (custom) player, or maybe we just want a link that makes the video play. To do this we use the Media Elements API. For example, lets say we have something like this:

?
1
< a href = "#" class = "play" >Click me to play the video!</ a >

Using the Media Elements API with jQuery we can write something as simple as this to make the video play:

?
1
$( '#our-video' )[0].play();
We’re using [0] here so we target a specific element (in the same way that document.getElementById() works!)

Easy, huh? Well it’s also possible to control a variety of video aspects with the media elements API, and you can create some pretty interesting things.

Functions

There are a bunch of features as part of the media elements API which can be used to control a video or how it is displayed. Here’s a bunch of things which become useful when creating a custom player:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$( '#our-video' )[0].play(); // Play the video
 
$( '#our-video' )[0].pause(); // Pause the video
 
$( '#our-video' )[0].volume = 1; // Sets volume, volume ranges from 0 to 1
 
$( '#our-video' )[0].currentTime; // Current video time
 
$( '#our-video' )[0].duration; // Duration of video
 
$( '#our-video' )[0].buffered; // Amount of video buffered in seconds
 
if ($( '#our-video' )[0].canPlayType( 'video/mp4' )) { .. // If the video can play this type of format
 
$( '#our-video' )[0].requestFullscreen; // (experimental) makes the video fullscreen

Using these simple functions and a few other tricks we’re going to combine all this to make a custom video player which you can change with just CSS.

Lets Get Started

First of all lets accustom ourselves with the HTML5 video tag. To create a new video element we just use the video tag. It’s best to use multiple video types since not all videos are supported by all browsers. Using just .webm and .mp4 will cover mostly every video type though. Miroprovides a simple method to convert files to .webm.

?
1
2
3
4
< video width = "600" height = "340" >
     < source src = "big-video.mp4" type = "video/mp4" >
     < source src = "movie.webm" type = "video/webm" >
</ video >

The CSS

CSS is what we’re going to use to style the video. This opens up a lot of possibilities since CSS is very easy to use, and changing the style of your video, therefore, becomes very easy. For this particular video style this is the CSS I’m going to be using, so go ahead and put it in your CSS file:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
body {
     font-size : 62.5% ;
}
 
.player {
     background : #2a2a2a ;
     box-sizing: border-box;
     border-radius: 5px ;
     height : 70px ;
     -moz-box-sizing: border-box;
     float : left ;
     font-family : Arial , sans-serif ;
     position : absolute ;
     padding : 0 ;
     bottom : 20px ;
     z-index : 2 ;
     opacity: 1 ;
     box-shadow: 0 0 10px rgba( 0 , 0 , 0 , 0.3 );
     -webkit-transition: opacity 0.3 s ease-in;
     transition: opacity 0.3 s ease-in;
     -moz-user-select: none ;
     -webkit-user-select: none ;
     user-select: none ;
}
 
.video {
     position : relative ;
}
 
.video:hover .player {
     opacity: 1 ;
}
 
.player .progress {
     width : 60% ;
     height : 20px ;
     border-radius: 5px ;
     background : #676767 ;
     box-shadow: inset 0 -5px 10px rgba( 0 , 0 , 0 , 0.1 );
     float : left ;
     cursor : pointer ;
     margin : 24px 0 0 0 ;
     padding : 0 ;
     position : relative ;
}
 
.player .progress-bar {
     background : #33b5d5 ;
     box-shadow: inset -30px 0px 69px -20px #89f6f5 ;
     border-radius: 5px ;
     height : 100% ;
     position : relative ;
     z-index : 999 ;
     width : 0 ;
}
 
.player .button-holder {
     position : relative ;
     left : 10px ;
}
 
.player .progress-button {
     background : #fff ;
     box-shadow: 0 0 20px rgba( 0 , 0 , 0 , 0.3 );
     border-radius: 30px ;
     width : 20px ;
     height : 20px ;
     position : absolute ;
     left : -20px ;
     text-decoration : overline ;
}
 
 
.player [class^= "buffered" ] {
     background : rgba( 255 , 255 , 255 , 0.1 );
     position : absolute ;
     top : 0 ;
     left : 30px ;
     height : 100% ;
     border-radius: 5px ;
     z-index : 1 ;
}
 
.player .play-pause {
     display : inline- block ;
     font-size : 3em ;
     float : left ;
     text-shadow : 0 0 0 #fff ;
     color : rgba( 255 , 255 , 255 , 0.8 );
     width : 10% ;
     padding : 17px 0 0 3% ;
     cursor : pointer ;
     font-variant : small-caps ;
}
 
.player .play, .player .pause-button {
     -webkit-transition: all 0.2 s ease-out;
}
 
.player .play .pause-button, .player .pause .play-button {
     display : none ;
}
 
.player .pause-button {
     padding : 5px 2px ;
     box-sizing: border-box;
     -moz-box-sizing: border-box;
     height : 34px ;
}
 
.player .pause-button span {
     background : #fff ;
     width : 8px ;
     height : 24px ;
     float : left ;
     display : block ;
}
 
.player .pause-button span:first-of-type {
     margin : 0 4px 0 0 ;
}
 
.player .time {
     color : #fff ;
     font-weight : bold ;
     font-size : 1.2em ;
     position : absolute ;
     right : 0 ;
     top : 24px ;
}
 
.player .stime, .ttime {
     color : #444 ;
}
.player .play:hover {
     text-shadow : 0 0 5px #fff ;
}
 
.player .play:active, .pause-button:active span {
     text-shadow : 0 0 7px #fff ;
}
 
 
.player .pause-button:hover span {
     box-shadow: 0 0 5px #fff ;
} .player .pause-button:active span {
     box-shadow: 0 0 7px #fff ;
}
 
 
.player .volume {
     position : relative ;
     float : left ;
     width : 8% ;
     margin : 0 0 0 4% ;
     height : 100% ;
}
 
.player .volume- icon {
     padding : 1.5% ;
     height : 100% ;
     cursor : pointer ;
     box-sizing: border-box;
     -moz-box-sizing: border-box;
     -webkit-transition: all 0.15 s linear;
}
 
.player .volume-icon-hover {
     background-color : #4f4f4f ;
}
 
.player .volume-holder {
     height : 100px ;
     width : 100% ;
     background : black ;
     position : absolute ;
     display : none ;
     background : #4f4f4f ;
     left : 0 ;
     border-radius: 5px 5px 0 0 ;
     top : -100px ;
}
 
.player .volume-bar-holder {
     background : #333 ;
     width : 20px ;
     box-shadow: inset 0px 0px 5px rgba( 0 , 0 , 0 , 0.3 );
     margin : 15px auto ;
     height : 80px ;
     border-radius: 5px ;
     position : relative ;
     cursor : pointer ;
}
 
.player .volume-button {
     background : #fff ;
     box-shadow: 0 0 20px rgba( 0 , 0 , 0 , 0.3 );
     border-radius: 30px ;
     width : 20px ;
     height : 20px ;
}
 
.player .volume-button-holder {
     position : relative ;
     top : -10px ;
}
 
.player .volume-bar {
     background : #33b5d5 ;
     box-shadow: inset -30px 0px 69px -20px #89f6f5 ;
     border-radius: 5px ;
     width : 100% ;
     height : 100% ;
     position : absolute ;
     bottom : 0 ;
}
 
.player .fullscreen {
     width : 12% ;
     cursor : pointer ;
     float : left ;
     height : 100% ;
}
 
.player .fullscreen a {
     width : 25px ;
     height : 20px ;
     border-radius: 3px ;
     background : #fff ;
     display : block ;
     position : relative ;
     top : 23px ;
     margin : 0px auto ;
}
 
.player .volume- icon span {
     width : 20% ;
     height : 13% ;
     background-color : #fff ;
     display : block ;
     position : relative ;
     z-index : 1 ;
     font-weight : bold ;
     top : 40% ;
     color : #fff ;
     left : 22% ;
}
 
.player .volume- icon span:before,
.player .volume- icon span:after {
     content : '' ;
     position : absolute ;
}
.player .volume- icon span:before {
     width : 0 ;
     height : 0 ;
     border : 1em solid transparent ;
     border-left : none ;
     border-right-color : #fff ;
     z-index : 2 ;
     top : -2px ;
     left : 10% ;
     margin-top : -40% ;
}
.player .volume- icon span:after {
     width : 2% ;
     height : 2% ;
     border : 1px solid #fff ;
     left : 190% ;
     border-width : 0px 0px 0 0 ;
     top : 5px ;
     border-radius: 0 50px 0 0 ;
     -webkit-transform: rotate( 45 deg);
     -moz-transform: rotate( 45 deg);
     -ms-transform: rotate( 45 deg);
     -o-transform: rotate( 45 deg);
      transform: rotate( 45 deg);
      font-variant : small-caps ;
  }
 
.player .v-change -11 span:after { border-width : 10px 10px 0 0 ; top : 0 ; }
.player .v-change -10 span:after { border-width : 9px 9px 0 0 ; top : 1px ; }
.player .v-change -9 span:after { border-width : 8px 8px 0 0 ; top : 1px ; }
.player .v-change -8 span:after { border-width : 7px 7px 0 0 ; top : 2px ; }
.player .v-change -7 span:after { border-width : 6px 6px 0 0 ; top : 2px ; }
.player .v-change -6 span:after { border-width : 5px 5px 0 0 ; top : 3px ; }
.player .v-change -5 span:after { border-width : 4px 4px 0 0 ; top : 3px ; }
.player .v-change -4 span:after { border-width : 3px 3px 0 0 ; top : 4px ; }
.player .v-change -3 span:after { border-width : 2px 2px 0 0 ; top : 4px ; }
.player .v-change -2 span:after { border-width : 1px 1px 0 0 ; top : 5px ; }
.player .v-change -1 span:after { border-width : 0px 0px 0 0 ; top : 5px ; }
 
.player .v-change -1 span:after {
     content : '+' ;
     -webkit-transform: rotate( 45 deg);
     font-size : 20px ;
     top : -6px ;
     left : 25px ;
}

jQuery

The easiest and most succinct way to go about doing this is to use jQuery and design our code as a plugin. Don’t forget to include the jQuery file! As with all jQuery plugins, make a new Javascript file and paste in the following:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(function($) {
 
     $.fn.videoPlayer = function(options) { // videoPlayer is the name of our plugin
         
                 
         var settings = { 
             playerWidth : '0.95', // Default is 95%
             videoClass : 'video'  // Video Class
         }
         
         // Extend the options so they work with the plugin
         if(options) {
             $.extend(settings, options);
         }
         
         
         // For each so that we keep chainability.
         return this.each(function() {  
 
                      // Code goes here
 
         });
     
     }
     
})(jQuery);

I’ve added a few customizable options (when you run this plugin you’ll be able to change the options to whatever you want). These include the width of the player for styling purposes (by default 0.95 or95%) and the video class (in case you need to change it because of clashes). All of our code is going to go inside the return this.each(function() { }); brackets.

Now the first thing we want to do is check that the video meta data is ready to run. In some cases this will take a moment to load, so if we don’t check this we’ll end up loading the video player without any data (that wouldn’t work!). We’re also going to set some basic variables, the purpose of which will become more apparent later on.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$( this )[0].addEventListener( 'loadedmetadata' , function () {
 
     // Basic Variables
     var $ this = $( this );
     var $settings = settings;
     
     // Wrap the video in a div with the class of your choosing
     $ this .wrap( '<div class="' +$settings.videoClass+ '"></div>' );
     
 
     // Select the div we just wrapped our video in for easy selection.
     var $that = $ this .parent( '.' +$settings.videoClass);
     
     // Some other misc variables to check when things are happening
     var $mclicking = false ,
         $vclicking = false ,
         $vidhover = false ,
         $volhover = false ,
         $playing = false ,
         $drop = false ,
         $begin = false ,
         $draggingProgess = false ,
         $storevol, 
         x = 0,
         y = 0,
         vtime = 0,
         updProgWidth = 0,
         volume = 0;
        

Next you want to create the structure of the player. This can be altered if you wish. We’ll also define some more variables and change the width of the player.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// The Structure of our video player
{
 
$( '<div class="player">'
      + '<div class="play-pause play">'
        + '<span class="play-button">&#9658;</span>'
        + '<div class="pause-button">'
          + '<span> </span>'
              + '<span> </span>'
        + '</div>'
      + '</div>'
      + '<div class="progress">'
        + '<div class="progress-bar">'
          + '<div class="button-holder">'
            + '<div class="progress-button"> </div>'
          + '</div>'
        + '</div>'
        + '<div class="time">'
          + '<span class="ctime">00:00</span>'
          + '<span class="stime"> / </span>'
          + '<span class="ttime">00:00</span>'
        + '</div>'
      + '</div>'
      + '<div class="volume">'
        + '<div class="volume-holder">'
          + '<div class="volume-bar-holder">'
            + '<div class="volume-bar">'
              + '<div class="volume-button-holder">'  
                + '<div class="volume-button"> </div>'
              + '</div>'
            + '</div>'
          + '</div>'
        + '</div>'
        + '<div class="volume-icon v-change-0">'
          + '<span> </span>'
        + '</div>'
      + '</div>'
      + '<div class="fullscreen"> '
        + '<a href="#"> </a>'
      + '</div>'
    + '</div>' ).appendTo($that);
 
}
 
 
// Set the width of the video
$videoWidth = $ this .width();
$that.width($videoWidth+ 'px' );
 
// Set width of the player based on previously noted settings
$that.find( '.player' ).css({ 'width' : ($settings.playerWidth*100)+ '%' , 'left' : ((100-$settings.playerWidth*100)/2)+ '%' });
 
 
// Video information
var $spc = $( this )[0], // Specific video
     $duration = $spc.duration, // Video Duration
     $volume = $spc.volume, // Video volume
     currentTime;
 
// The width of the progress bar
var progWidth = $that.find( '.progress' ).width();

Next lets start defining some functions. The first function we’re going to define is for buffering, so the user can see what sections of the video is buffered. The second is for time setting, so the time will increase correctly. The timing function is going to be run every time the current time is updated. I’ve commented in the code so you can see exactly what is happening.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
var bufferLength = function () {
 
     // The buffered regions of the video
     var buffered = $spc.buffered;
     
     // Rest all buffered regions everytime this function is run
     $that.find( '[class^=buffered]' ).remove();
     
     // If buffered regions exist
     if (buffered.length > 0) {
             
         // The length of the buffered regions is i
         var i = buffered.length;
             
         while (i--) {
             // Max and min buffers
             $maxBuffer = buffered.end(i);
             $minBuffer = buffered.start(i);
                     
             // The offset and width of buffered area               
             var bufferOffset = ($minBuffer / $duration) * 100;         
             var bufferWidth = (($maxBuffer - $minBuffer) / $duration) * 100;
                             
             // Append the buffered regions to the video
             $( '<div class="buffered"></div>' ).css({ "left" : bufferOffset+ '%' , 'width' : bufferWidth+ '%' }).appendTo($that.find( '.progress' ));
             
         }
     }
}
 
// Run the buffer function
bufferLength();
 
// The timing function, updates the time.
var timeUpdate = function ($ignore) {
     
     // The current time of the video based on progress bar position
     var time = Math.round(($( '.progress-bar' ).width() / progWidth) * $duration);
     
     // The 'real' time of the video
     var curTime = $spc.currentTime;
     
     // Seconds are set to 0 by default, minutes are the time divided by 60
     // tminutes and tseconds are the total mins and seconds.
     var seconds = 0,
         minutes = Math.floor(time / 60),
         tminutes = Math.round($duration / 60),
         tseconds = Math.round(($duration) - (tminutes*60));
     
     // If time exists (well, video time)
     if (time) {
         // seconds are equal to the time minus the minutes
         seconds = Math.round(time) - (60*minutes);
         
         // So if seconds go above 59
         if (seconds > 59) {
             // Increase minutes, reset seconds
             seconds = Math.round(time) - (60*minutes);
             if (seconds == 60) {
                 minutes = Math.round(time / 60);
                 seconds = 0;
             }
         }
         
     }
     
     // Updated progress width
     updProgWidth = (curTime / $duration) * progWidth
     
     // Set a zero before the number if its less than 10.
     if (seconds < 10) { seconds = '0' +seconds; }
     if (tseconds < 10) { tseconds = '0' +tseconds; }
     
     // A variable set which we'll use later on
     if ($ignore != true ) {
         $that.find('.progress-bar ').css({' width ' : updProgWidth+' px '});
         $that.find(' .progress-button ').css({' left ' : (updProgWidth-$that.find(' .progress-button ').width())+' px '});
     }
     
     // Update times
     $that.find(' .ctime ').html(minutes+' : '+seconds)
     $that.find(' .ttime ').html(tminutes+' : '+tseconds);
 
     // If playing update buffer value
     if($spc.currentTime > 0 && $spc.paused == false && $spc.ended == false) {
         bufferLength();
     }
     
}
 
// Run the timing function twice, once on init and again when the time updates.
timeUpdate();
$spc.addEventListener(' timeupdate', timeUpdate);

Next the play button! We’re going to add and remove CSS classes to make the play change to a pause button when clicked. We’ll also set a variable to check if the video is playing, which we will use later in the code:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// When the user clicks play, bind a click event   
$that.find( '.play-pause' ).bind( 'click' , function () {
     
     // Set up a playing variable
     if ($spc.currentTime > 0 && $spc.paused == false && $spc.ended == false ) {
         $playing = false ;
     } else { $playing = true ; }
     
     // If playing, etc, change classes to show pause or play button
     if ($playing == false ) {
         $spc.pause();
         $( this ).addClass( 'play' ).removeClass( 'pause' );
         bufferLength();
     } else {
         $begin = true ;
         $spc.play();
         $( this ).addClass( 'pause' ).removeClass( 'play' );
     }              
     
});

One of the most complicated parts of this code is the progress slider. First off we need to check when the user clicks on the progress bar and then set a variable telling us that’s what’s happening. Then when the user moves the mouse we’ll be able to adjust it so it slides appropriately. We’re going to use the same process for the volume slider, so I’ve included it here too, as well as an animation function for the volume icon, as well as a way to check if the user is hovering over the volume icon using the jQuery hover() function.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Bind a function to the progress bar so the user can select a point in the video
$that.find( '.progress' ).bind( 'mousedown' , function (e) {
     
     // Progress bar is being clicked
     $mclicking = true ;
     
     // If video is playing then pause while we change time of the video
     if ($playing == true ) {
         $spc.pause();
     }
     
     // The x position of the mouse in the progress bar
     x = e.pageX - $that.find( '.progress' ).offset().left;
     
     // Update current time
     currentTime = (x / progWidth) * $duration;
     
     $spc.currentTime = currentTime;
     
});
 
// When the user clicks on the volume bar holder, initiate the volume change event
$that.find( '.volume-bar-holder' ).bind( 'mousedown' , function (e) {
     
     // Clicking of volume is true
     $vclicking = true ;
     
     // Y position of mouse in volume slider
     y = $that.find( '.volume-bar-holder' ).height() - (e.pageY - $that.find( '.volume-bar-holder' ).offset().top);
     
     // Return false if user tries to click outside volume area
     if (y < 0 || y > $( this ).height()) {
         $vclicking = false ;
         return false ;
     }
     
     // Update CSS to reflect what's happened
     $that.find('.volume-bar ').css({' height ' : y+' px '});
     $that.find(' .volume-button ').css({' top ' : (y-($that.find(' .volume-button ').height()/2))+' px '});
      
     // Update some variables
     $spc.volume = $that.find(' .volume-bar ').height() / $(this).height();
     $storevol = $that.find(' .volume-bar ').height() / $(this).height();
     $volume = $that.find(' .volume-bar ').height() / $(this).height();
     
     // Run a little animation for the volume icon.
     volanim();
     
});
 
// A quick function for binding the animation of the volume icon
var volanim = function() {
 
     // Check where volume is and update class depending on that.
     for(var i = 0; i < 1; i += 0.1) {
                     
         var fi = parseInt(Math.floor(i*10)) / 10;
         var volid = (fi * 10)+1;
         
         if($volume == 1) {
             if($volhover == true) {
                 $that.find(' .volume-icon ').removeClass().addClass(' volume-icon volume-icon-hover v-change-11 ');
             } else {
                 $that.find(' .volume-icon ').removeClass().addClass(' volume-icon v-change-11 ');
             }
         }
         else if($volume == 0) {
             if($volhover == true) {
                 $that.find(' .volume-icon ').removeClass().addClass(' volume-icon volume-icon-hover v-change-1 ');
             } else {
                 $that.find(' .volume-icon ').removeClass().addClass(' volume-icon v-change-1 ');
             }
         }
         else if($volume > (fi-0.1) && volume < fi && !$that.find(' .volume-icon ').hasClass(' v-change- '+volid)) {
             if($volhover == true) {
                 $that.find(' .volume-icon ').removeClass().addClass(' volume-icon volume-icon-hover v-change- '+volid);
             } else {
                 $that.find(' .volume-icon ').removeClass().addClass(' volume-icon v-change- '+volid);  
             }
         }      
         
     }
}
// Run the volanim function
volanim();
 
// Check if the user is hovering over the volume button
$that.find(' .volume').hover( function () {
     $volhover = true ;
}, function () {
     $volhover = false ;
});

Next we have to do the actual mouse moving event. There are a bunch of things that depend on mouse move so the function is quite long. For instance, if the user is dragging the mouse while holding the progress bar, the progress bar should slide. Similarly, so should the volume bar. On top of that, if the user is moving the mouse and the video is already playing, the player should disappear so it isn’t a distraction to the actual video. I’ve included the entire function below, commented so you can see what’s going on. I’ve also included a function that fixes a few problems with the play and pause button, so the correct icon is always displaying.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// For usability purposes then bind a function to the body assuming that the user has clicked mouse
// down on the progress bar or volume bar
$( 'body, html' ).bind( 'mousemove' , function (e) {
     
     // Hide the player if video has been played and user hovers away from video
     if ($begin == true ) {
         $that.hover( function () {
             $that.find( '.player' ).stop( true , false ).animate({ 'opacity' : '1' }, 0.5);
         }, function () {
             $that.find( '.player' ).stop( true , false ).animate({ 'opacity' : '0' }, 0.5);
         });
     }
     
     // For the progress bar controls
     if ($mclicking == true ) {   
         
         // Dragging is happening
         $draggingProgress = true ;
         // The thing we're going to apply to the CSS (changes based on conditional statements);
         var progMove = 0;
         // Width of the progress button (a little button at the end of the progress bar)
         var buttonWidth = $that.find('.progress-button ').width();
         
         // Updated x posititon the user is at
         x = e.pageX - $that.find(' .progress ').offset().left;
         
         // If video is playing
         if($playing == true) {
             // And the current time is less than the duration              
             if(currentTime < $duration) {       
                 // Then the play-pause icon should definitely be a pause button
                 $that.find(' .play-pause ').addClass(' pause ').removeClass(' play ');
             }
         }
         
         
         if(x < 0) { // If x is less than 0 then move the progress bar 0px
             progMove = 0;
             $spc.currentTime = 0;
         }
         else if(x > progWidth) { // If x is more than the progress bar width then set progMove to progWidth
             $spc.currentTime = $duration;
             progMove = progWidth;  
         }
         else { // Otherwise progMove is equal to the mouse x coordinate
             progMove = x;
             currentTime = (x / progWidth) * $duration;
             $spc.currentTime = currentTime;
         }
         
         // Change CSS based on previous conditional statement
         $that.find(' .progress-bar ').css({' width ' : $progMove+' px '});
         $that.find(' .progress-button ').css({' left ' : ($progMove-buttonWidth)+' px '});
         
     }
     
     // For the volume controls
     if($vclicking == true) {   
         
         // The position of the mouse on the volume slider
         y = $that.find(' .volume-bar-holder ').height() - (e.pageY - $that.find(' .volume-bar-holder ').offset().top);
         
         // The position the user is moving to on the slider.
         var volMove = 0;
         
         // If the volume holder box is hidden then just return false
         if($that.find(' .volume-holder ').css(' display ') == ' none ') {
             $vclicking = false;
             return false;
         }
         
         // Add the hover class to the volume icon
         if(!$that.find(' .volume-icon ').hasClass(' volume-icon-hover ')) {
             $that.find(' .volume-icon ').addClass(' volume-icon-hover ');
         }
         
         
         if(y < 0 || y == 0) { // If y is less than 0 or equal to 0 then volMove is 0.
             
             $volume = 0;
             volMove = 0;
             
             $that.find(' .volume-icon ').removeClass().addClass(' volume-icon volume-icon-hover v-change-11 ');
             
         } else if(y > $(this).find(' .volume-bar-holder ').height() || (y / $that.find(' .volume-bar-holder ').height()) == 1) { // If y is more than the height then volMove is equal to the height
             
             $volume = 1;
             volMove = $that.find(' .volume-bar-holder ').height();
             
             $that.find(' .volume-icon ').removeClass().addClass(' volume-icon volume-icon-hover v-change-1 ');
             
         } else { // Otherwise volMove is just y
         
             $volume = $that.find(' .volume-bar ').height() / $that.find(' .volume-bar-holder ').height();
             volMove = y;
             
         }
     
         // Adjust the CSS based on the previous conditional statmeent
         $that.find(' .volume-bar ').css({' height ' : volMove+' px '});
         $that.find(' .volume-button ').css({' top ' : (volMove+$that.find(' .volume-button ').height())+' px '});
         
         // Run the animation function
         volanim();
         
         // Change the volume and store volume
         // Store volume is the volume the user last had in place
         // in case they want to mute the video, unmuting will then
         // return the user to their previous volume.
         $spc.volume = $volume;
         $storevol = $volume;
         
         
     }
     
     // If the user hovers over the volume controls, then fade in or out the volume
     // icon hover class
     
     if($volhover == false) {
         
         $that.find(' .volume-holder ').stop(true, false).fadeOut(100);
         $that.find(' .volume-icon ').removeClass(' volume-icon-hover ');   
         
     }
     
     else {
         $that.find(' .volume-icon ').addClass(' volume-icon-hover ');
         $that.find(' .volume-holder ').fadeIn(100);          
     }
     
         
});
 
// When the video ends the play button becomes a pause button
$spc.addEventListener(' ended ', function() {
     
     $playing = false;
     
     // If the user is not dragging
     if($draggingProgress == false) {
         $that.find(' .play-pause ').addClass(' play ').removeClass(' pause');
     }
     
});

Next is a little function that checks if the user is clicking their mouse down onto the volume icon, and if so, whether to mute the video or not. We use our stored volume so we can set the volume to the previous volume should the user unmute the video.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// If the user clicks on the volume icon, mute the video, store previous volume, and then
// show previous volume should they click on it again.
$that.find( '.volume-icon' ).bind( 'mousedown' , function () {
     
     $volume = $spc.volume; // Update volume
     
     // If volume is undefined then the store volume is the current volume
     if ( typeof $storevol == 'undefined' ) {
          $storevol = $spc.volume;
     }
     
     // If volume is more than 0
     if ($volume > 0) {
         // then the user wants to mute the video, so volume will become 0
         $spc.volume = 0;
         $volume = 0;
         $that.find( '.volume-bar' ).css({ 'height' : '0' });
         volanim();
     }
     else {
         // Otherwise user is unmuting video, so volume is now store volume.
         $spc.volume = $storevol;
         $volume = $storevol;
         $that.find( '.volume-bar' ).css({ 'height' : ($storevol*100)+ '%' });
         volanim();
     }
     
     
});

Next, a quick little function that resets everything when the user lets go of the mouse button:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// If the user lets go of the mouse, clicking is false for both volume and progress.
// Also the video will begin playing if it was playing before the drag process began.
// We're also running the bufferLength function
$('body, html ').bind(' mouseup', function (e) {
     
     $mclicking = false ;
     $vclicking = false ;
     $draggingProgress = false ;
     
     if ($playing == true ) { 
         $spc.play();
     }
     
     bufferLength();
     
     
});

Finally we’re going to add a button that allows us to enable fullscreen mode. If the browser doesn’t support fullscreen the button will not be displayed, otherwise we just request it for every browser until one works.

Fullscreen is not supported by every browser. In the below example the fullscreen icon will not appear if the browser doesn’t support it.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
                 
                 // Check if fullscreen supported. If it's not just don't show the fullscreen icon.
                 if (!$spc.requestFullscreen && !$spc.mozRequestFullScreen && !$spc.webkitRequestFullScreen) {
                     $( '.fullscreen' ).hide();
                 }
                 
                 // Requests fullscreen based on browser.
                 $( '.fullscreen' ).click( function () {
                 
                     if ($spc.requestFullscreen) {
                         $spc.requestFullscreen();
                     }
                 
                     else if ($spc.mozRequestFullScreen) {
                         $spc.mozRequestFullScreen();
                     }
                     
                     else if ($spc.webkitRequestFullScreen) {
                         $spc.webkitRequestFullScreen();
                     }
                 
                 });
                 
                 
                 
             });
             
         });
     
     }
     
})(jQuery);

文章出处:https://www.inserthtml.com/2013/03/custom-html5-video-player/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值