Vytváříme vlastní HTML5 přehrávač videa pomocí CSS3 a jQuery

Předvedeme si tvorbu snadno modifikovatelného přehrávače pro HTML5 video a nabídneme ho jako jQuery plugin, ve kterém můžete nastavit, jaké kontrolní prvky budou zobrazeny a ovlivnit vzhled přehrávače pomocí témat vzhledu.

Tento text je zkráceným překladem článku Building a custom HTML5 video player with CSS3 and jQuerydev.opera.com, jehož autorem je Ionut Colceriu a je zde zveřejněn pod licencí CC BY-NC-SA 3.0.

Úvod

Prvek <video> z HTML5 je již podporován většinou moderních prohlížečů. Nativní podpora videa v prohlížečích přináší řadu výhod (jsou popsané např. v článku Introduction to HTML5 video od Bruce Lawsona), proto se ji řada vývojářů snaží využít, jak je to jen možné. Zůstává zde ještě několik bariér, zejména problém s tím, jaké kodeky ten který prohlížeč podporuje.

Další velkou bariérou je tvorba vlastního přehrávače pro HTML5 <video>   — řešení postavená na Flashi zde mají výhodu, Flash IDE totiž nabízí jednoduché rozhraní pro tvorbu a modifikace komponenty pro přehrávání videa. POKUD chcete vytvořit vlastní přehrávač pro HTML5 <video>,  musíte vše vytvořit v HTML5, CSS3 a JavaScriptu.

A tady ke slovu přichází tento článek. Podíváme se v něm na tvorbu snadno modifikovatelného přehrávače pro HTML5 <video> a nabídneme ho jako jQuery plugin, ve kterém můžete nastavit, jaké kontrolní prvky budou zobrazeny, a také přidat vlastní CSS.

Pro snazší manipulaci s DOMem použijeme jQuery, dále pak jQuery UI pro vytvoření kontrolních prvků typu slider, které nám umožní měnit přehrávanou pozici videa a hlasitost.

Ovládací prvky videa

Jako profesionální webdesigneři chceme vytvořit přehrávač videa, kterou bude vypadat konzistentně napříč prohlížeči. Jenže v každém prohlížeči přehrávač videa vypadá a chová se jinak, od minimalistického přehrávače ve Firefoxu a Chromu po ten nablýskaný v Opeře a Safari (viz obrázek níže). Pokud chceme, aby naše ovládací prvky vypadaly ve všech prohlížečích stejně a zapadly do našeho designu, musíme si je všechny vytvořit sami. Není to tak složité, jak se může zdát.

Nativní ovládací prvky HTML5 videa v různých prohlížečích.

Všechny mediální prvky v HTML5 podporují media elements API, které je dostupné z JavaScriptu a přes ně napojíme funkce videa jako je play, pause atd. k tlačítkům, které si vytvoříme.

Základní kód pro ovládací prvky

Nejdřív napíšeme HTML kód pro naše ovládací prvky. Budeme potřebovat tlačítko Play/Pause, pruh s přehrávanou pozicí videa (seek bar), zobrazení času (timer), dále pak tlačítko a slider pro nastavení zvuku. Kód vložíme za  prvek <video> a obalíme ho dalším prvkem.

<div class="ghinda-video-controls">
    <a class="ghinda-video-play" title="Play/Pause"></a>
    <div class="ghinda-video-seek"></div>
    <div class="ghinda-video-timer">00:00</div>
    <div class="ghinda-volume-box">
        <div class="ghinda-volume-slider"></div>
        <a class="ghinda-volume-button" title="Mute/Unmute"></a>
    </div>
</div>

U všech prvků jsme místo ID použili třídy, to abychom mohli do jedné stránky současně vložit několik přehrávačů videa.

Zabalení přehrávače do jQuery pluginu

Po vytvoření HTML kódu musíme naše prvky napojit na media elements API, aby mohly ovládat přehrávání videa. Jak jsme již zmínili, náš přehrávač zabalíme jako plugin pro jQuery, což nám usnadní jeho opakované použití.

