Last week two of my students wanted to know if there was a way to create a HTML5 video playlist without using a third-party service such as YouTube. They also wanted a responsive solution that would be easy to implement.
One possible answer is to use PHP to generate URL variables for a <video>
element, an approach similar to the one I’ve provided in the simple server-side image gallery. There are also many JQuery plugin candidates, but it seemed excessive to load in a 100K framework just to create a playlist. Instead, I opted to show the students a solution using native JavaScript, using the principles of progressive enhancement.
The easiest way to start development on the video playlist is to work from the base HTML upwards. For this example I’ll reference outtakes from Marsel Van Oosten’s and Daniella Sibbing’s spectacular astrophotography timelapse Nambian Nights, licensed under Creative Commons.
Writing The Base HTML
The construction of the HTML makes the simple assumption that the CSS and JavaScript we add later will fail to work as intended. Obviously, that’s not what we want to happen, but it’s the pragmatic default state. HTML is the base layer of our web page: if we build that to serve as many visitors as possible, then CSS and JavaScript can be considered an enhancement to the basic experience. Keeping this approach in mind, our markup looks something like this:
<figure id="video_player">
<video controls poster="nambia1.jpg">
<source src="nambia1.mp4" type="video/mp4">
<source src="nambia1.webm" type="video/webm">
</video>
<figcaption>
<a href="nambia1.mp4"><img src="nambia1.jpg" alt="Nambia Timelapse 1"></a>
<a href="nambia2.mp4"><img src="nambia2.jpg" alt="Nambia Timelapse 2"></a>
<a href="nambia3.mp4"><img src="nambia3.jpg" alt="Nambia Timelapse 3"></a>
</figcaption>
</figure>
(For the same of clarity, I’m placing all files in the same location. I’m also assuming that all browsers using the page understand HTML5 video: if that assumption was unreasonable, there are further fallbacks I could write in).
The links go directly to the .mp4
version of the videos, which will be displayed in the majority of browsers. The result won’t look pretty, nor does it have the interactivity we want, but it does work. Our next step is to enhance the presentation of the playlist with CSS.
Creating A Responsive Solution
Ideally, we want the three thumbnail links to be displayed in a dimmed state beside the main video. Hovering will brighten the links. I’ll use display: table
together with percentage measurements to achieve this:
#video_player {
display: table;
line-height: 0;
font-size: 0;
background: #000;
}
#video_player video,
#video_player figcaption {
display: table-cell;
vertical-align: top;
}
#video_player figcaption {
width: 25%;
}
#video_player figcaption a {
display: block;
opacity: .5;
transition: 1s opacity;
}
#video_player figcaption a img,
figure video {
width: 100%;
height: auto;
}
#video_player figcaption a:hover {
opacity: 1;
}
If the browser is less than 700 pixels wide, it makes sense to display the thumbnails below the main video:
@media (max-width: 700px) {
#video_player video,
#video_player figcaption {
display: table-row;
}
#video_player figcaption a {
display: inline-block;
width: 33.33%;
}
}
With the basic presentation rules done, it’s time to add the JavaScript.
Adding Interactivity
The first task is to ensure that all of the links inside the video respond in the same way to a click. At the bottom of the page, we start our script with:
var video_player = document.getElementById("video_player"),
links = video_player.getElementsByTagName('a');
for (var i=0; i<links.length; i++) {
links[i].onclick = handler;
}
… then add the handler
function that we’ve just add to each link. I’ll show the complete function here, and explain it in a moment:
function handler(e) {
e.preventDefault();
videotarget = this.getAttribute("href");
filename = videotarget.substr(0, videotarget.lastIndexOf('.')) || videotarget;
video = document.querySelector("#video_player video");
video.removeAttribute("controls");
video.removeAttribute("poster");
source = document.querySelectorAll("#video_player video source");
source[0].src = filename + ".mp4";
source[1].src = filename + ".webm";
video.load();
video.play();
}
This script does several things:
- Prevents the user’s click on a link from engaging the default behavior: so long as the user is running JavaScript, clicking on the link will no longer take them directly to the referenced
.mp4
file. - Looks at the filename referenced in the clicked link’s
href
attribute. - Splits the filename and captures everything before the last period, giving us the path and name of the file without an extension. (This assumes that the files are named correctly, and that we have been consistent when naming related
.mp4
and.webm
files.) - Finds the
<video>
element and removes itsposter
image andcontrols
. - Finds the
<source>
elements for the video and sets them to the appropriate filename that we derived from steps 2 and 3. - Ensures that the new video is loaded and plays it.
There’s much more we can do to this simple playlist example. Autoplaying the next video in the sequence is an obvious first step, as is returning the player controls when the user is hovering over the <video>
element. There’s also the possibility of using a single video rather than several separate ones, using HTML5 technologies to jump to different cuepoints in the video on click. I’ll address these features and more in upcoming articles.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.