Here Be Dragons

Any device that supports HTML5 content must also, by definition, support HTML5 audio and video. It follows that these clients must also feature controls for AV content, initiated by using the controls attribute in your HTML. However the appearance of those controls is left up to the client: multimedia controls look quite different in IE 9 compared to Chrome. This is an issue for any designer who wishes to integrate a particular UI look-and-feel into all aspects of their website, or to make their site appear as similar as possible across different browsers and platforms.

It is entirely possible to make consistent custom AV controls for HTML5 with a little work and JavaScript. Before we add any scripting, however, we should be aware of a few things:

Keeping to the best practices of graceful degradation and progressive enhancement, we will leave A/V controls on for the video by default, and then use JavaScript to turn them off and insert our own controls. The idea behind this is simple: if the client blocks JavaScript, they will still have the ability to play our audio and video content using the browser’s built-in controls. If they have JavaScript enabled, our own controls will be substituted for the defaults.

The JavaScript controls over HTML audio and video are implemented in the form of two simple methods: play() and pause(). More advanced controls such as rewind and scene access are possible, but will not be the focus of this article.

First, let’s get the basic video on the page, together with the HTML that our JavaScript will hook into. (If you’re not familiar with HTML5 video or codecs, you might want to read the associated reading list).

To create the play button, I’ll use the Unicode character “black right-pointing triangle” (U+25BA),with “black medium square” (U+25fC) representing stop, which have the advantages of very easy creation and alteration in size and color without loss of quality. I’ll integrate the controls into a figcaption element to minimize UI space.

<figure id="customcontrols">
	<video controls poster="here-be-dragons.png">
		<source src="here-be-dragons.m4v" type="video/mp4">
		<source src="here-be-dragons.webm" type="video/webm">
		<a href="#">▶</a>
		<cite>Here Be Dragons</cite>

We’ll add some CSS that will hide our controls by default, and tidy up the display:

#customcontrols {
	font-size: 0;
#customcontrols figcaption { 
	background: rgba(0,0,0,0.6); 
	display: none; padding: .5em; 
	color: #fff;
	position: relative; top: -2.2rem;
	text-align: right;
	margin-bottom: -2.2rem;
#customcontrols figcaption a { 
	text-decoration: none; font-size: 1rem; 
	margin-right: .5rem;
	color: #fff;
	border-bottom: none;
#customcontrols a:hover { color: red; }
#customcontrols a:visited { color: #770; }

I’ve used relative positioning and an rgba background color to place the caption on top of the video, but made it invisible by default. In the script we’ll turn off native controls for the video and substitute our own:

var moviecontainer = document.getElementById("customcontrols"),
movie = moviecontainer.querySelector("video"),
controls = moviecontainer.querySelector("figcaption"),
playpause = controls.querySelector("a");
movie.removeAttribute("controls"); = "block";

To this code we’ll add:

playpause.addEventListener("click", function(e) { 
	if (movie.paused) {;
		playpause.innerHTML = "◼";
	} else { 
		playpause.innerHTML = "►";

A simple explanation: if the movie is paused, it is set to play, and the link turned to represent a stop button. Otherwise, the movie is playing, and must be paused.

Here Be Dragons by Brian Dunning, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at to learn more.
Check out the CodePen demo for this article at