$.fn.gVideo = function(options) {
    // build main options before element iteration
    var defaults = {
        theme: 'simpledark',
        childtheme: ''
    };
    var options = $.extend(defaults, options);
    // iterate and reformat each matched element
    return this.each(function() {
        var $gVideo = $(this);

        //create html structure
        //main wrapper
        var $video_wrap = $('<div></div>').addClass('ghinda-video-player').addClass(options.theme).addClass(options.childtheme);
        //controls wraper
        var $video_controls = $('<div class="ghinda-video-controls"><a class="ghinda-video-play" title="Play/Pause"></a><div class="ghinda-video-seek"></div><div class="ghinda-video-timer">00:00</div><div class="ghinda-volume-box"><div class="ghinda-volume-slider"></div><a class="ghinda-volume-button" title="Mute/Unmute"></a></div></div>');
        $gVideo.wrap($video_wrap);
        $gVideo.after($video_controls);

V tomto případě vytvoříme HTML kód našeho přehrávače dynamicky pomocí jQuery (tedy kromě vlastního prvku <video>). Atribut controls (ten zajišťuje zobrazení nativních prvků přehrávače) odstraníme až ve skriptu. To vše pro případ, kdyby měl uživatel vypnutý JavaScript – naše ovládací prvky by mu v takovém případě byly na nic a nemohl by video ani ovládat nativními prvky. Je proto smysluplnější do HTML kódu atribut controls zapisovat pro případ, že by se náš skript nenačetl; odstraníme ho až po úspěšném načtení skriptu.

Nyní si připravíme odkazy na ovládací prvky:

//get newly created elements
var $video_container = $gVideo.parent('.ghinda-video-player');
var $video_controls = $('.ghinda-video-controls', $video_container);
var $ghinda_play_btn = $('.ghinda-video-play', $video_container);
var $ghinda_video_seek = $('.ghinda-video-seek', $video_container);
var $ghinda_video_timer = $('.ghinda-video-timer', $video_container);
var $ghinda_volume = $('.ghinda-volume-slider', $video_container);
var $ghinda_volume_btn = $('.ghinda-volume-button', $video_container);

$video_controls.hide(); // keep the controls hidden

Na všechny ovládací prvky se odkazujeme jejich třídou a ponecháváme je skryty, dokud vše nebude připraveno.

Pojďme na ovládací prvek pro Play/Pause:

var gPlay = function() {
    if($gVideo.attr('paused') == false) {
        $gVideo[0].pause();
    } else {
        $gVideo[0].play();
    }
};

$ghinda_play_btn.click(gPlay);
$gVideo.click(gPlay);

$gVideo.bind('play', function() {
    $ghinda_play_btn.addClass('ghinda-paused-button');
});

$gVideo.bind('pause', function() {
    $ghinda_play_btn.removeClass('ghinda-paused-button');
});

$gVideo.bind('ended', function() {
    $ghinda_play_btn.removeClass('ghinda-paused-button');
});

Většina prohlížečů nabídne alternativní sadu ovládacích prvků videa v kontextovém menu, když na video kliknete pravým tlačítkem myši. Kdyby uživatel toto ovládání použil, mohlo by to rozhodit naše vytvořené ovládání. Abychom tomu předešli, napojíme na naše tlačítko Play/Pause události videa „Play“, „Pause“ a „Ended“.

Vzhled našeho tlačítka budeme měnit přidáváním a odebíráním tříd podle aktuálního stavu  videa (Play/Pause).

Pro vytvoření pruhu zobrazujícího přehrávanou pozici videa použijeme komponentu slider z jQuery UI.

var createSeek = function() {
    if($gVideo.attr('readyState')) {
        var video_duration = $gVideo.attr('duration');
        $ghinda_video_seek.slider({
            value: 0,
            step: 0.01,
            orientation: "horizontal",
            range: "min",
            max: video_duration,
            animate: true,
            slide: function(){
                seeksliding = true;
            },
            stop:function(e,ui){
                seeksliding = false;
                $gVideo.attr("currentTime",ui.value);
            }
        });
        $video_controls.show();
    } else {
        setTimeout(createSeek, 150);
    }
};

createSeek();

Jak vidíte, funkci voláme rekurzivně a kontrolujeme vlastnost readyState videa. Dotazujeme se na ni tak dlouho, dokud není video připraveno, do té doby neznáme délku videa a nemůžeme vytvořit slider. Jakmile je video připraveno, inicializujeme slider a zobrazíme ovládací prvky.

Nyní vytvoříme časovač (timer), který bude poslouchat událost timeupdate videa.

var gTimeFormat=function(seconds){
    var m=Math.floor(seconds/60)<10?"0"+Math.floor(seconds/60):Math.floor(seconds/60);
    var s=Math.floor(seconds-(m*60))<10?"0"+Math.floor(seconds-(m*60)):Math.floor(seconds-(m*60));
    return m+":"+s;
};

var seekUpdate = function() {
    var currenttime = $gVideo.attr('currentTime');
    if(!seeksliding) $ghinda_video_seek.slider('value', currenttime);
    $ghinda_video_timer.text(gTimeFormat(currenttime));
};

$gVideo.bind('timeupdate', seekUpdate);

Ve funkci seekUpdate přečteme atribut currentTime videa a funkcí gTimeFormat naformátujeme výstupní hodnotu času.

Na ovládání hlasitosti zvuku použijeme také slider z jQuery UI a vlastní funkci pro tlačítko na ztišení videa.

$ghinda_volume.slider({
    value: 1,
    orientation: "vertical",
    range: "min",
    max: 1,
    step: 0.05,
    animate: true,
    slide:function(e,ui){
        $gVideo.attr('muted',false);
        video_volume = ui.value;
        $gVideo.attr('volume',ui.value);
    }
});

var muteVolume = function() {
    if($gVideo.attr('muted')==true) {
        $gVideo.attr('muted', false);
        $ghinda_volume.slider('value', video_volume);

        $ghinda_volume_btn.removeClass('ghinda-volume-mute');
    } else {
        $gVideo.attr('muted', true);
        $ghinda_volume.slider('value', '0');

        $ghinda_volume_btn.addClass('ghinda-volume-mute');
    };
};

$ghinda_volume_btn.click(muteVolume);

A konečně odebereme prvku <video> atribut controls, protože teď již jsou naše vlastní ovládací prvky připraveny a chceme je používat namísto výchozích ovládacích prvků.

$gVideo.removeAttr('controls');

Nyní, když máme náš plugin hotový, můžeme ho spustit na jakémkoliv prvku <video> chceme, třeba takhle:

$('video').gVideo();

Tímto se spustí náš plugin pro všechny prvky <video> na stránce.

Vzhled a chování

A nyní k té zábavné části, tj. vzhledu a chování našeho přehrávače. Jakmile je plugin hotov, je stylování ovládacích prvků pomocí trochy CSS opravdu snadné.

Napřed nastylujeme hlavní kontejner video přehrávače.

.ghinda-video-player {
    float: left;
    padding: 10px;
    border: 5px solid #61625d;

    -moz-border-radius: 5px; /* FF1+ */
        -ms-border-radius: 5px; /* IE future proofing */
    -webkit-border-radius: 5px; /* Saf3+, Chrome */
    border-radius: 5px; /* Opera 10.5, IE 9 */

    background: #000000;
    background-image: -moz-linear-gradient(top, #313131, #000000); /* FF3.6 */
    background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #313131),color-stop(1, #000000)); /* Saf4+, Chrome */

    box-shadow: inset 0 15px 35px #535353;
}

Necháváme ho plavat doleva, abychom zabránili jeho expandování na plnou šířku přehrávače, místo toho chceme, aby byl široký stejně jako prvek <video>. Použili jsme gradienty a zakulacené rohy pro pěkný vzhled a inset box shadow, který má emulovat gradientový efekt v Opeře, která zatím gradienty nepodporuje (ve verzi 10.60, tj. při psaní původního textu).

Nyní necháme plavat doleva všechny ovládací prvky, abychom je vodorovně zarovnali. Na tlačítka Play/Pause a Volume Mute/Unmute použijeme opacity a transition (přechod) pro vytvoření pěkného hover efektu.

.ghinda-video-play {
    display: block;
    width: 22px;
    height: 22px;
    margin-right: 15px;
    background: url(../images/play-icon.png) no-repeat;

    opacity: 0.7;

    -moz-transition: all 0.2s ease-in-out; /* Firefox */
        -ms-transition: all 0.2s ease-in-out; /* IE future proofing */
        -o-transition: all 0.2s ease-in-out;  /* Opera */
    -webkit-transition: all 0.2s ease-in-out; /* Safari and Chrome */
    transition: all 0.2s ease-in-out;
}

.ghinda-paused-button {
    background: url(../images/pause-icon.png) no-repeat;
}

.ghinda-video-play:hover {
    opacity: 1;
}

V části o JavaScriptu jste viděli, jak jsme přidávali a odebírali třídy tlačítku Play/Pause podle toho, v jakém stavu se video nachází. Proto třída ghida-paused-button přepisuje vlastnost background z třídy ghinda-video-play.

A nyní k posuvníkům. Jak jste již viděli, používáme ovládací prvek slider z jQuery UI. Tato komponenta má své vlastní styly definované ve stylesheetu jQuery UI, ovšem my je kompletně přepíšeme, abychom její vzhled přizpůsobili našemu přehrávači.

.ghinda-video-seek .ui-slider-handle {
    width: 15px;
    height: 15px;
    border: 1px solid #333;
    top: -4px;

    -moz-border-radius:10px;
        -ms-border-radius:10px;
    -webkit-border-radius:10px;
    border-radius:10px;

    background: #e6e6e6;
    background-image: -moz-linear-gradient(top, #e6e6e6, #d5d5d5);
    background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #e6e6e6),color-stop(1, #d5d5d5));

    box-shadow: inset 0 -3px 3px #d5d5d5;
}

.ghinda-video-seek .ui-slider-handle.ui-state-hover {
    background: #fff;
}

.ghinda-video-seek .ui-slider-range {
    -moz-border-radius:15px;
        -ms-border-radius:15px;
    -webkit-border-radius:15px;
    border-radius:15px;

    background: #4cbae8;
    background-image: -moz-linear-gradient(top, #4cbae8, #39a2ce);
    background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #4cbae8),color-stop(1, #39a2ce));

    box-shadow: inset 0 -3px 3px #39a2ce;
}

Slider pro nastavení zvuku je nyní viditelný vždy a je umístěn vedle tlačítka Mute/Unmute. To upravíme, takže bude ve výchozím stavu skrytý a zobrazí se jen, když myší najedeme na tlačítko Mute/Unmute. A opět nám s tím pomůžou tranzice (přechody):

.ghinda-volume-box {
    height: 30px;

    -moz-transition: all 0.1s ease-in-out; /* Firefox */
        -ms-transition: all 0.1s ease-in-out; /* IE future proofing */
        -o-transition: all 0.2s ease-in-out;  /* Opera */
    -webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
    transition: all 0.1s ease-in-out;
}

.ghinda-volume-box:hover {
    height: 135px;
    padding-top: 5px;
}

.ghinda-volume-slider {
    visibility: hidden;
    opacity: 0;

    -moz-transition: all 0.1s ease-in-out; /* Firefox */
        -ms-transition: all 0.1s ease-in-out;  /* IE future proofing */
        -o-transition: all 0.1s ease-in-out;  /* Opera */
    -webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
    transition: all 0.1s ease-in-out;
}

.ghinda-volume-box:hover .ghinda-volume-slider {
    position: relative;
    visibility: visible;
    opacity: 1;
}

Slider pro nastavení zvuku skryjeme a volume kontejneru nastavíme malou pevnou výšku, do které se právě vejde Mute/Unmute tlačítko. Když na ně najedeme myší, výška se pomocí tranzice zvětší; selektor .ghinda-volume-box:hover .ghinda-volume-slider pak zajistí zobrazení slideru pomocí tranzice.

Stačily nám základní znalosti CSS a některých nových vlastností CSS3, abychom našemu přehrávači vytvořili pěkné rozhraní, viz obrázek:

Hotový přehrávač videa

Vytvořme přehrávači témata vzhledu

Jak jste si možná všimli, když jsme vytvářeli plugin pro jQuery, definovali jsme v něm několik výchozích voleb. Jedná se o theme  a childtheme, ty lze změnit při volání pluginu a umožní nám snadno aplikovat různá témata vzhledu.

Tématem vzhledu se rozumí kompletní sada nových pravidel CSS pro všechny ovládací prvky. Naopak child theme (dceřiné téma) je sada pravidel CSS, která staví na pravidlech existujícího tématu vzhledu, a rozšiřují tak nebo přepisují „rodičovský“ styl.

Při volání pluginu můžeme specifikovat obě volby nebo jen jednu.

$('video').gVideo({
    childtheme:'smalldark'
});

V tomto příkladu při volání pluginu specifikujeme child theme (dceřiné téma) smalldark. Tím se použije výchozí rodičovské téma vzhledu a následně se přes ně aplikuje naše dceřiné téma, které přepíše několik pravidel rodičovského téma vzhledu. Na obrázku uvidíte smalldark téma vzhledu v akci:

Dceřiné téma vzhledu smalldark v akci.

Obě téma vzhledu si můžete prohlédnout v akci na živé ukázce hotového přehrávače.

Z postupu popsaného v tomto článku vznikl jQuery plugin, který je připravený pro produkční nasazení. Můžete si stáhnout jeho nejnovější verzi (nebo se zapojit do vývoje) z Github repozitáře Acorn Media Playeru.

Další odkazy k HTML5 videu

Vystudoval jsem biochemii. Vymyslel a založil Zdroják. Aktuálně ho vedu. Nejsem váš hodný tatínek, který vás bude brát za ručičku, ale zlý moderátor diskusí. Smiřte se s tím!

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 5

Přehled komentářů

alblaho fuj, to je složité
Michal Re: fuj, to je složité
Tesarik Re: fuj, to je složité
Jamen To ti trval překlad článku 2 roky?
Martin Hassman Re: To ti trval překlad článku 2 roky?
Zdroj: https://www.zdrojak.cz/?p=3703