Creating and customizing an HTML5 video player with CSS
Tags: css, html, beginners
Published: 2022-09-05 04:08:39

HTML5 provides a default video player for rendering video assets. However, with CSS we can tweak and customize the styling of the video player to suit our taste or match our website theme or style.

In this article, I will show you how to customize an HTML5 video player with CSS so that you can create a video player that blends seamlessly into the design of your next app. 

In order to follow along in this article, you should have a working knowledge of HTML, CSS, and JavaScript, in addition to a working understanding of DOM manipulation and event listening.

I also recommend you use the latest version of your browser or a Chrome browser for the best performance.

# What is an HTML5 video player?
An [HTML5 video player](https://en.wikipedia.org/wiki/HTML5_video) is an HTML5 streaming technology that was created as a more compatible alternative to Adobe Flash Player. It allows a broadcaster to stream video assets over web platforms via an HLS ([HTTPS](https://en.wikipedia.org/wiki/HTTP_Live_Streaming) Live Streaming) protocol to fetch content from CDNs ([Content Delivery Networks](https://en.wikipedia.org/wiki/Content_delivery_network)).

All major browsers and operating systems support HTML5 video players. 

# What does it mean to customize an HTML5 video player?
Customizing an HTML5 video player means changing the default look or styling to your taste. This is done by writing a new style sheet for the DOM element that renders a selected video player. 

# Use cases and real-life examples of customized HTML5 video players
You can find real-life examples of customized HTML5 video players on YouTube, the [Cloudinary Video Player](https://demo.cloudinary.com/video-player/), [JWPlayer](https://www.jwplayer.com/), and [Video JS](https://videojs.com/). Each of these websites or frameworks utilizes the power of CSS to customize their videos or allow their users to do the same. 

As you can see, there are many use cases for custom video players, especially in apps where the video is the primary function (like YouTube, for example). With the following tutorial, you will learn how to create your own HTML5 video player and customize it to look like a native part of your app.

# How to create a new HTML5 video player
To create a new HTML5 video player, we will need to create a new project folder. Inside the folder create an HTML file called `index.html`.

Type the following code in the `index.html` file:
```html
<!DOCTYPE html>
<html lang="en">
  <body>
  <video src="https://res.cloudinary.com/codelife/video/upload/v1637805738/intro_l5ul1k.mp4"></video>
  </body>
</html>
```
In the code above, we have an HTML document with a `video` tag in the body. We also passed in a video URL as the source. 

If you preview this webpage in a browser, you should see the following:
![](https://paper-attachments.dropbox.com/s_B7E7FAB66F3D67FCD02F94C3407FE02B00F60BDDD432018352DE846981AA78E5_1637806039145_image.png)
In the image above, the HTML5 video player renders a video that we can't interact with because we have not set the necessary parameters to make the video player functional.

To fix this, let’s go ahead to add more attributes to the `video` tag. Replace the `video` tag in the HTML document with the following:
```html
<video src="https://res.cloudinary.com/codelife/video/upload/v1637805738/intro_l5ul1k.mp4" controls autoplay loop muted width="400px" height="300px" ></video>
```
In the code above, we added `controls` to display the default controls for the video player. By default it is set to `true` (which means `controls` is the same as `controls="true"`). It only accepts `true` or `false` as its value.

`autoplay` is used to decide whether the video should start playing immediately after it is loaded or not. Every new video element has a default autoplay value of `false` until you include `autoplay` as an attribute.

`loop` is used to decide if a video should start again when it ends. Every new video element has a default loop value of `false`.

`muted` is used to decide if the video should play with audio or not. Every new video element has a default muted value of  `false` .

Finally, `width`  and `height` set the horizontal and vertical size of the video.

 If you preview the new code in a browser, you should see the following:
![](https://paper-attachments.dropbox.com/s_B7E7FAB66F3D67FCD02F94C3407FE02B00F60BDDD432018352DE846981AA78E5_1637807126358_gif.gif)

# Customizing the HTML5 video player
To customize the player we will need to create two additional files: `script.js` and `style.css`. 

`Script.js` is where will write the functionality for the video’s controls, while the `style.css` is where we will write our stylesheet for the video. We could write the contents of the two files inside `index.html` but that would make our code lengthy and untidy

Replace the content of the `index.html` with the following code. This will be the structure of the video before customization:
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  </head>
  <body>
    <div class="container">
      <video onclick="play(event)" src="https://res.cloudinary.com/codelife/video/upload/v1637805738/intro_l5ul1k.mp4" id="video"></video>
      <div class="controls">
        <button onclick="play(event)"><i class="fa fa-play"></i><i class="fa fa-pause"></i></button>
        <button onclick="rewind(event)"><i class="fa fa-fast-backward"></i></button>
        <div class="timeline">
          <div class="bar">
            <div class="inner"></div>
          </div>
        </div>
        <button onclick="forward(event)"><i class="fa fa-fast-forward"></i></button>
        <button onclick="fullScreen(event)"><i class="fa fa-expand"></i></button>
        <button onclick="download(event)"><i class="fa fa-cloud-download"></i></button>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>
```
In the above code, we included our custom stylesheet (`style.css`) and a Font Awesome CDN link. Then we created a container div, where we included the video and all the controls we added previously.

In the controls div, we have a button that toggles the video playing state, as well as a button to reverse and forward the current time of the video, a button to preview the video in full screen, a button to open the video as a downloadable file, and a div to show the current position of the video timeline.

Next, we write our stylesheet. With the stylesheet, we can alter the default styling of the video player by referencing certain objects with the use of selectors, and then assign a new attribute to each property we want to customize. 

To do that, type the following code inside the `style.css` file:
```css
.container {
  position: relative;
  display: flex;
  width: max-content;
  height: max-content;
  justify-content: center;
  align-items: center;
}  
.container #video {
  width: 600px;
  height: 400px;
  border-radius: 20px;
}
.container .controls {
  position: absolute;
  bottom: 40px;
  width: 100%;
  display: flex;
  justify-content: space-around;
  opacity: 0.2;
  transition: opacity 0.4s;
}
.container:hover .controls {
  opacity: 1;
}
.container .controls button {
  background: transparent;
  color: #fff;
  font-weight: bolder;
  text-shadow: 2px 1px 2px #000;
  border: none;
  cursor: pointer;
}
.container .controls .timeline {
  flex: 1;
  display: flex;
  align-items: center;
  border: none;
  border-right: 3px solid #ccc;
  border-left: 3px solid #ccc;
}
.container .controls .timeline .bar{
  background: rgb(1, 1, 65);
  height: 4px;
  flex: 1;
}
.container .controls .timeline .bar .inner{
  background: #ccc;
  width: 0%;
  height: 100%;
}
.fa {
  font-size: 20px !important;
}
```
In this file, you will notice that the container has a position of `relative`. This is to control the position of the other elements inside it. 

We set the position of the div with the `controls` class as `position: absolute` and `bottom: 40px`. This will place the `controls` div 40px from the bottom of the video container. We also specified an `!important` font size for our icons.

Next, our video player needs functionality, like a play, pause, and fullscreen button, plus the ability for our users to download, rewind, and forward. These functionalities will make our video player interactive. 

Input the following code into `script.js`:
```javascript
// Select the HTML5 video
const video = document.querySelector("#video")
// set the pause button to display:none by default
document.querySelector(".fa-pause").style.display = "none"
// update the progress bar
video.addEventListener("timeupdate", () => {
  let curr = (video.currentTime / video.duration) * 100
  if(video.ended){
    document.querySelector(".fa-play").style.display = "block"
    document.querySelector(".fa-pause").style.display = "none"
  }
  document.querySelector('.inner').style.width = `${curr}%`
})
// pause or play the video
const play = (e) => {
  // Condition when to play a video
  if(video.paused){
    document.querySelector(".fa-play").style.display = "none"
    document.querySelector(".fa-pause").style.display = "block"
    video.play()
  } else{
    document.querySelector(".fa-play").style.display = "block"
    document.querySelector(".fa-pause").style.display = "none"
    video.pause()
  }
}
// trigger fullscreen
const fullScreen = (e) => {
  e.preventDefault()
  video.requestFullscreen()
}
// download the video
const download = (e) => {
  e.preventDefault()
  let a = document.createElement('a')
  a.href = video.src 
  a.target = "_blank"
  a.download = ""
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}
// rewind the current time
const rewind = (e) => {
  video.currentTime = video.currentTime - ((video.duration/100) * 5)
}
// forward the current time
const forward = (e) => {
  video.currentTime = video.currentTime + ((video.duration/100) * 5)
}
```
In the code snippet above, we created a constant `video` which is used to identify the video in the various functions of the script file.

The `pause` icon is set to `display: none` by default. We then ran an event listener on the video, to check `timeupdate`. For every time update, we update the width of the inner progress bar to the percent current time of the total duration of the video using this formula: 
```javascript
let curr = (video.currentTime / video.duration) * 100
```
Then we created a function called `play` that we use to toggle the playing state of the video and decide which buttons to display. For this, we wrote some logic, where if the play button is clicked when the `video.paused` is `true` we hide the pause button, display the play button, and play the video, else we do the opposite for each item.

For the fullscreen function, we just trigger a `requestFullscreen()` function on the video element. In the download function, we created a new `a` tag and assign the video URL as the `href` attribute. 

Next, we set the `target` as `_blank` to open the downloadable video in a new tab. Then we programmatically clicked the new link we created using the `click()`  function.

We also need to create functions to rewind or forward the video. We can do this by using the following logic:

For rewind:
```javascript
video.currentTime = video.currentTime - ((video.duration/100) * 5)
```
For forward:
```javascript
video.currentTime = video.currentTime + ((video.duration/100) * 5)
```
If we did everything right, we should have the following result:
![](https://paper-attachments.dropbox.com/s_B7E7FAB66F3D67FCD02F94C3407FE02B00F60BDDD432018352DE846981AA78E5_1638046645619_db35a7c7-b810-4f02-b7ec-0753a4073201.gif)

# Conclusion 

In this article, we have learned what it means to customize an HTML5 video player and how to do it ourselves using CSS. However, you can always challenge yourself to add more features to make your video blend in even better with your own UI.

If you have any questions, feel free to drop them in the comment section below.