Publisert i bloggen, lørdag 14. desember 2013:

Video med HTML5

Mine erfaringer med video i HTML5 har vært begrenset, jeg har som regel forholdt meg til plattformen Vimeo og i enkelte tilfeller YouTube.

Men da jeg for en snau uke siden skulle dele timelapse-prosjektet mitt her i denne bloggen valgte jeg å gå for video i HTML5 i stedet for embedding fra tjenester som Vimeo og YouTube.

Jeg hadde sannsynligvis ikke vært like dristig om dette var på nettstedet til noen andre, da HTML5 og video ikke er 100 % standard i alle browserversjoner. Embedding fra Vimeo eller YouTube ville ha løst eventuelle kompatibilitetsproblemer, med Flash og HTML5 om hverandre, avhengig av hva som ble støttet. Men siden denne bloggen er mest for de «spesielt innvidde» valgte jeg å kjøre en hard linje. Kan du ikke se videoene mine? Ikke mitt problem!

I all enkelhet

Jeg startet med en helt enkel og strippet ned video-tag for embedding av en MP4 videofil. Jeg kunne også hatt med formatene WebM og Ogg, men MP4 støttes av de fleste, så jeg valgte å gå for dette ene formatet.

<video  width="100%" controls>
<source src="/img/timelapse-linneslia.mp4" type="video/mp4">
<p>Nettleseren din st?tter tydeligvis ikke visning av MP4-video og HTML5</p>
</video>

Resultatet:

Dette resultatet er i og for seg ganske tilfredsstillende, men jeg liker ikke helt knappene i avspilleren, som for øvrig ser helt annerledes ut i de forskjellige nettleserne.

Tilpasset mitt eget design

Oppdatering 2023: Resten av dette blogginnlegget er utdatert. Løsningen som jeg beskrev har jeg erstattet med ny teknologi og eksemplene vil mest sannsynlig ikke fungere slik de en gang gjorde.

Jeg laget derfor min egen videoavspiller med CSS og la til funksjonalitet med JavaScript:

HTML-koden jeg bruker når jeg skal legge inn en ny video i et blogginnlegg er så enkel som dette:

<p class="hardcodevideo" data-mp4-url="/img/timelapse-linneslia.mp4">

Fra placeholder til video-tag

Når siden er ferdig lastet putter jeg riktig markup inn i <class="hardcodevideo"> med jQuery. Og URL til videofilen får jeg fra data-attributtet «data-mp4-url».

Riktig markup sørger for at designet blir riktig på avspilleren, siden jeg har definert dette i CSS, blant annet ved hjelp av CSS sprites.

Jeg knytter flere «click events» til de forskjellige knappene/kontrollene, slik at play- og pauseknappen får riktig funksjonalitet. Her hadde jeg litt problemer når jeg forsøkte å kun bruke jQuery, det viste seg at det ikke var rett frem å gjøre kall til videoelementet fra jQuery, så jeg måtte gå den «tunge veien» om DOM (Document Object Model).

Neste steg var å vise en linje under videoen som viste hvor langt avspillingen var kommet. Det gjorde jeg enkelt ved å ha en <div> hvor bredden var definert i prosent, som tilsvarte samme prosent av video som var avspilt. Er 50 % av videolengden avspilt skal bredden være 50 %.

Verre var det ikke. Jeg gjengir både HTML, CSS og JavaScript nedenfor. Men husk at dette var noe jeg satte sammen i løpet av en kveld da jeg skulle vise en video i et blogginnlegg, så løsningen kan høyst sannsynlig forbedres.

HTML

<p class="hardcodevideo" data-mp4-url="/img/timelapse-linneslia.mp4">

Et problem jeg oppdaget i Chrome er at samme video-url ikke kan brukes i flere video-tagger på den samme siden, da vil bare én av de fungere. Så vidt meg bekjent finnes det ingen løsning på dette problemet, annet enn å legge til noen parametere i URL-en som gjør at Chrome behandler det som separate videofiler. Men da mister man også fordelene som caching gir, siden begge lastes som en egen fil. Et slikt parameter kan for eksempel være «videofil.mp4?i=1», «videofil.mp4?i=2» og så videre.

CSS

