Suave, for elegant HTML5 videos (how they should have been). Suave was built to re-engineer the unstructured mess the HTML5
HTML5 video is awesome, what’s not awesome is the markup. The semantics and unmodular approach with HTML5 video upset me and I was inspired to fix it. So here’s my idea, which is very modular and works in all browsers supporting HTML5 video.
Table of contents
The problem
HTML5 video is a brilliant invention, cleverly injecting useful pieces of Shadow DOM in for us so we no longer need to code in video controls and other funky buttons. It seems someone had a little too much coffee when thinking about a solution for the markup (don’t get me started on the responsive images
For those wondering what I’m really digging into, let’s take a cross-browser
<video>
<source src="video/trailer.mp4" type="video/mp4">
<source src="video/trailer.ogv" type="video/ogv">
<source src="video/trailer.webm" type="video/webm">
</video>
I love the naming conventions here, source ‘src’. Source source (they definitely had too much coffee by this point). But seriously, what on earth happened here? HTML5 is meant to be intelligent and in my eyes this is a little dumb. What happens if I suddenly change the file name and/or directories, I’ve then got to change it multiple times… Crazy.
My solution
So here’s where Suave comes in. Thanks to my little script, you no longer have to worry about the above catastrophe and can code an HTML5 video with just one line of code (this is proper valid HTML5, too!):
<video data-src="video/mymovie.{mp4, ogv, webm}"></video>
All you need to do is feed it the file extensions you require for each video inside a data-* attribute, easy. Suave is fully modular as well, call it as many times on the page and it’ll just keep doing its thing. What I also like about this solution is that I’m enhancing HTML5, with HTML5. Of course some people will disagree and say I’m missing a few codecs, lost my mind and am hashing out strange ideas, but my project would be finished ontime and save countless future hours.
Free eBook
Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.
- Observables and Async Pipe
- Identity Checking and Performance
- Web Components <ng-template> syntax
- <ng-container> and Observable Composition
- Advanced Rendering Patterns
- Setters and Getters for Styles and Class Bindings
I’ve been using Grunt.js a lot recently and I love how you can simply include some curly braces to say ‘or this too’, so that’s where the idea came from to simplify an overcomplicated system. This is fully semantic stuff too, if anything this improves the semantics of the
<video src="video/mymovie.mp4"></video>
And that’s where the simplicity of my idea came from. Sure it isn’t how the HTML5 spec intended it, but remember this stuff is still new to everyone and remember this is still a huge work in progress.
JavaScript
For those interested in how Suave works, here’s a break down of the script:
window.suave = ( function ( window, document, undefined ) {
'use strict';
/*
* Constructor function
*/
var Suave = function ( elem ) {
this.elem = elem;
};
/*
* Prototypal setup
*/
Suave.prototype = {
init : function () {
var dataAttr = this.elem.getAttribute('data-src');
var videoSource = dataAttr.match(/^([^]+){/)[1];
var fileExts = dataAttr.match(/{([^]+)}$/)[1].toString().replace(/\s/g, '').split(',');
for (var i = 0; i < fileExts.length; i++) {
var extension = fileExts[i];
var source = document.createElement('source');
source.src = videoSource + extension;
source.type = 'video/' + extension;
this.elem.appendChild(source);
}
}
};
/*
* Initiate the plugin
*/
[].forEach.call(document.querySelectorAll('video[data-src]'), function (suave) {
new Suave(suave).init();
});
})( window, document );
From the top, I create the constructor function, which I pass the current element into (passed in at the bottom loop). This then has some internal Prototype workings that grab the data-src attribute (we’re looking at the init function here).
First I grab the videoSource from the attribute, which uses a RegExp to capture the file path and file name, but not the extension.
Next I grab the file extensions (fileExts) which captures everything inside the curlies {}. From here, I use the .toString() method, which converts the array sent back from .match() to a string (you guessed it), from here, I .replace() any whitespace to get a clean array for adding the file extensions, and then use the .split(‘,’) method to split the string by commas which then returns a new array. I then loop through that array of file extensions and create the right amount of tags, populating them with the necessary src and type attributes.
At the bottom, I then hook into the Array.prototype (but use an empty array shorthand to access this) and loop through all video[data-src] tags, which will hold our Suave.js videos! Inside this loop, I pass in the current element and create a new Suave instance to the current item.
Feedback welcome :)