HTML 5 Mediaelemente für alle – Warum und Wie video-/audio- Elemente schon heute genutzt werden sollten
Ich gehöre mit Sicherheit nicht zu denjenigen, welche die Nutzung von HTML5 in seiner reinen Form bereits heute propagieren. Die Probleme der Rückwärtskompatibilität mit HTML5-Elementen sind zu groß und können eben nicht mit dem document.createElement – Trick behoben werden. Ausnahmen bestätigen jedoch die Regel und eine hiervon sind mit Sicherheit die HTML5 Mediaelemente, audio und video. Warum sollten diese Elemente also zum Einbinden von Multimediainhalten genutzt werden, wenn immernoch Flash oder andere Plugins – zumindest als Fallback genutzt werden müßen?
audio/video Elemente sind einfacher zu Handhaben als object-/embed-Elemente
Im Laufe der Zeit haben sich eine Menge Einbindetechniken für Flash-Player entwicklet. Diese Menge an Einbindetechniken sind jedoch kein Zeichen von Flexibilität, sondern Ausdruck für die Unzulänglichkeiten jeder jeweils anderen Einbindetechnik. Ein paar Beispiele:
-
verschachtelte object-Elemente bzw. verschachtelte object-/embed – Elemente
fehleranfällig, da unterschiedlicher Code für unterschiedliche Browser; kaum ein Entwickler kann sich den genauen Einbindecode merken; unelegantes HTML
-
Einbindung mit swfobject oder ähnlichem
kann nicht ohne Javascript funktionieren; kaum ein Entwickler kann sich den Einbindecode merken; Herausforderungen dies elegant mit einem CMS zu lösen
-
Javascript transformiert ein HTML-Element automatisch zum Videoplayer-Code (z. B.: a.video -> object)
kann nicht ohne Javascript funktionieren; angesichts der Vorhandenen HTML5-Semantik ist diese Einbindung semantisch überholt
Auf der anderen Seite stehen die HTML5-Elemente audio/video, welche die Einbindung von Mediainhalten so einfach machen, wie die Einbindung von Bildern.
<video src="mein-video.mp4" poster="mein-poster-bild.jpg" controls="controls"></video>
Unterstützt der Browser nicht das video-Element bzw. das Video-Format kann dies mit Javascript erkannt und in ein unterstütztes object-Element umgewandelt werden. Was bleibt ist jedoch ein klarer Einbindecode, der semantisch und elegant ist und in modernen Browsern grundsätzlich auch ohne Javascript und vor allem ohne weitere Plugins funktioniert.
Es funktioniert auf mehr Endgeräten
Spätestens seit der unsäglichen iPhone/iPad – Flash Diskussion wissen alle, daß Flash nicht auf allen Geräten installiert ist. Bindet man Mediainhalte per HTML5 ein und fällt – bei nicht Unterstützung – auf ein oder besser mehrere mögliche Plugin(s) (Flash, Quicktime, VLC etc.) zurück, erreicht man schlichtweg mehr User.
jMediaelement – Video/Audio für alle
Das jMediaelement-Script auf Basis von jQuery stellt eine Lösung dar, welche erkennt, ob die HTML5-Mediaelemente im allgemeinen und die konkreten Mediadaten im besonderen unterstützt werden. Bei Bedarf bindet es unterstützte Plugins ein (derzeit Flash auf JW Player Basis sowie VLC), normalisiert die unterschiedlichen APIs und hilft bei der Erstellung von stylbaren Kontrollelementen für die Player.
Mediainhalte mit jMediaelement einbinden
Die Einbindung von Video- und Audio – Dateien mit jMediaelement ist dementsprechend sehr einfach. Als Grundlage muß man lediglich den HTML Code schreiben, wie er durch HTML 5 vorgesehen ist. Die Attribute poster, loop, autoplay, controls werden hierbei unterstützt. Man kann statt einer Source-Datei auch mehrere Dateien verwenden. Als mögliche Source-Dateien kommen neben MP3, MP4 und OGG auch FLV, MOV und weitere in Frage.
Nachfolgend ein paar Beispiele:
<video src="mein-video.mp4" poster="mein-poster-bild.jpg" controls="controls"></video> <video loop="loop"> <a class="source" href="mein-video.flv" controls="controls">Video als flv</a> <source src="mein-video.flv" /> </video> <video poster="mein-bild.png" autoplay="autoplay" controls="controls"> <a class="source" href="mein-video.ogg">Video als ogg</a> <source src="mein-video.ogg" /> <a class="source" href="mein-video.mp4">Video alsmp4</a> <source src="mein-video.mp4" /> </video>
Anschließend ruft man einfach das jQuery Plugin auf den Audio/Video Elementen auf. In der Regel muß man hier nur den Pfad zur Flashplayerdatei konfigurieren:
$('audio, video').jmeEmbed({ jwPlayer: { path: '../mediaplayers/player.swf' } });
Zur “kugelsicheren” Einbindung mit schönem Fallback, falls alle Stricke reißen, kann noch etwas mehr getan werden, aber dies soll hier erstmal reichen.
Multimedia scripten war noch nie so einfach
Eine Sache die mit jMediaelement wirklich Spaß macht, ist das Scripten der Player. Zum einen ist die API für die unterschiedlichen Player normalisiert, zum anderen erweitern diese jQuery selbst. Gleichgültig welche API und welcher Browser verwendet wird, ist und bleibt das HTML5-Element hierbei das anzusprechende Element, so daß mit den Mediaplayern gearbeitet werden kann, wie man dies von jQuery gewohnt ist. Eine Auflistung der meisten Methoden findet sich im jMediaelement-Wiki.
Hier ein paar Beispiele:
Sind mehrere Video- und/oder Audio-Player auf einer Seite und sollen, sobald der User einen Player startet, alle anderen pausiert werden, könnte dies folgender einfacher Code bewerkstelligen:
$(document).bind('play', function(e){ $('audio, video').not(e.target).pause(); });
Wir wollen Sprungmarken in das Video erlauben. Klickt der User auf eine Sprungmarke springt der Player an diese Stelle und fängt an zu spielen. Wir haben hierfür folgendes HTML vorbereitet:
<video class="skip-video" src="mein-video.mp4" poster="mein-poster-bild.jpg" controls="controls"></video> <ul class="skip-links"> <li><a href="#" data-time="10">jump to 10</a></li> <li><a href="#" data-time="20">jump to 20</a></li> <li><a href="#" data-time="30">jump to 30</a></li> </ul>
Dann würde unser Javascript wie folgt aussehen:
$('ul.skip-links').delegate('a', 'click', function(e){ var time = parseInt($(this).attr('data-time'), 10); if(isNaN(time)){return false;} $('video.skip-video') .currentTime(time) .play() ; return false; });
Wir wollen, daß ein Video automatisch, aber im gemuteten Zustand, abspielt. Zwar kennt der HTML5 Standard das Attribut autoplay, aber für den mute-Zustand gibt es keine Markup-API. Unser HTML könnte dann so aussehen:
<video class="automute" autoplay="autoplay" src="mein-video.mp4" poster="mein-poster-bild.jpg" controls="controls"></video>
… und unser Javascript wie folgt:
$('video.automute').muted(true);
Bisher haben wir die Player nur in verschiedene Zustände versetzt (currentTime, play, pause, muted). Es ist aber genauso möglich, Zustände auszulesen. Hierzu müßen wir allerdings abwarten, bis die API bereit ist, ausgelesen zu werden. Dies sagt uns die Methode jmeReady. Hier ein kleines Beispiel:
$('video.myvideo').jmeReady(function(){ var muted = $(this).muted(); //true|false var time = $(this).currentTime(); //am Anfang wohl in der Regel 0 //etc. });
Manche Daten wie beispielsweise die Länge des Videos/Audios sind erst noch später verfügbar, nämlich dann, wenn die Metadaten geladen wurden, wofür das Event loadedmeta zur Verfügung steht. Hier ein Beispiel:
$('video.myvideo').bind('loadedmeta', function(){ var duration = $(this).getDuration(); //das video dauert xxx Sekunden });
Unter meinen jMediaelement-Demos befindet sich eine Audioplayer-Demo, welche zeigt, wie einfach mit der Methode loadSrc eine Playliste erstellt werden kann.
Stylebare Kontrollelemente erstellen
Die Erstellung von stylbaren HTML-Kontrollelementen wird durch jMediaelement ebenfalls unterstützt. Hierbei ging es mir um die größtmögliche Flexibilität für den Webautoren. Anstatt Kontrollelemente in einer mehr oder – in der Regel – weniger konfigurierbaren, lokalisierbaren und barrierearmen Form mit Javascript in das HTML zu Rendern, darf(/muß) der Entwickler sein HTML selber schreiben. Das einzige was vorgegeben wird, ist eine HTML-Klasse, welche dem Script sagt, wie sich das Kontrollelement verhalten sowie ein Mechanismus, welcher Player hierdurch gesteuert werden soll.
Wir wollen beispielsweise einen Play-/Pause-Togglebutton machen. Die vorgegebene Klasse nennt sich hierfür ‘play-pause’.
Unser HTML könnte dann wie folgt aussehen:
<a href="#" class="play-pause">play / pause</a> <!-- oder --> <button class="play-pause">play / pause</button> <!-- oder, aber nicht empfohlen, da nicht tastaturbenutzbar --> <span class="play-pause">play / pause</span>
Folgende Schreibweisen wären jQuery UI Themeroller kompatibel:
<a href="#" class="play-pause"><span class="ui-icon"></span> play / pause</a> <!-- oder --> <button class="play-pause"><span class="ui-icon"></span> play / pause</button> <!-- oder, empfohlen: --> <button class="play-pause"><span class="ui-icon"></span> <span class="button-text">play / pause</span></button>
Für die Assoziierung eines Kontrollelements mit einem bestimmten video-/audio-Element, biete ich im Prinzip 3 Möglichkeiten an:
- gemeinsames wrapper-Element
- data-controls-Attribut am Kontrollelement (HTML5-valide, data-controls=”IDREF”)
- data-controls-Attribut an einem wrapper-Element
gemeinsames wrapper-Element
Wird die jQuery-Methode ‘jmeControl’ auf einem Wrapper-Element ohne data-controls-Attribut aufgerufen, werden alle darin befindlichen Kontrollelemente mit dem ersten gefundenen video/audio-Element assoziiert:
Unser HTML:
<div class="video-wrapper"> <video src="mein-video.mp4" poster="mein-poster-bild.jpg"></video> <a href="#" class="play-pause">abspielen / pausieren</a> <a href="#" class="mute-unmute">ton aus / ton an</a> </div>
Unser Javascript:
$('div.video-wrapper').jmeControl();
data-controls-Attribut am Kontrollelement
Soll das Kontrollelement eigentlich ganz woanders auf die Webseite, gibt es unter Umständen keinen gemeinsamen wrapper, welcher andere video/audio-Elemente ausschließt bzw. wäre obige Schreibweise ineffizient.
Unser HTML:
<div class="video-wrapper"> <video id="my-video" src="mein-video.mp4" poster="mein-poster-bild.jpg"></video> </div> <!-- ganz viel HTML dazwischen --> <a data-controls="my-video" href="#" class="play-pause">abspielen / pausieren</a>
… und unser Javascript:
$('a.play-pause').jmeControl();
data-controls-Attribut an einem wrapper-Element
Exsistieren mehrere Kontrollelemente weit vom zu kontrollierenden video-/audio-Tag entfernt, wäre es müßig jedem einzelnen Element das data-controls-Attribut zu geben.
Unser HTML:
<div class="video-wrapper"> <video id="my-video" src="mein-video.mp4" poster="mein-poster-bild.jpg"></video> </div> <!-- ganz viel HTML dazwischen --> <div class="control-wrapper" data-controls="my-video"> <a href="#" class="play-pause">abspielen / pausieren</a> <a href="#" class="mute-unmute">ton aus / ton an</a> </div>
… und unser Javascript:
$('div.control-wrapper').jmeControl();
Konfiguration der Kontrollelemente
Die Kontrollelemente sind daneben zusätzlich konfigurierbar. Beispielsweise sind alle slider sowie die progressbar Teil von jQuery UI und alle Optionen jQuery UI Optionen können verwendet werden. Wir wollen beispielsweise unsere Klassen Namespacen, da wir in einem ganz anderen Modul bereits die Klasse play-pause verwenden, außerdem wollen wir, daß der bereits abgespielte Teil auf der Timeline anders eingefärbt wird und sich der Sliderhandle animiert auf der Timeline bewegt.
Unser HTML:
<div class="video-wrapper"> <video id="my-video" src="mein-video.mp4" poster="mein-poster-bild.jpg"></video> </div> <div class="control-wrapper" data-controls="my-video"> <a href="#" class="jme-play-pause">abspielen / pausieren</a> <div class="jme-time-slider"></div> </div>
… und unser Javascript:
$('div.control-wrapper').jmeControl({ classPrefix: 'jme-', timeSlider: { range: 'min', animate: true } });
Fazit: Eine API sie zu knechten
Als ich mit dem Projekt angefangen habe, stand die Auseinandersetzung mit den HTML5 Mediaelementen im Vordergrund. Als ich dem ganzen einen Sinn verleihen wollte, war für mich der erste Gedanke, so viel HTML 5 wie möglich so wenig Flash/Plugins wie nötig, möglich zu machen. Diese Sichtweise hat sich inwzischen enorm geändert. jMediaelement ist für mich ein Tool, welches es erlaubt Mediainhalte einerseits einfach und elegant einzubinden und gegebenefalls ebenso einfach zu scripten und zu stylen sowie andererseits Mediainhalte auch dort zugänglich zu machen, wo entsprechende Plugins (noch) nicht verfügbar sind. Aber wem mein erster Gedanke eher gefällt, kann jMediaelement auch für seine Zwecke nutzen .