.hardcodevideo { background: #000; width: 100%; }
.hardcodevideo .spillknappoverlay { position: absolute; top: 0; left: -2000px; width: 128px; height: 128px; background-image: url(/style/playknapp_128x128.png); background-repeat: no-repeat; background-position: center center; opacity: 0.8; cursor: pointer; }
.hardcodevideo .spillknappoverlay:hover { opacity: 0.9; }
.hardcodevideo video { display: block; width: 100%; padding: 0; margin: 0; cursor: pointer; }
.hardcodevideo .fremdriftscontainer { background-image: url(/style/menu.png); background-repeat: repeat-x; background-position: bottom left; height: 10px; }
.hardcodevideo .fremdriftscontainer .fremdriftsindikator { background-image: url(/style/videofremdrift_bg.png); background-position: top right; height: 10px; width: 0%; }
.hardcodevideo .videokontrollere { background-image: url(/style/menu.png); background-repeat: repeat-x; color: white; height: 32px; padding: 5px; }
.hardcodevideo .videokontrollere .playknapp { opacity: 0.8; cursor: pointer; float: left; background-image: url(/style/playpause.png); background-position: 0px 0px; width: 32px; height: 32px; }
.hardcodevideo .videokontrollere .playknapp:hover { opacity: 1; }
.hardcodevideo .videokontrollere .tidspunkter { float: right; font-size: 0.8em; }

Her har jeg lagt opp til at alle videoer vises i 100 % bredde, dvs. 100 % bredde av området satt av til artikkel-/blogginnhold, noe som passer til mitt responsive design.

JavaScript

Forutsetter inkludering av jQuery-biblioteket.

var fremdriftsintervall = 0;

$( document ).ready(function() {
	$('.hardcodevideo').each(function(){
		id = Math.round((Math.random()*1000)+1000);
		mp4 = $(this).data('mp4-url');
		$(this).attr('id','videocontainer_'+id);
	  lagHardcodeVideoavspiller(id,mp4)
	});
});

function lagHardcodeVideoavspiller(id,mp4)
 {
 	$('#videocontainer_'+id).html('');
 	$('#videocontainer_'+id).append('<div class="spillknappoverlay"></div><video id="video_'+id+'"><source src="'+mp4+'" type="video/mp4"><p>Nettleseren din støtter tydeligvis ikke visning av MP4-video og HTML5</p></video>');
 	$('#videocontainer_'+id).append('<div class="fremdriftscontainer"><div class="fremdriftsindikator"></div></div>');
 	$('#videocontainer_'+id).append('<div class="videokontrollere"><div class="playknapp"></div><div class="tidspunkter"></div><div class="fullskjermknapp" style="display: none;">Fullskjerm</div></div>');
 	//$('#videocontainer_'+id).append('<input class="fullskjermknapp" type="button" value="fullscreen">');
 	
 	// play-pause knapp
	$('#videocontainer_'+id+' .videokontrollere .playknapp').click(function() {
	  videoPlayAndPause('videocontainer_'+id,'video_'+id)
	});
 	// play-pause knapp
	$('#videocontainer_'+id+' .spillknappoverlay').click(function() {
	  videoPlayAndPause('videocontainer_'+id,'video_'+id)
	});
	
	// selve videovinduet
	$('#video_'+id).click(function() {
	  videoPlayAndPause('videocontainer_'+id,'video_'+id)
	});
 	
 	// skipping
	$('#videocontainer_'+id+' .fremdriftscontainer').mousedown(function(e) {
	   fremdriftshopp('videocontainer_'+id,'video_'+id,e.pageX)
	});

	$('#videocontainer_'+id+' .fullskjermknapp').click(function() {
	   //For Webkit
	   document.getElementById('video_'+id).webkitEnterFullscreen();
	 
	   //For Firefox
	   document.getElementById('video_'+id).mozRequestFullScreen();
	 
	   return false;
	});

	// event video ferdig avspilt
	$('#video_'+id).bind("ended", function() {
		 clearInterval ( fremdriftsintervall );
	   $('#videocontainer_'+id+' .videokontrollere .playknapp').css("background-position", "0px 0px");
	   $('#videocontainer_'+id+' .fremdriftsindikator').css("width", "100%");
	   posisjonerplayknappen('videocontainer_'+id,'video_'+id);
	   $('#videocontainer_'+id+' .spillknappoverlay').show();
	});
	
	$(window).resize(function() {
	  posisjonerplayknappen('videocontainer_'+id,'video_'+id);
	});
	
	setTimeout(function(){posisjonerplayknappen('videocontainer_'+id,'video_'+id)},1000);
	setTimeout(function(){posisjonerplayknappen('videocontainer_'+id,'video_'+id)},3000);
 	
 }

function posisjonerplayknappen(containerid,videoid)
 {
 	var videoOffsetLeft = $('#'+videoid).offset().left;
 	var videoWidth = $('#'+videoid).width();
 	var videoOffsetTop = $('#'+videoid).offset().top;
 	var videoHeight = $('#'+videoid).height();
 	playknappLeft = videoOffsetLeft + ((videoWidth-128)/2);
 	playknappTop = videoOffsetTop + ((videoHeight-128)/2);
 	$('#'+containerid+' .spillknappoverlay').css('left', playknappLeft+'px');
 	$('#'+containerid+' .spillknappoverlay').css('top', playknappTop+'px');
 }



function fremdriftshopp(containerid,videoid,xposisjon)
 {
 	posisjonerplayknappen(containerid,videoid);
 	$('.fremdriftscontainer').offset().left;
 	hopptilprosent = (xposisjon - $('.fremdriftscontainer').offset().left) / $('.fremdriftscontainer').width();
 	hopptilsekund = document.getElementById(videoid).duration * hopptilprosent;
	$('#'+containerid+' .fremdriftsindikator').css("width", hopptilprosent+"%");
  document.getElementById(videoid).currentTime = hopptilsekund;
 }

function videofremdrift(containerid,videoid)
 {
 	var totallengde = document.getElementById(videoid).duration;
 	var avspiltlengde = document.getElementById(videoid).currentTime;
 	var prosentvisavspilt = ((avspiltlengde/totallengde)*100);
 	$('#'+containerid+' .fremdriftsindikator').css("width", prosentvisavspilt+"%");
 	$('#'+containerid+' .tidspunkter').html(baresekundertilminutterogsekunder(avspiltlengde)+' / '+baresekundertilminutterogsekunder(totallengde));
 }

function videoPlayAndPause(containerid,videoid)
 {
 	posisjonerplayknappen(containerid,videoid);
 	if($('#'+containerid+' .playknapp').css("background-position")=="0px 0px") // play er trykket
 	 {
 	 	fremdriftsintervall = setInterval ( "videofremdrift('"+containerid+"','"+videoid+"')", 50 );
 	 	document.getElementById(videoid).play();
 	 	$('#'+containerid+' .spillknappoverlay').hide();
 	 	$('#'+containerid+' .playknapp').css("background-position", "32px 0px");
 	 }
 	else // pause er trykket
 	 {
 	 	clearInterval ( fremdriftsintervall );
 	 	document.getElementById(videoid).pause();
 	 	$('#'+containerid+' .spillknappoverlay').show();
 	 	$('#'+containerid+' .playknapp').css("background-position", "0px 0px");
 	 }
 }

function baresekundertilminutterogsekunder(sekunder)
 {
 	if(sekunder>60) // vi har også minutter
 	 {
 	 	minutter = Math.floor(sekunder/60);
 	 	sekunder = sekunder - (minutter*60);
 	 }
 	else
 	 {
 	 	minutter = 0;
 	 }
 	sekunder = Math.floor(sekunder);
 	if(sekunder==60) // det tar seg dårlig ut med 60 sekunder
 	 {
 	 	sekunder = 59;
 	 }
 	if(sekunder<10)
 	 {
 	 	sekunder = '0'+sekunder;
 	 }
 	return minutter+':'+sekunder;
 }

Mulige forbedringer

Relatert innhold

Gigantisk timelapse
Hva er jQuery?
CSS -sprites

Bloggen

Paid and organic last click
Are og Ida på date
Kunstig intelligens
Vekst- prosjektet
Da Outlook stjal ikonet mitt
Sen eller tidlig påske?
Koordinater i SVG
Påstand: Corner er mål
Vestfold-Rogaland kalkulator
Twitter og VM på ski
My New Year's Resolutions
Et bilde sier mer enn tusen ord
Rogaland blir nye Vestfold
På størrelse med Vestfold
Datoformat i Excel og Google Analytics
what3words Hvilke tre ord?
Covfefe will make America great again
Om domenenavn og firmanavn
Fotballfrue: Jeg tar innpå deg
Sakte-TV: Se gresset gro
Sakte-TV: Se maling tørke
Første generasjon iPapp har kommet
Jukselapp fotografering
Det sorte hullet cookies disabled
Høysesong for kjipe annonser
Om analsex og popups
Rotasjon av vindsymboler
Hvor mye er Fotballfrue verdt?
Slik tar du et screenshot
Nyttige husketrekanter
Enklere utregning med kryssmultiplisering
Min egen lille adventskalender
Logge antall likes på Facebook
Hva er sitemap.xml?
Hva er robots.txt?
Responsivt design
Webscraping med PHP
Jeg sammenligner epler og pærer
Scalable Vector Graphics
Google Analytics API: Hente data
Google Analytics API: Muligheter
HTML5: Video
Big Data
Cookies: Hvordan det brukes
Cookies: Hva er det?
Excel i to vinduer
CRM-systemet «Kontor»
Gigantisk timelapse
Hva er jQuery?
Overvåke ReadyNAS DUO med PHP
Favicon - ikonet i adressefeltet
Animert heading på hardcode.no
CSS -sprites
Komprimere PNG-bilder
Redesign av hardcode.no
Klikkbar flash uten clickTAG
Relevans har stor verdi
Alle har wide- screen i 2013
Markedsandeler nettlesere 2010
Internet Explorer-vindu i feil størrelse
Hvor stor er en piksel?
Markedsføring og kundelojalitet
Flash-versjoner
Vestre Sylling og Øverskogen JFF
Sidevisninger, besøk og brukere
Widescreen kommer
Hvor brede bør sidene være?
Fortsatt lese hele saken?
Lese hele saken nå?
Første møte med AdWords
Bort med IE6
Utviklingen på nettleserfronten
Nyttige jukselapper
Nye Sylling.no
Klær med egen logo?
Værdata fra yr.no
Logodesign trender i 2008
Gmail grimaser
Google Analytics
Publiseringssystemet Outpost
Hardcode.no relanseres
Publiserings -systemet