Popular Searches:
Uploading, APIs, Creating Players, BEML
For front-end developers, it's long been a rule of thumb that you should keep your content and styling separate for easy maintainability and reuse. This rule easily applies to the world of web design, but how is it addressed from a video publishing point of view?
Let's imagine a scenario in which a publisher's website contained twenty distinct subsections, each having its own unique color palette. The default approach to matching player skins in this situation would be to create one player for each section, edit each player's style through the Studio, and work publishing logic into the site to determine which player to show. While this may not sound all that complicated, it's certainly more complex than what many web designers and developers are used to. Why can't updating a player's style be as simple as editing a CSS file?
Well, actually, it can be. By using the Brightcove Player API, it's possible to dynamically set player styles by using custom Brightcove CSS strings. Before we begin looking at how to do this, it's important to understand how CSS for web and CSS for Brightcove players differ.
The key difference with Brightcove CSS is the lack of selectors, in the general sense. For instance, consider the following web CSS format:
.classNameOne {
color: #ffffff;
background: #000000;
}
.classNameTwo {
color: #450000;
background: #ffffff;
}
A similar definition in Brightcove CSS looks like this:
classNameOne-color: #ffffff; classNameOne-background: #000000; classNameTwo-color: #450000; classNameTwo-background: #ffffff;
As you can see, each class name drops into the property level, effectively flattening the CSS structure that we're all so used to. Another thing to consider is the fact that properties for HTML nodes and properties for Brightcove style targets aren't the same. As an example, the playhead well element contains "buffered", "watched", and "unloaded", which aren't standard CSS properties.
At this point, you may be wondering how it's possible to make Brightcove CSS as easy to use and maintain as standard stylesheets. Hierarchy is an important organizational feature, so let's start by addressing the format of Brightcove CSS. Instead of
playheadWell-buffed: #450000; playheadWell-watched: #ffffff; playheadWell-unloaded: #000000;
Let's stick with what we're used to:
.playheadWell {
buffed: #450000;
watched: #ffffff;
unloaded: #000000;
}
The next issue is getting our CSS into the player. Styling HTML with CSS is simple; we just include a CSS file using a link tag or a style import and the browser takes care of things. Styling a player is slightly different. Since we need to get the CSS from a stylesheet into Flash, there are a few intermediary steps involved. First, we'll need the location of the CSS file to parse. To keep things easy and as standard as possible, we'll use a link tag. To prevent this CSS from being interpreted by the browser as standard CSS, we'll give it a rel value of "brightcove-css". Another thing to note is the file extension. I'm using ".bcss" instead of "css" for a very important reason. Some Internet Explorer configurations will attempt to download and open CSS files loaded into iframes, and we definitely don't want that mucking up a user's experience. Using a non-standard extension prevents this behavior.
<link rel="brightcove-css" href="http://test.com/bc.bcss" />
The rest of this article will reference the content of the Kudos Brightcove CSS loader script, which can be downloaded here.
In order to manipulate the content of our CSS file, we need to draw it into JavaSscript. We'll do this using a method similar to that which is commonly used to draw API results into a page using tag injection. The key difference will be instead of injecting a script tag, we're using an iframe. The event attachment detection below circumvents a common problem with Internet Explorer, in which iframe onload events are not correctly bound.
//| The inject method takes a path to a css file and creates an iframe to draw its contents into the page
this.inject = function (s) {
//| Create the iframe element and assign appropriate properties to prevent it from being seen
var n = document.createElement('iframe');
n.setAttribute('src', s);
n.setAttribute('id', 'bcss');
n.style.display = 'none';
n.style.height = '1px';
n.style.width = '1px';
//| When the contents of the iframe are loaded, we know we can access the css within
if (n.addEventListener) {
n.addEventListener('load', bcss.loader, false);
} else if (n.attachEvent) {
n.attachEvent('onload', bcss.loader);
} else {
n.onload = bcss.loader;
}
document.body.appendChild(n);
};
So now we have an iframe in our page which contains the CSS contents of the file we have in our link tag. We're not done yet, though. That content has to be handed over to JavaScript as a string:
//| This is what we do when the iframe loads
this.loader = function () {
var n = document.getElementById('bcss');
//| Cross-browser nonsense, as always
var d = ((typeof n.contentDocument == undefined) || (n.contentDocument == null))
? n.contentWindow.document : n.contentDocument;
var c = d.body.innerHTML;
//| Remove the iframe so we don't clutter the dom with trash
setTimeout('document.body.removeChild(document.getElementById("bcss"));', 500);
//| Pass the altered css to the set method
bcss.translate(c);
};
OK, we have our CSS as a string, and we're even being kind and cleaning up our used iframe element. Now that the CSS content is ours to play with, we have to perform a few cleanups on it to ensure we can parse it as easily as possible:
//| Parses css into a Brightcove-readable string to send to the player
this.translate = function (css) {
//| Take out any HTML that firebug might add, and remove all whitespace to
//| make parsing easier
css = css.replace(/<.*?>/ig, '');
css = css.replace(/\s{1,}?/ig, '');
//| Find each class-level chunk
var p = css.split('}');
var s = '';
for (var i in p) {
//| Get the classname for use in the atribute names below
var n = p[i].substr(0, p[i].indexOf('{'));
var r = p[i].substr(p[i].indexOf('{') + 1).split(';');
//| Step through the key/value pairs within this selector chunk
for (var j in r) {
//| Some browsers will give us some blank lines after the splits, so we take them out here
if (r[j].length < 1) { continue; }
var t = r[j].substr(0, r[j].indexOf(':'));
var v = r[j].substr(r[j].indexOf(':') + 1);
//| Combine selector name with property name for our new key, assign the old value
s += (n.replace('.', '')+'-'+t+':'+v+';');
}
}
try {
//| In some cases, the player will have already loaded, which means we have to set styles now
this.player.setStyles(s);
} catch (e) {
//| Otherwise, we queue the change
queue = s;
}
};
In the above code chunk, we've taken our stripped-down CSS and split it into its various class selectors. We then capture the class name, and split the remaining class definition into a list of properties. Looping through each property, we mash the class name into the property name, add the value, and format everything uniformly. Out of our loop comes a nice single line of Brightcove-formatted CSS. Telling the player to use the new CSS is as easy as calling the setStyles method.
This solution is fully re-usable, and even scriptable. You can manually call the bcss.inject() method, passing it the location of a CSS file, and your player will be dynamically updated.
Using this method, you can change player styles on different events, customize color schemes to match your web properties on the fly, and prototype new player styles easier than ever.
To see the Kudos Brightcove CSS Loader in action, head on over to the Kudos example page.
Thanks for reading and good luck styling your own players with Brightcove CSS.