Script om in kleiner venster kleinere video's te downloaden - uitleg

Skip links en inhoudsopgave

Laatst aangepast: .

Afbeelding 1: de videospeler in kleinere en grotere vensters

Korte omschrijving

Met behulp van JavaScript worden in een smaller browservenster kleinere video's gedownload, wat sneller is en bandbreedte bespaart.

BELANGRIJK

Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.

Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.

Als je dit lastig vindt, downloadt dan de hele handel (ga terug naar het voorbeeld en kies daar voor downloaden). In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.

Alles op deze site kan vrij worden gebruikt, met twee beperkingen:

* Je gebruikt het materiaal op deze site volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte info zitten. Voor eventuele schade die door gebruik van materiaal van deze site ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.

* Deze uitleg wordt regelmatig bijgewerkt. Het is daarom niet toegestaan deze uitleg op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat de uitleg afkomstig is van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.

Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.

Alle code is geschreven in een afwijkende lettersoort en -kleur. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles vanwege de leesbaarheid in een gewone letter.)

Opmerkingen

Links in deze uitleg, vooral links naar andere sites, kunnen verouderd zijn. Op de pagina met links vind je steeds de meest recente links.

Dit voorbeeld is gemaakt op een systeem met Linux (Kubuntu). Daarbij is vooral gebruik gemaakt van Komodo Edit, GIMP en Firefox met extensies. De pdf-bestanden zijn gemaakt met LibreOffice.

Vragen of opmerkingen? Fout gevonden? Ga naar het forum.

Iets gevonden waar je wat aan hebt? Mooi. Als je je waardering wilt uiten, maak dan een donatie over aan War Child Nederland, een organisatie die kinderen uit oorlogsgebieden helpt hun trauma's te verwerken. Of - nog beter - wordt donateur:
War Child Nederland

Korte handleiding hoe het script te gebruiken

Je wilt alleen weten, hoe je dit script kunt gebruiken, en de rest zal je worst wezen? Dan moet je hier zijn.

Het maakt niet uit, hoeveel of hoe weinig <video>-elementen er op een pagina staan.

Als voor een bepaald <video>-element grote en kleine video's beschikbaar zijn, moet in dat <video>-element de breedte worden opgegeven, waaronder de kleine video gebruikt gaat worden:

<video data-smscr="480" (...) rest van de code (...) >

Als het browservensters smaller dan 480 px is, kijkt het script of er een kleinere video aanwezig is. De maat móét als waarde van het attribuut data-smscr worden opgegeven, in pixels tussen aanhalingstekens, maar zonder 'px'. Dus gewoon als getal. Je kunt desgewenst verschillende breedtes opgeven bij verschillende <video>'s.

Binnen het <video>-element komen de <source>'s. De grote video móét boven de kleine video staan. (Anders zal elke browser altijd de kleine video afspelen.) De volgorde van het formaat (eerst 'mp4', of eerst 'webm', of eerst 'ogg', of eerst ...) maakt niet uit.

Verder móét de kleine video het attribuut data-smscr met als waarde 'small' hebben:

<source data-smscr="small" src="..." type="">

Dat is alles. In browservensters smaller dan – in dit geval – 480 px zal nu de kleine video worden gebruikt.

Achterliggend idee

Tot voor ongeveer 'n jaar geleden was het ongelooflijk moeilijk om naar een mobieltje een kleinere afbeelding te sturen dan naar een breedbeeldmonitor. Dat is fantastisch opgelost met <srcset>, waarin je suggesties voor de te downloaden afbeelding kunt geven. Op een mobieltje zal de browser dan een (veel) kleinere afbeelding downloaden dan op een breedbeeldmonitor. Wat enorm veel tijd en bandbreedte scheelt.

In het html5-element <picture> is dit probleem opgelost, doordat daarin gebruik gemaakt kan worden van media query's. Al even fantastisch.

<video> had dit al jaren geleden opgelost: je kon in het <video>-element media query's gebruiken en daardoor bijvoorbeeld naar een smaller browservenster een kleinere video sturen. Dit was zelfs al jarenlang in alle grotere browsers geïmplementeerd.

Kortom: iedereen gelukkig. Zowel voor afbeelding als voor video's kon het te downloaden bestand op simpele wijze worden aangepast aan de grootte van het browservenster.

Hoewel, iederéén gelukkig?

Kennelijk niet. In precies hetzelfde tijdvak waarin de oplossingen met <picture> en <srcset> werden ingevoerd, heeft w3c de media query's bij <video> verwijderd. Waarom? Joost mag het weten. Of eigenlijk weet Joost het wel: op de discussielijst van w3c werden argumenten aangevoerd, die net zo goed voor <srcset> en <picture> gelden. Er was ook wel wat tegenstand, maar omdat media query's bij <video> weinig bekend waren, is het toch verwijderd.

Waarom je iets dat goed werkt en in alle browsers is geïmplementeerd, waarnaar in honderden handleidingen in boeken en op internet wordt verwezen, enz., enz., verwijdert en gelijktijdig bij twee andere elementen iets soortgelijks ingevoerd? Ik vrees dat slechts een in zelfhaat of hooliganisme gespecialiseerd psychoanalyticus daar achter kan komen.

Vandaar dit script. Wat ooit dodelijk simpel kon, daar heb je nu een script voor nodig. En om dat maar gelijk gezegd te hebben: dit script is waarschijnlijk niet het meest efficiënte, hoewel het snel genoeg is. Mogelijk wordt het te traag, als je honderden video's op 'n pagina hebt staan, maar ik vermoed dat 'n site als YouTube niet echt zit te wachten op dit script.

Het script zelf hoeft niet gewijzigd te worden. Alle benodigde gegevens worden gewoon in de html opgegeven. Als je het script ingewikkelder zou maken, zou het mogelijk wat efficiënter kunnen werken, maar het moest simpel blijven. Het moet werken, zonder dat het script zelf gewijzigd hoeft te worden.

In elk <video>-element zitten vier <source>'s: een grote en een kleine video in mp4-formaat, en een grote en een kleine video in webm-formaat. Daarmee worden alle browsers bestreken. Maar voor het script maakt het niets uit, hoeveel <source>'s er zijn. Als er maar een grote en een kleine versie aanwezig is. (Als er maar één versie aanwezig is, is er nog niets aan de hand, maar dan heeft het script gewoon geen enkele invloed.)

De volgorde van de <source>'s in het <video>-element is van belang. Een browser loopt van boven naar beneden alle <source>'s af en gebruikt de eerste video, die afgespeeld kan worden. In het voorbeeld staan de webm-video's boven de mp4-video's. Een browser die met webm uit de voeten kan, bekijkt de mp4-video's niet eens.

Omdat de browser de bovenste afspeelbare video gebruikt, staan de grote video's boven de kleine. Zonder script zal de browser altijd de grote video afspelen, ook op een mobieltje, omdat die nou eenmaal bovenaan staat. Het script maakt hiervan gebruik, door in een smaller browservenster de kleine video boven de grote video te zetten.

De volgorde van webm, mp4, ogg, of welk formaat dan ook maakt niet uit, als de grote video maar steeds boven de kleine video staat.

Onderaan de html-pagina staat een link naar het script.

Als de pagina is geladen, maakt het script een lijstje van alle <video>-elementen. Als er geen <video>'s zijn, gebeurt er verder niets.

Vervolgens wordt de breedte van het browservenster opgevraagd.

Bij elke <video> wordt vervolgens gekeken, of daarbij het attribuut data-smsrc="..." aanwezig is. Een attribuut dat met data- begint, mag overal voor worden gebruikt. Het is ideaal om aan JavaScript bepaalde gegevens door te geven. Op de plaats van de puntjes staat een getal. In het voorbeeld is dat '480': als de breedte van het browservenster kleiner dan 480 px is, wordt de kleine video gebruikt.

(Door bij verschillende <video>'s verschillende waarden op te geven bij data-smsrc, kun je per video opgeven bij welke breedte de kleinere video gebruikt moet gaan worden.)

Als bij <video> het attribuut data-smsrc="..." aanwezig is, én als op de plaats van de puntjes een getal staat, én als de breedte van het browservenster in px kleiner is dan dat getal, dan wordt gekeken of er een kleinere video beschikbaar is. Als dit niet zo is, wordt met de volgende <video> doorgegaan. Je kunt dus op één pagina <video>'s met en zonder kleinere alternatieve video gebruiken.

Als de <video> aan bovenstaande voorwaarden voldoet, wordt door het script een lijstje van alle <source>'s bij die <video> gemaakt. Als bij een <source> het attribuut data-smsrc="small" aanwezig is, wordt die <source> verder bekeken. Als er geen data-smsrc="small" aanwezig is, wordt met de volgende <source> verder gegaan, tot alle <sources>'s zijn bekeken. Als bij geen enkele <source> data-smsrc="small" aanwezig is, wordt met de volgende <video> verder gegaan. Er gebeurt dan dus niets.

Goed, er is dus een <source> met data-smsrc="small". Bij die <source> wordt de extensie van de video ingelezen. In het voorbeeld is dat 'webm' of 'mp4', omdat je daarmee alle browsers beslaat, maar het mogen ook andere extensies zijn.

Vervolgens wordt gekeken, of de browser die soort video kan afspelen. Als dat zo is, wordt die video als bron opgegeven bij src in het <video>-element. Het script voegt dat automatisch in bij het betreffende <video>-element op de pagina met html. Omdat die video bovenaan staat, zal de browser nu die video afspelen.

Omdat er een kleinere video is gevonden voor deze <video>, worden verdere <source>'s niet bekeken en wordt met de volgende <video> verder gegaan.

Als de video bij die <source> niet kan worden afgespeeld door de browser, wordt met de volgende <source> bij de <video> verder gegaan, net zolang tot er een afspeelbare kleinere video is gevonden. Als er geen kleinere afspeelbare video wordt gevonden, gebeurt er gewoon verder niets bij die <video>.

In het voorbeeld is de inhoud van de grotere en kleinere video's hetzelfde, maar dat hoeft niet. Je kunt prima voor bredere browservensters een video van de paashaas gebruiken, en voor smallere vensters een video met de kerstman gebruiken. Of, iets realistischer: een video waarin alleen het belangrijkste deel is te zien.

Als je de veranderde html wilt bekijken, moet dat op een speciale manier. Als je de broncode van de html-pagina bekijkt, zie je gewoon de html die je zelf hebt beschreven. Als je de door het script gewijzigde html wilt bekijken, moet je de Gegenereerde code bekijken. In een browservenster dat smaller is dan 480 px, want in bredere vensters verandert er niets.

Het hele verhaal nog 'ns heel kort samengevat: als voor een smaller browservenster een kleinere video beschikbaar is, geef je dat als volgt aan:

* Zet in de betreffende <video> het attribuut data-smscr="...", met op de plaat van de puntjes het aantal px, waaronder een kleinere video moet worden gebruikt.

* Zet in de <source> van de kleinere video het attribuut data-smscr="small" (met in de src uiteraard de bestandsnaam van de kleinere video).

Gegenereerde code

Het onderstaande geldt alleen voor desktopbrowsers. In browsers op mobiele systemen is het vaak ook mogelijk gegenereerde code te bekijken, maar dat is veel ingewikkelder. Bovendien verandert de manier, waarop dat kan, nogal snel.

Als je html schrijft, kan dat (hopelijk) in de browser worden weergegeven. Vanuit de browser kun je die html bekijken, precies zoals je hem hebt ingevoerd. Alsof je het in een editor ziet. In Firefox bijvoorbeeld kan dat door ergens op de pagina te rechtsklikken en te kiezen voor Paginabron bekijken, of door in het menu te kiezen voor Extra → Webontwikkelaar → Paginabron. (Of door de veel snellere sneltoets Ctrl+U.) Elke browser heeft dit soort mogelijkheden.

Wat je dan te zien krijgt, is exact de code, zoals jij die hebt ingetypt. Inclusief alle fouten, hoofd- en kleine letters, noem maar op. Als je zo slordig bent om een <p> niet af te sluiten, zit er niet plotsklaps een afsluitende </p> in de code. Als er css wordt gebruikt, html wordt ingevoegd via JavaScript, noem maar op, zie je daar niets van, want dat heb jij niet ingetypt.

Daar heb je dus eigenlijk vrij weinig aan, want die code kende je al. Die heb je zelf bloedig zitten intypen.

Wat de browser daadwerkelijk gebruikt, is iets totaal anders: de gegenereerde code. En die is veel interessanter, want die code blijkt (fors) af te wijken van wat jij heb ingetypt. De browser gebruikt een tijdelijke kopie van de door jou geschreven code, die zo is aangepast dat er voor de browser mee te werken is.

Elke browser heeft inmiddels mogelijkheden om de gegenereerde code te bekijken. In Firefox bijvoorbeeld in het menu Extra → Webontwikkelaar → Hulpmiddelen in-/uitschakelen. In Google Chrome in het menu onder Meer hulpprogramma's → Hulpprogramma's voor ontwikkelaars. In Internet Explorer open je dit door op F12 te drukken, en het kan vast ook via het menu.

Houdt er wel rekening mee dat elke browser de door jou ingetypte code iets zal aanpassen. In Firefox bijvoorbeeld wordt een <P> veranderd in een <p>. Als er 'n </p> mist, is die opeens wel aanwezig in de gegenereerde code. Wat elke browser precies aanpast, zal iets verschillen en kan ook nog veranderen. In het verleden veranderde Internet Explorer bijvoorbeeld een <p> juist in een <P>, nu is dat niet meer zo.

Semantische elementen en WAI-ARIA

Deze twee onderwerpen zijn samengevoegd, omdat ze veel met elkaar te maken hebben.

Semantische elementen

De meeste elementen die in html worden gebruikt, hebben een semantische betekenis. Dat wil zeggen dat je aan de gebruikte tag al (enigszins) kunt zien, wat voor soort inhoud er in het element staat. In een <h1> staat een belangrijke kop. In een <h2> staat een iets minder belangrijke kop. In een <p> staat een alinea. In een <table> staat een tabel (en geen lay-out, als het goed is!). Enz.

Door het op de goede manier gebruiken van semantische elementen, kunnen zoekmachines, schermlezers, enz. de structuur van een pagina begrijpen. De spider van een zoekmachine is redelijk te vergelijken met een blinde. Het is dus ook in je eigen belang om semantische elementen zo goed mogelijk te gebruiken. Een site die toegankelijk is voor mensen met een handicap, is in de regel ook goed te verwerken door een zoekmachine en maakt dus een grotere kans gevonden en bezocht te worden.

Als het goed is, wordt het uiterlijk van de pagina bepaald met behulp van css. Het uiterlijk staat hierdoor (vrijwel) los van de semantische inhoud van de pagina. Met behulp van css kun je een <h1> heel klein weergeven en een <h6> heel groot, terwijl schermlezers, zoekmachines, en dergelijke nog steeds weten dat de <h1> een belangrijke kop is.

Slechts enkele elementen, zoals <div> en <span>, hebben geen semantische betekenis. Daardoor zijn deze elementen uitstekend geschikt om met behulp van css het uiterlijk van de pagina aan te passen: de semantische betekenis verandert niet, maar het uiterlijk wel. Voor een schermlezer of zoekmachine verandert er (vrijwel) niets, voor de gemiddelde bezoeker krijgt het door de css een heel ander uiterlijk.

(De derde laag, naast html voor de inhoud en css voor het uiterlijk, is JavaScript. Die zorgt voor de interactie tussen site en bezoeker. De min of meer strikte scheiding tussen css en html aan de ene kant en JavaScript aan de andere kant is met de komst van css3 en html5 veel vager geworden. Je kunt nu bijvoorbeeld ook met css dingen langzaam verplaatsen en met html deels de invoer in formulieren controleren.)

Html5 heeft een aantal nieuwe elementen, die speciaal zijn bedoeld om de opbouw van een pagina aan te geven. In dit voorbeeld worden hiervan <main> en <section> gebruikt. Beide gedragen zich als een gewone <div>, maar dan een <div> met een semantische betekenis. Hierdoor kunnen schermlezers, zoekmachines, en dergelijke beter zien, hoe de pagina is samengesteld.

<main>

Hierbinnen staat de belangrijkste inhoud van de pagina (in dit voorbeeld zijn dat de vier video's met bijbehorende links en dergelijke).

<section>

Een min of meer samenhangend deel van de pagina. In dit voorbeeld staat elke <video> met bijbehorende titel, links, en dergelijke in een eigen <section>.

Met behulp van dit soort nieuwe semantische elementen kan bijvoorbeeld een schermlezer in één keer een heel menu passeren en gelijk naar de echte inhoud gaan. Alleen hadden deze nieuwe elementen tot voor kort één probleem: ze hadden in de praktijk nog weinig nut, omdat schermlezers en dergelijke ze nog niet herkenden. Daarom werd een zogenaamde WAI-ARIA-code toegevoegd aan deze elementen. Dat is een al veel langer bestaande code, die schermlezers en dergelijke wel herkennen. Voor <main> ziet dat er zo uit:

<main role="main">

Inmiddels is dit behoorlijk veranderd. Het advies is nu om deze speciale toevoeging niet meer te gebruiken, omdat de meeste schermlezers en dergelijke dit soort nieuwe elementen inmiddels herkennen.

WAI-ARIA-codes

WAI-ARIA wordt vaak ingekort tot ARIA. Voluit betekent het Web Accessibility Initiative – Accessible Rich Internet Applications.

Er wordt in dit voorbeeld één WAI-ARIA-code gebruikt: aria-labelledby.

aria-labelledby

Met behulp van aria-labelledby="..." kan een element worden gekoppeld aan een (korte) beschrijving. Op de normale weergave op het scherm heeft dit verder geen enkele invloed.

In dit voorbeeld wordt het bij <video> gebruikt:

<video data-smscr="480" aria-labelledby="titel-1" controls preload="metadata" poster="116-images/elliot_b_senior_project_with_after_effects.jpg">

Dit is de eerste <video>. Het volledige WAI-ARIA-attribuut is hier aria-labelledby="titel-1". 'titel-1' verwijst naar de id van het element, waar de beschrijving is te vinden:

<h2 id="titel-1" lang="en">Elliot B senior project with after effects</h2>

Dit is de <h2> die boven de eerste <video> staat. De id van deze <h2> is 'titel-1', de id waar aria-labelledby naar verwijst. Nu is voor schermlezers en dergelijke duidelijk dat dit de titel van de video is.

De code aanpassen aan je eigen ontwerp

Toegankelijkheid en zoekmachines

Het eerste deel van deze tekst is voor alle voorbeelden hetzelfde. Eventueel specifiek voor dit voorbeeld geldende dingen staan verderop onder het kopje Specifiek voor dit voorbeeld.

Toegankelijkheid (in het Engels 'accessibility') is belangrijk voor bijvoorbeeld blinden die een schermlezer gebruiken, of voor motorisch gehandicapte mensen die moeite hebben met het bedienen van een muis. Een spider van een zoekmachine (dat is het programmaatje dat de site indexeert voor de zoekmachine) is te vergelijken met een blinde. Als je je site goed toegankelijk maakt voor gehandicapten, is dat gelijk goed voor een hogere plaats in een zoekmachine. Dus als je 't niet uit sociale motieven wilt doen, kun je 't uit egoïstische motieven doen.

(Op die plaats in de zoekmachine heb je maar beperkt invloed. De toegankelijkheid van je site is maar één van de factoren, maar zeker niet onbelangrijk.)

Als je bij het maken van je site al rekening houdt met toegankelijkheid, is dat nauwelijks extra werk. 't Is ongeveer te vergelijken met inbraakbescherming: doe dat bij 'n nieuw huis en 't is nauwelijks extra werk, doe 't bij 'n bestaand huis en 't is al snel 'n enorme klus.

Enkele tips die helpen bij toegankelijkheid:

Specifiek voor dit voorbeeld

Getest in

Laatst gecontroleerd op 15 november 2016

Onder dit kopje staat alleen maar, hoe en waarin is getest. Eventuele problemen, ook die met betrekking tot zoomen en lettergroottes, staan hieronder bij Bekende problemen (en oplossingen). Het is belangrijk dat deel te lezen, want uit een test kan ook prima blijken dat iets totaal niet werkt!

Eventuele opmerkingen over de toegankelijkheid specifiek voor dit voorbeeld staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld.

Dit voorbeeld is getest op de volgende systemen:

Er is op de aan het begin van dit hoofdstukje genoemde controledatum getest in de meest recente versie van de browser, die op het betreffende besturingssysteem kon draaien. Het aantal geteste browsers en systemen is al tamelijk fors, en als ook nog rekening gehouden moet worden met (zwaar) verouderde browsers, is het gewoon niet meer te doen. Surfen met een verouderde browser is trouwens vragen om ellende, want updates van browsers hebben heel vaak met beveiligingsproblemen te maken.

In resoluties groter dan 800x600 is ook in- en uitzoomen en – voor zover de browser dat kan – een kleinere en grotere letter getest. Er is ingezoomd en vergroot tot zover de browser kan, maar niet verder dan 200%.

Er is getest met behulp van muis en toetsenbord, behalve op de iPad, Android, Windows Phone en Windows 10 Mobile, waar een touchscreen is gebruikt. Op Windows 8.1 en 10 is getest met een touchscreen, met een combinatie van toetsenbord en touchpad, en met een combinatie van toetsenbord en muis.

Als dat relevant is, is op de desktop ook getest, als JavaScript uitstaat. Eventuele problemen staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld. (Op iOS, Android, Windows Phone en Windows 10 Mobile is niet getest zonder JavaScript, omdat je JavaScript in een toenemend aantal mobiele browsers niet uit kunt zetten. Bovendien is een mobiel apparaat zonder JavaScript niet veel meer dan een duur en groot uitgevallen horloge.)

Naast deze 'gewone' browsers is ook getest in Lynx, WebbIE, NVDA, TalkBack, VoiceOver en ChromeVox.

Lynx is een browser die alleen tekst laat zien en geen css gebruikt. Er is getest op Linux.

WebbIE is een browser die gericht is op mensen met een handicap. Er is getest op Windows 7.

NVDA is een schermlezer, zoals die door blinden wordt gebruikt. Er is getest in combinatie met Firefox op Windows 7 en Firefox op Windows 10.

TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome.

VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS en OS X.

ChromeVox is een schermlezer in de vorm van een extensie bij Google Chrome. Er is getest op een systeem met Kubuntu Linux.

Als het voorbeeld in deze programma's toegankelijk is, zou het in principe toegankelijk moeten zijn in alle aangepaste browsers en dergelijke. En dus ook voor zoekmachines, want een zoekmachine is redelijk vergelijkbaar met een blinde. Eventuele opmerkingen over de toegankelijkheid specifiek voor dit voorbeeld staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld.

Alleen op de hierboven genoemde systemen en browsers is getest. Er is dus niet getest op bijvoorbeeld 'n Blackberry. De kans is (heel erg) groot dat dit voorbeeld niet (volledig) werkt op niet-geteste systemen en apparaten. Om het wel (volledig) werkend te krijgen, zul je vaak (kleine) wijzigingen en/of (kleine) aanvullingen moeten aanbrengen, bijvoorbeeld met JavaScript.

Er is ook geen enkele garantie dat iets werkt in een andere tablet of smartphone dan hierboven genoemd, omdat fabrikanten in principe de software kunnen veranderen. Dit is anders dan op de desktop, waar browsers altijd (vrijwel) hetzelfde werken, zelfs op verschillende besturingssystemen. Iets wat in Android browser werkt, zal in de regel overal werken in die browser, maar een garantie is er niet. De enige garantie is het daadwerkelijk testen op een fysiek apparaat. En aangezien er duizenden mobiele apparaten zijn, is daar eigenlijk geen beginnen aan.

De html is gevalideerd met de validator van w3c, de css ook. Als om een of andere reden niet volledig gevalideerd kon worden, wordt dat bij Bekende problemen (en oplossingen) vermeld.

Nieuwe browsers worden pas getest, als ze uit het bèta-stadium zijn, omdat er anders 'n redelijke kans is dat je tegen 'n bug zit te vechten, die voor de uiteindelijke versie nog gerepareerd wordt. Dit voorbeeld is alleen getest in de hierboven met name genoemde browsers. Vragen over niet-geteste browsers kunnen niet worden beantwoord, en het melden van fouten in niet-geteste browsers heeft ook geen enkel nut. (Melden van fouten, problemen, enz. in wel geteste browsers: graag!)

Bekende problemen (en oplossingen)

Waarop en hoe is getest, kun je gelijk hierboven vinden bij Getest in.

Als je hieronder geen oplossing vindt voor een probleem dat met dit voorbeeld te maken heeft, kun je op het forum proberen een oplossing te vinden voor je probleem. Om forumspam te voorkomen, moet je je helaas wel registreren, voordat je op het forum een probleem kunt aankaarten.

Beetje saai, maar er zijn geen bekende problemen.

Wijzigingen

Alleen grotere wijzigingen worden hier vermeld, geen dingen als een link die is geüpdatet.

:

Nieuw opgenomen.

Inhoud van de download en licenties

De inhoud van deze download kan vrij worden gebruikt, met drie beperkingen:

* Sommige onderdelen die van 'n andere site of zo afkomstig zijn, vallen mogelijk onder een of andere licentie. Dat is hieronder bij het betreffende onderdeel te vinden.

* Je gebruikt het materiaal uit deze download volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte code en dergelijke zitten. Voor eventuele schade die door gebruik van materiaal uit deze download ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.

* Dit voorbeeld (en de bijbehorende uitleg en dergelijke) wordt regelmatig bijgewerkt. Het is daarom niet toegestaan dit voorbeeld (en de bijbehorende uitleg en dergelijke) op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat voorbeeld, uitleg, en dergelijke afkomstig zijn van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.

Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.

afbeelding-116-dl.html: de pagina met het voorbeeld.

afbeelding-116.pdf: de uitleg (aangepast aan de inhoud van de download).

afbeelding-116-inhoud-download-en-licenties.txt: een kopie van de tekst onder dit kopje (Inhoud van de download en licenties).

116-css-dl:

afbeelding-116-dl.css: stylesheet voor afbeelding-116-dl.html.

116-images:

elliot_b_senior_project_with_after_effects.jpg: screenshot videospeler linksboven.

how_to_drive_fast_with_david_rodriguez.jpg: screenshot videospeler rechtsboven.

peer_tutoring_program_by_angelina_g.jpg: screenshot videospeler linksonder.

making_video_a_game_with_bill_decker.jpg: screenshot videospeler rechtsonder.

116-js:

afbeelding-116.js: javascript dat de grootte van de video's regelt.

afbeelding-116-met-commentaar: zelfde als afbeelding-116.js, maar met commentaar.

116-video:

Deze map bevat alle video's. Van elke video zijn vier stuks aanwezig: een grote in webm-formaat, een kleine in webm-formaat, een grote in mp4-formaat en een kleine in mp4-formaat. De kleine zijn herkenbaar aan het woord 'klein' in de naam. De video's zijn afkomstig van het Internet Archive. Op de pagina met het voorbeeld staat boven elke video de precieze pagina op die website.

De video's vallen onder de Public Domain Creative Commons license: Creative Commons.

HTML

De code is geschreven in een afwijkende lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)

In de html hieronder wordt alleen de html besproken, waarover iets meer is te vertellen. Een <h1> bijvoorbeeld wordt in de regel niet genoemd, omdat daarover weinig interessants valt te melden. (Als bijvoorbeeld het uiterlijk van de <h1> wordt aangepast met behulp van css, staat dat verderop bij de bespreking van de css.)

Zaken als een doctype en charset hebben soms wat voor veel mensen onbekende effecten, dus daarover wordt hieronder wel een en ander geschreven.

<!DOCTYPE html>

Een document moet met een doctype beginnen om weergaveverschillen tussen browsers te voorkomen. Zonder doctype is de kans op verschillende (en soms volkomen verkeerde) weergave tussen verschillende browsers heel erg groot.

Geldige doctypes vind je op www.w3.org/QA/2002/04/valid-dtd-list.

Gebruik het volledige doctype, inclusief de eventuele url, anders werkt het niet goed.

Het hier gebruikte doctype is dat van html5. Dit kan zonder enig probleem worden gebruikt: het werkt zelfs in Internet Explorer 6.

<html lang="nl">

De toevoeging lang="nl" bij <html> geeft aan dat de pagina in het Nederlands is. De taal is van belang voor schermlezers, automatisch afbreken, automatisch genereren van aanhalingstekens, juist gebruik van decimale punt of komma, en dergelijke.

<meta charset="utf-8">

Zorgt dat de browser letters met accenten en dergelijke goed kan weergeven.

utf-8 is de beste charset (tekenset), omdat deze alle talen van de wereld (en nog heel veel andere extra tekens) bestrijkt, maar toch niet meer ruimte inneemt voor de code, dan nodig is. Als je utf-8 gebruikt, hoef je veel minder entiteiten (&auml; en dergelijke) te gebruiken, maar kun je bijvoorbeeld gewoon ä gebruiken.

Deze regel moet zo hoog mogelijk komen te staan, als eerste regel binnen de head, omdat hij anders door sommige browsers niet wordt gelezen.

In html5 hoeft deze regel niet langer te zijn, dan wat hier staat.

<meta name="viewport" content="width=device-width, initial-scale=1">

Mobiele apparaten variëren enorm in breedte. En dat is een probleem. Sites waren, in ieder geval tot voor kort, gemaakt voor desktopbrowsers. En die hebben, in vergelijking met bijvoorbeeld een smartphone, heel brede browservensters. Hoe moet je op 'n smartphone een pagina weergeven, die is gemaakt voor de breedte van een desktop? Je kunt natuurlijk wachten tot álle sites zijn omgebouwd voor smartphones, tablets, enz., maar dan moet je waarschijnlijk heel erg lang wachten.

Mobiele browsers gokken erop dat een pagina een bepaalde breedte heeft. Safari voor mobiel bijvoorbeeld gaat ervan uit dat een pagina 980 px breed is. De pagina wordt vervolgens zoveel versmald dat hij binnen het venster van het apparaat past. Op een iPhone wordt de pagina dus veel smaller dan op een iPad. Vervolgens kan de gebruiker inzoomen op het deel van de pagina dat hij of zij wil zien.

Dit betekent ook dat bij het openen van de pagina de tekst meestal heel erg klein wordt weergegeven. (Meestal, want niet alle browsers en apparaten doen het op dezelfde manier.) Niet erg fraai, maar bedenk maar 'ns 'n betere oplossing voor bestaande sites.

Nieuwe sites of pagina's kunnen echter wel rekening houden met de veel kleinere vensters van mobiele apparaten. In dit voorbeeld worden in smallere vensters kleinere video's getoond. De bijbehorende titel, link, en dergelijke worden ook verkleind. Maar die stomme mobiele browser weet dat niet, dus die gaat ervan uit dat ook de al aangepaste pagina 980 px breed is, en verkleint die dan. Dat is ongeveer even behulpzaam als de gedienstige kelner die behulpzaam de stoel naar achteren trekt, net als jij wilt gaan zitten.

Om de door de browser aangeboden hulp vriendelijk maar beslist te weigeren, wordt deze tag gebruikt. Hiermee geef je aan dat de pagina is geoptimaliseerd voor mobiele apparaten.

Een iPad in portretstand bijvoorbeeld is 768 px breed. De kreet width=device-width zegt tegen de mobiele browser dat de breedte van de weer te geven pagina gelijk is aan de breedte van het apparaat. Voor een iPad in portretstand dus 768 px.

En dat klopt, want in smallere vensters worden de titels, links, en dergelijke automatisch ook smaller. Er is op deze pagina niets, wat problemen kan opleveren in een smaller browservenster.

Simpeler gezegd: je zegt tegen het mobiele apparaat dat de pagina geen vaste breedte heeft, en dat het dus niet nodig is om de weergave aan te passen.

Er staat nog een tweede deel in de tag: initial-scale=1. Sommige mobiele apparaten zoomen een pagina gelijk in of uit. Ook weer in een poging behulpzaam te zijn. Ook dat is hier niet nodig, want de pagina past zich aan het apparaat aan. Er is ook een instructie om zoomen helemaal onmogelijk te maken, maar die wordt niet gebruikt. De bezoeker kan zelf nog gewoon zoomen, wat belangrijk is voor mensen die wat slechter zien.

<video data-smscr="480" aria-labelledby="titel-1" controls preload="metadata" poster="116-images/elliot_b_senior_project_with_after_effects.jpg">

<source src="116-video/elliot_b_senior_project_with_after_effects.webm" type="video/webm"> <source data-smscr="small" src="116-video/elliot_b_senior_project_with_after_effects_klein.webm" type="video/webm"> <source src="116-video/elliot_b_senior_project_with_after_effects.mp4" type="video/mp4"> <source data-smscr="small" src="116-video/elliot_b_senior_project_with_after_effects_klein.mp4" type="video/mp4"> Je browser ondersteunt het afspelen van video's niet. Je kunt hieronder de video nog wel downloaden. </video>

De hierboven staande code is de code, zoals die is te vinden bij de eerste <video> op de pagina met html. Dit is ook de code die je krijgt te zien, als je gewoon in de browser de broncode bekijkt. Als je echter de gegenereerde code – de code die de browser echt gebruikt – bekijkt in browservensters smaller dan 480 px, zie je een iets andere code.

De veranderingen worden aangebracht door het script. Hier wordt alleen bovenstaande code bekeken, de door het script aangepaste veranderingen staan hieronder bij Door het script aangebrachte wijzigingen in het <video>-element.

Bovenstaande code hoort bij de eerste <video>. De andere drie <video>'s hebben afwijkende code, omdat – uiteraard – titels, video's, en dergelijke anders zijn, maar de werking is bij alle vier de <video>'s precies hetzelfde.

Hier gelijk onder staat een korte omschrijving van de onderdelen uit bovenstaande code, iets lager staat de uitgebreide beschrijving van alle onderdelen.

<video> en </video>: begin- en eindtag. In de begintag staan enkele attributen die aangeven, hoe het element zich moet gedragen. Er zijn veel meer attributen, die worden verderop besproken.

<source>: binnen elke <source> staat een video. Zodra de browser een video vindt die kan worden afgespeeld, wordt niet verder gekeken naar volgende <source>'s.

<video data-smscr="480" aria-labelledby="titel-1" controls preload="metadata" poster="116-images/elliot_b_senior_project_with_after_effects.jpg">

<video>: gewoon de openingstag. Helemaal achteraan, na een hele reeks elementen die binnen <video> zitten, wordt het element afgesloten met </video>.

data-smscr="480": dit attribuut is een eigengemaakt, je zult het in geen enkele specificatie tegenkomen. In html5 kun je eigen attributen maken, die precies hetzelfde worden behandeld als bijvoorbeeld width="300" bij een afbeelding. Je kunt ze dus bijvoorbeeld ook in een selector gebruiken. De enige voorwaarde is dat de naam begint met data-.

Het wordt hier gebruikt om in browservensters aan het script door te geven onder welke breedte van het browservenster een kleinere video moet worden gebruikt. In dit geval is die breedte 480 px, waarbij 'px' wordt weggelaten. Hoe het precies werkt, staat hieronder bij Door het script aangebrachte wijzigingen in het <video>-element.

aria-labelledby="titel-1": dit is een zogenaamde WAI-ARIA-code. Deze is van belang voor schermlezers en dergelijke. De video wordt op deze manier gekoppeld aan een element met id="titel-1". Dat is hier de <h2> boven de eerste video, waarin de titel van de video staat. Zonder deze koppeling zou een schermlezer (maar ook een zoekmachine) niet weten, wat dit voor video is. Meer hierover staat bij WAI-ARIA-codes.

controls: geeft aan dat knoppen moeten worden weergegeven, waarmee de videospeler is te bedienen. De maker van de browser heeft voor deze knoppen gezorgd, dus ze verschillen enigszins per browser. Als je controls weglaat, worden de bedieningsknoppen niet getoond. Maar ook dan kan in de meeste browsers nog steeds met rechtsklikken een contextueel menu worden geopend, waarmee de video toch kan worden afgespeeld. In sommige browsers echter kan de video nu helemaal niet worden afgespeeld, omdat die mogelijkheid in het contextueel menu ontbreekt.

Op mobiele browsers kun je niet rechtsklikken, dus daar kan de video zonder bedieningsknoppen gewoon helemaal niet worden afgespeeld.

Het weglaten van controls heeft alleen maar zin, als je de video via JavaScript wilt laten afspelen, of via JavaScript eigen knoppen wilt laten weergeven.

preload="metadata": hiermee regel je het downloaden van de video: zodra de pagina wordt geopend, of pas als de video daadwerkelijk wordt afgespeeld. Dit is niet meer dan een hint voor de browser, de browser kan afwijken van wat hier wordt opgegeven. Ook al geef je bijvoorbeeld op dat de video gelijk bij openen van de pagina moet worden gedownload, dan zullen de meeste mobiele browsers dit toch pas gaan doen, als de gebruiker kiest voor afspelen.

Mogelijke waarden:

none: pas downloaden als wordt afgespeeld.

metadata: alleen metagegevens zoals breedte, hoogte en afspeelduur ophalen.

auto: video gelijk downloaden, al voordat wordt gekozen voor afspelen. Als je niets invult bij preload, is dit de standaardwaarde.

Hier wordt als waarde 'metadata' gebruikt, zodat de speelduur van de video gelijk bij openen van de pagina wordt opgevraagd. Veel browsers tonen deze speelduur in de videospeler, zodat de bezoeker al voor het afspelen weet, hoe lang de video gaat duren.

poster="116-images/elliot_b_senior_project_with_after_effects.jpg": achter poster kun je de url van een afbeelding opgeven, die wordt getoond voordat de video wordt afgespeeld.

Als je poster weglaat, wordt op de desktop het eerste frame uit de video getoond, maar de meeste mobiele browsers tonen dan alleen een witte of zwarte rechthoek met knoppen. Maar ook als het eerste frame wel wordt getoond, is dit vaak niet geschikt. Bij de eerste twee video's van dit voorbeeld bijvoorbeeld is het eerste frame een zwart vlak.

autoplay: wordt niet gebruikt in dit voorbeeld. Zorgt ervoor dat de video automatisch begint af te spelen. Heel fijn als je toevallig in een gehorig huis woont naast een beroepsbokser met 'n kort lontje. Vooral als je vaak 's nachts surft en op de betreffende video luidkeels het Wilhelmus wordt gezongen door het voltallige Nederlandse elftal. Na de revolutie komt hier drie maanden zonnepanelen aanbrengen op een verlaten olieplatform op te staan.

Serieus: dit is een prima manier om bezoekers weg te jagen. Laat mensen zelf kiezen of ze wel of niet je video willen afspelen. Dit geldt nog sterker, als de video ook geluid heeft. In dat geval zou je op z'n minst ook muted moeten opgeven (zie hieronder).

loop: wordt niet gebruikt in dit voorbeeld. Als de video is uitgespeeld, wordt weer van voren af aan begonnen.

height: wordt niet gebruikt in dit voorbeeld. De hoogte van de video in pixel. Zodra ook een hoogte in de css wordt opgegeven, overrulet deze de hier opgegeven hoogte.

In dit voorbeeld wordt de hoogte van de video in browservensters met een minimale breedte van 480 px opgegeven in de css.

width: de breedte van de video in pixel. Zodra ook een breedte in de css wordt opgegeven, overrulet deze de hier opgegeven breedte.

In dit voorbeeld wordt de breedte van de video opgegeven in de css.

muted: wordt niet gebruikt in dit voorbeeld. Zet het geluid uit. De browser is niet verplicht hiernaar te luisteren.

(Normaal genomen zal wel worden geluisterd, als het geluid is uitgezet. Als het geluid aanstaat, zal niet altijd door de browser worden gehoorzaamd. Mocht je partner als onderdeel van een knetterende ruzie een scheldpartij aan je hebben gestuurd, dan wordt daardoor voorkomen dat deze onbedoeld tijdens de directievergadering wordt afgespeeld.)

mediagroup: wordt niet gebruikt in dit voorbeeld. Wordt gebruikt om twee of meer video's gelijktijdig af te laten spelen. Dit maakt het bijvoorbeeld mogelijk om een video te voorzien van een doventolk. De video's worden met dezelfde knoppen bediend. Achter mediagroupM wordt de naam van de groep ingevuld: mediagroup="video-1". Elke video komt in een apart <video>-element te staan.

src: hierin komt de url van de af te spelen video. Dit wordt alleen gebruikt, als er maar één video is opgegeven. Zodra er meerdere video's zijn, waaruit de browser moet kiezen, komt elke video in een aparte <source> te staan binnen <video>. In de code hierboven staat dan ook geen src in de <video>-tag.

(Het script zet, in browservensters smaller dan 480 px, een src binnen <video> met daarin pad naar en naam van de kleine video. Omdat deze nu bovenaan staat, zal de browser deze gebruiken. In vensters smaller dan 480 px kun je deze verandering zien, maar alleen in de gegenereerde code. Hoe deze verandering precies werkt, is te vinden bij Door het script aangebrachte wijzigingen in het <video>-element.)

<source src="116-video/elliot_b_senior_project_with_after_effects.webm" type="video/webm">

<source data-smscr="small" src="116-video/elliot_b_senior_project_with_after_effects_klein.webm" type="video/webm"> <source src="116-video/elliot_b_senior_project_with_after_effects.effects.mp4" type="video/mp4"> <source data-smscr="small" src="116-video/elliot_b_senior_project_with_after_effects_klein.mp4" type="video/mp4">

Binnen het <video>-element kun je meerdere video's opgeven. De browser bekijkt alle video's. Zodra er eentje wordt gevonden die kan worden afgespeeld, wordt die gebruikt. De rest van de <source>'s wordt niet meer bekeken.

Bij dit vinden helpt het opgegeven MIME-type (type) van de video. Als je geen MIME-type opgeeft, moet de browser een deel van elke video downloaden om uit te proberen, of die video kan worden afgespeeld. Dit onnodige downloaden van onafspeelbare video's kan worden voorkomen door het opgeven van een MIME-type.

Omdat de grote video's boven de kleinere video's staan, zal de browser altijd de grotere video afspelen. Ook op een mobieltje. Het script zorgt ervoor, dat in browservensters smaller dan 480 px de kleine video wordt gebruikt, door de volgorde van de <source>'s te wijzigen. Hoe dat precies werkt, is te te vinden bij Door het script aangebrachte wijzigingen in het <video>-element.

<source: gewoon de opening van de tag. De tag wordt aan het eind van de regel afgesloten met een >.

src: hierachter staan pad naar en naam van de video.

type: d it is een zogenaamd MIME-type. Het deel voor de schuine streep geeft een soort grove indeling, hier 'video'. Het tweede deel geeft het formaat weer. Met de twee formaten 'webm' en 'mp4' kun je alle browsers bedienen. Helaas konden de browsermakers het niet eens worden over één formaat, anders had je – wat het formaat betreft – met één <source> kunnen volstaan.

In principe kun je zoveel <source>'s gebruiken, als je wilt. Als je dus om een of andere reden speciaal voor Internet Explorer een exotisch formaat wilt gebruiken, zet je dat gewoon vooraan. Browsers die dat exotische formaat niet kennen, negeren het gewoon en gebruiken een latere <source>.

data-smscr="small": dit attribuut is een eigengemaakt, je zult het in geen enkele specificatie tegenkomen. In html5 kun je eigen attributen maken, die precies hetzelfde worden behandeld als bijvoorbeeld width="300" bij een afbeelding. Je kunt ze dus bijvoorbeeld ook in een selector gebruiken. De enige voorwaarde is dat de naam begint met data-.

Dit attribuut is in twee <source>'s aanwezig. Dit zijn de <source>'s, waarin de video's voor kleinere browservensters zitten. Als er een <source> met dit attribuut aanwezig is, zal de video uit deze <source> worden gebruikt in browservensters smaller dan – in dit geval – 480 px. Hoe dit precies werkt, staat hieronder bij Door het script aangebrachte wijzigingen in het <video>-element.

Je browser ondersteunt het afspelen van video's niet. Je kunt hieronder de video nog wel downloaden.: Ten slotte staat er nog een tekst in het <video>-element. Deze tekst wordt getoond in browsers die het <video>-element niet kennen. In dit geval verwijst de tekst naar de download-links die onder elke video zijn aangebracht.

Door het script aangebrachte wijzigingen in het <video>-element

De hieronder beschreven veranderingen zie je niet, als je gewoon de bron van de pagina bekijkt. Dan zie je gewoon de html zoals die in de pagina staat. Om de door het script gewijzigde html te zien, moet je de gegenereerde code bekijken.

Het script kijkt als eerste of er in een van de <video>-elementen een attribuut met de naam 'data-smscr' en als waarde een getal voorkomt. Zodra dat wordt gevonden, wordt gekeken of de waarde daarvan een positief getal is. In het voorbeeld staat in elke <video> data-smscr="480", waarmee hieraan dus is voldaan.

Als bij een of meer <video>'s het data-smscr-attribuut niet aanwezig is, of als de waarde ervan geen positief getal is, verandert er niets bij deze <video> en gaat het script verder met de volgende <video>.

In het voorbeeld staat in elk <video>-element data-smscr="480". Als je een ander getal invult, blijft de werking hetzelfde, alleen verandert de breedte van het browservenster, waarbij die werking optreedt.

Als de breedte van het browservenster 480 px of meer is, gebeurt er verder niets en wordt met de volgende <video> verder gegaan.

Als het browservenster smaller is dan 480 px, wordt voor deze <video> de rest van het script uitgevoerd: er wordt bij elke <source> gekeken, of daar een data-smscr met als waarde 'small' in staat. In het voorbeeld staat in elke tweede <source> data-smscrc="small".

Bij deze <source>'s wordt vervolgens gekeken, of de video die binnen die <source> in de src staat, afgespeeld kan worden door de videospeler. Als dat zo is, wordt niet verder gezocht. Als de video niet kan worden afgespeeld, wordt verdergegaan met de volgende <source>.

Als de video afgespeeld kan worden, wordt aan het <video>-element een src toegevoegd met daarin de naam van de gevonden video. Als je in een browservenster smaller dan 480 px in Firefox de gegenereerde code bekijkt, staat daarin:

<video data-smscr="480" aria-labelledby="titel-1" controls="" preload="metadata" poster="116-images/elliot_b_senior_project_with_after_effects.jpg" src="http://css-voorbeelden.nl/afbeelding/ video/116-video/elliot_b_senior_project_with_after_effects_klein.webm">

Aan het <video>-element is aan het eind achter src door het script pad naar en naam van de kleine webm-video toegevoegd. Omdat een src aanwezig is, worden de ook nog steeds aanwezige <source>'s verder niet bekeken door de browser, maar wordt de in het src-attribuut staande video afgespeeld.

<p class="groot">Video downloaden? Kies <a lang="en" href="116-video/elliot_b_senior_project_with_after-effects.mp4" download="Elliot B senior project with after effects.mp4" title="Download video in mp4-formaat">mp4</a> <span>(95,5 <abbr title="kilobyte">kB</abbr>)</span> of <a lang="en" href="116-video/elliot_b_senior_project_with_after_effects.webm" download="Elliot B senior project with after effects.webm" title="Download video in webm-formaat">webm</a> <span>(39,8 <abbr>kB</abbr>)</span>.</p>

Onder elke video staan links om de video te kunnen downloaden. Deze links zijn aangebracht voor het geval de browser de video niet af kan spelen. Je kunt dan in ieder geval de video downloaden en op 'n andere manier afspelen.

Hierboven staat de code voor het downloaden van de eerste video in groot formaat.

Er zijn twee links: eentje voor de video in mp4-formaat, en eentje voor de video in webm-formaat. De bezoeker kan hierdoor kiezen, welk formaat wordt gedownload. Als je maar één formaat opgeeft, is er een kans dat de gedownloade video niet kan worden afgespeeld. Door een class aan de <p> waar de links in staan te geven, kun je met css deze link verbergen. Dat gebeurt in dit voorbeeld in browservensters smaller dan 480 px. Daarin wordt deze code verborgen, maar wordt het zusje hiervan getoond: vrijwel hetzelfde, maar met video's in kleiner formaat.

In de <p> staan twee gewone links met in beide een title, zodat ook voor schermlezers en dergelijke duidelijk is, welke link bij welke video hoort. Er staat één relatief nieuw attribuut in de links:

download="Elliot B senior project with after effects.mp4"

Normaal genomen zou als naam voor de download 'elliot_b_senior_project_with_after_effects.mp4' worden gebruikt. Maar in browsers die download herkennen, wordt de naam nu verandert in het veel mensvriendelijker 'Elliot B senior project with after effects.mp4'.

De extensie 'mp4' hoeft niet te worden gebruikt achter download, maar het is beter om dat wel te doen. Niet alle browsers blijken deze extensie zelf toe te voegen, waardoor deze niet altijd achter de naam van de video komt te staan. Een van de grootste ondingen wat betreft veiligheid op Windows is het standaard verbergen van extensies, waardoor 'n gebruiker niet snel kan zien, wat voor soort bestand iets is. Om te voorkomen dat dit veiligheidsrisico naar andere systemen wordt geëxporteerd, wordt een extensie achter download gebruikt.

De grootte van de video staat in een <span>. Door de grootte apart in een <span> te zetten, ontstaat een aanknopingspunt voor css, waardoor je de grootte bijvoorbeeld in een kleinere letter kunt weergeven.

Omdat kB een afkorting is, staat deze in een <abbr>. De afkorting kB komt voor de eerste keer voor onder de eerste video, daarom staat bij de eerste <abbr> de afkorting voluit geschreven:

<abbr title="kilobyte">kB</abbr>

Afhankelijk van de (instellingen van de) browser begint deze bij activeren van deze link gelijk met downloaden, of wordt eerst om bevestiging gevraagd. Mogelijk wordt niet iedereen gelijk dol van vreugde, als een browser zonder eerst om bevestiging te vragen een video van 300 gigabyte begint te downloaden. Daarom is achter de link de grootte van de download aangegeven.

(Afhankelijk van de browser werkt dit download-attribuut mogelijk alleen op de server. In Firefox bijvoorbeeld speelde, tot voor kort, de video gewoon af, als je het lokaal uitprobeerde. Maar in datzelfde Firefox werd de video wel gedownload, als je het op 'n server uitprobeerde.)

<script src="../116-js/afbeelding-116.js"></script>

Onderaan de html staan een link naar het script. In html5 is de toevoeging type="text/javascript" niet meer nodig, omdat dit de standaardinstelling is.

De link naar het script staat helemaal onderaan de pagina, om te voorkomen dat de browser staat te wachten tijdens het verwerken van het script. Nu kan eerst de rest van de pagina worden geladen, voordat het script wordt verwerkt.

Een andere reden om de link onderaan de pagina te zetten: de <video>-elementen moeten al zijn aangemaakt door de browser, omdat het script niet kan werken met nog niet bestaande elementen.

CSS

De code is geschreven in een afwijkende lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code) is in de hele uitleg blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)

Omdat deze site nou eenmaal (voornamelijk) op css is gericht, wordt hieronder álle css besproken.

Technisch gezien is er geen enkel bezwaar om de css in de stylesheet allemaal achter elkaar op één regel te zetten:

div#header-buiten {position: absolute; right: 16px; width: 100%; height: 120px; background: yellow;} div p {margin-left 16px; height: 120px; text-align: center;}

Maar als je dat doet, garandeer ik je hele grote problemen, omdat het volstrekt onoverzichtelijk is. Beter is het om de css netjes in te laten springen:

              div#header-buiten {
            position: absolute;
            right: 16px;
            width: 100%;
            height: 120px;
            background: yellow;
        }

        div p {
            margin-left: 16px;
            height: 120px;
            text-align: center;
        }

Hiernaast is het heel belangrijk voldoende commentaar (uitleg) in de stylesheet te schrijven. Op dit moment weet je waarschijnlijk (hopelijk...), waarom je iets doet. Maar over vijf jaar kan dat volstrekt onduidelijk zijn. Op deze site vind je nauwelijks commentaar in de stylesheets, maar dat heeft een simpele reden: deze uitleg is in feite één groot commentaar.

Op internet zelf is het goed, als de stylesheet juist zo klein mogelijk is. Dus voor het uploaden kun je normaal genomen het beste het commentaar weer verwijderen. Veel mensen halen zelfs alles wat overbodig is weg, voordat ze de stylesheet uploaden. Inspringingen bijvoorbeeld zijn voor mensen handig, een computer heeft ze niet nodig.

Je hebt dan eigenlijk twee stylesheets. De uitgebreide versie waarin je dingen uitprobeert, verandert, enz., met commentaar, inspringingen, en dergelijke. Dat is de mensvriendelijke versie. Daarnaast is er dan een stylesheet die je op de echte site gebruikt: een gecomprimeerde versie.

Dat comprimeren kun je met de hand doen, maar er bestaan ook hulpmiddelen voor. Als je op internet zoekt naar 'css' en 'compress' of 'comprimeren', vind je tal van sites, waar je dat automatisch kunt laten doen.

(Stylesheetss op deze site zijn niet gecomprimeerd. Omdat het vaak juist om de css gaat, kunnen mensen dan zonder al te veel moeite de css bekijken.)

css voor alle vensters

/* afbeelding-116-dl.css */

Om vergissingen te voorkomen is het een goede gewoonte bovenaan het stijlbestand even de naam neer te zetten. Voor je het weet, zit je anders in het verkeerde bestand te werken.

body

Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.

background: #ff9;

Achtergrondkleurtje.

color: black;

Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.

Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.

font-family: Arial, Helvetica, sans-serif;

Als Arial is geïnstalleerd op de machine van de bezoeker, wordt deze gebruikt, anders Helvetica. Als die ook niet wordt gevonden, wordt in ieder geval een schreefloze letter (zonder dwarsstreepjes) gebruikt.

margin: 0; padding: 0;

Slim om te doen vanwege verschillen tussen browsers.

section

Alle <section>'s. Elke video met bijbehorende links, titel, en dergelijke staat in een eigen <section>.

margin-top: 20px;

Kleine marge aan de bovenkant, zodat de video's en dergelijke niet tegen elkaar aan komen te staan.

h2, .origineel, .groot, .klein

Alle <h2>'s, de elementen met class="origineel", class="groot" en class="klein". Dit zijn de elementen met de titel en de (download-)links.

background: white;

Witte achtergrond.

color: black;

Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.

Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.

Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.

max-width: 294px; Afbeelding 2: zelfs in een vensters met een breedte van 200 px ziet alles er goed uit

Maximumbreedte.

Alle elementen, waarvoor deze selector geldt, zijn blok-elementen. Een blok-element wordt normaal genomen even breed als z'n ouder. Die ouder is hier <section>, ook een blok-element. <section> wordt daarom normaal genomen ook even breed als z'n ouder <main>, ook weer een blok-element. Het wordt eentonig: het blok-element <main> wordt normaal genomen ook weer even breed als ouder <body>, ook een blok-element. <body> wordt normaal genomen even breed als ouder <html>. <html> is het buitenste element en wordt daarom normaal genomen even breed als het venster van de browser.

Als je deze hele keten terug volgt, worden daardoor de elementen, waar deze selector voor geldt, ook even breed als het venster van de browser. Omdat hier geen gewone breedte, maar alleen een maximumbreedte is opgegeven, worden deze elementen nooit breder dan het venster van de browser, ook niet als dit smaller dan 294 px is.

Hier iets onder krijgen deze elementen nog een padding van 3 px en een border van 1 px. Daardoor wordt de eigenlijke maximumbreedte 1 + 3 + 294 + 3 + 1 = 302 px.

Hieronder bij video krijgen de video's een breedte van 300 px en een maximumbreedte van 100%. Daar komt nog een border van 1 px bij. Ook de video's worden hierdoor 302 px breed, maar nooit breder dan het venster van de browser.

De titels en links boven en onder de video's sluiten hierdoor altijd netjes op de video's aan. Op de afbeelding is een heel smal browservenster met een breedte van 200 px te zien. Ook daarin sluiten video's, titels, links, en dergelijke netjes op elkaar aan, omdat ze in zo'n smal venster allemaal even breed worden als het venster van de browser.

text-align: center;

Tekst horizontaal centreren.

margin: 0 auto;

Omdat voor onder en links niets is opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 0 auto 0 auto in de volgorde boven – rechts – onder – links. Boven en onder geen marge, links en rechts auto wat hier hetzelfde betekent als evenveel. Titel en links staan hierdoor altijd horizontaal gecentreerd binnen hun ouder <section>, ongeacht hoe breed <section> is.

Omdat, zoals iets hierboven bij max-width beschreven, <section> even breed is als het venster van de browser, staan titel en links hierdoor ook altijd horizontaal gecentreerd binnen het venster. (Omdat title en links maximaal 302 px breed zijn, zie je hier pas iets van in browservensters die meer dan 302 px breed zijn.)

Deze manier van horizontaal centreren van een blok-element werkt alleen, als het te centreren element een breedte heeft.

border: black solid;

Zwart randje. De breedte wordt gelijk hieronder opgegeven.

border-width: 0 1px 1px;

Kleur en stijl van de border zijn gelijk hierboven al opgegeven.

Omdat voor links geen waarde is opgegeven, krijgt links dezelfde waarde als rechts. Hier staat dus eigenlijk 0 1px 1px 1px in de volgorde boven – rechts – onder – links. Aan alle kanten een randje, behalve aan de bovenkant.

Aan de onderkant, onder de download-links, blijft dit randje zo staan. Boven de video staat een titel in een <h2>. Hieronder bij h2 wordt het randje bij die <h2> met border-width aan de onderkant weggehaald en aan de bovenkant toegevoegd, zodat de hele video met bijbehorende titel en links door een rand is omgeven.

border-radius: 0 0 5px 5px;

Rechts- en linksonder ronde hoek.

Deze ronde hoeken zijn bedoeld voor .groot en .klein, de <p>'s met de download-links onder de video. De ronde hoeken bij .origineel, de link naar de originele video boven de video, worden iets hieronder bij .origineel weggehaald. Bij h2 gelijk hieronder worden de ronde hoeken verplaatst naar links‑ en rechtsboven. Het eindresultaat is een kader met ronde hoeken rondom de hele video, inclusief bijbehorende titels en links.

padding: 3px;

Kleine ruimte tussen tekst in en buitenkant van de titels en links.

h2

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.

h2, .origineel, .groot, .klein {background: white; color: black; max-width: 294px; text-align: center; margin: 0 auto; border: black solid; border-width: 0 1px 1px; border-radius: 0 0 5px 5px; padding: 3px;}

Alle <h2>'s. Dit zijn de titels boven de video's.

font-size: 1em;

Een <h2> heeft een vrij grote letter. Hier wordt dat veranderd in een normale lettergrootte.

Hier gelijk onder wordt de vette letter van de <h2> ook nog veranderd in een normale dikte. Je zou hierdoor mogelijk kunnen denken dat je dan net zo goed die <h2> door een gewone <p> kunt vervangen, maar dat is niet zo. Uiterlijk zou een <p> er inderdaad net zo uitzien als deze <h2>, maar schermlezers kunnen makkelijk van <h> naar <h> springen, en voor zoekmachines is een <h2> een indicatie dat hier enigszins belangrijke tekst in staat.

Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.

font-weight: normal;

Van zichzelf heeft een <h2> vette tekst. Dat wordt hier veranderd in normale tekst.

border-width: 1px 1px 0;

Bij h2, .origineel, .groot, .klein hebben de <h2>'s al een border gekregen, hier wordt aangegeven aan welke kanten die border moet staan.

Omdat voor links geen breedte is opgegeven, krijgt links dezelfde breedte als rechts. Hier staat dus eigenlijk 1px 1px 0 1px in de volgorde boven – rechts – onder – links. Boven, rechts en links een randje.

border-radius: 5px 5px 0 0;

Links‑ en rechtsboven ronde hoek.

padding-bottom: 0;

Bij h2, .origineel, .groot, .klein is aan alle kanten een padding gegeven. Hier wordt de padding aan de onderkant weggehaald, omdat er anders een te grote opening tussen de titel en de eronder staande link naar de originele video zit.

.origineel

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.

h2, .origineel, .groot, .klein {background: white; color: black; max-width: 294px; text-align: center; margin: 0 auto; border: black solid; border-width: 0 1px 1px; border-radius: 0 0 5px 5px; padding: 3px;}

Alle elementen met class="origineel". De <p>'s met de links naar de originele video's.

font-size: 0.85em;

Iets kleinere letter.

Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.

border-width: 0 1px;

Omdat voor onder en links geen waarde is opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 0 1px 0 1px in de volgorde boven – rechts – onder – links.

Bij h2, .origineel, .groot, .klein is een border aan de zijkanten en onderkant van deze <p>'s gegeven. Hier wordt die border beperkt tot de linker- en rechterkant. .origineel staat boven <video>. <video> krijgt bij video een border aan de bovenkant. Als .origineel ook een border aan de onderkant zou krijgen, zou tussen .origineel en de eronder staande <video> een dubbele border staan.

border-radius: 0;

De bij h2, .origineel, .groot, .klein gegeven ronde hoeken weghalen.

padding-top: 0;

Bij h2, .origineel, .groot, .klein is aan alle kanten een padding opgegeven. Hier wordt de padding aan de bovenkant weggehaald, omdat anders een te grote ruimte ontstaat tussen .origineel en de erboven staande <h2>.

video

Alle <video>'s. De elementen waar de eigenlijke video in zit.

background: white;

Witte achtergrond. Als de browser niet met <video> uit de voeten kan, wordt een tekst getoond. Om zeker te zijn dat die leesbaar is, wordt de achtergrond van <video> wit gemaakt.

color: black;

Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.

Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.

Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.

display: block; Afbeelding 3: video als inline-element

Je zou het misschien niet zeggen, maar <video> is een inline-element, net zoals bijvoorbeeld een <img>. Het heeft weliswaar wat bijzondere eigenschappen, maar het blijft een inline-element. Dat heeft hier een aantal ongewenste bijwerkingen.

De hieronder opgegeven breedte en maximumbreedte werken niet bij een inline-element.

Een inline-element heeft een regelhoogte. <video> staat op de basislijn, waar ook de tekst zou staan, als die er was. Onder die basislijn is nog wat extra ruimte voor letters als de 'j' en de 'y', die onder de basislijn uitsteken. Op de afbeelding is te zien, dat die ruimte ook onder <video> aanwezig is, ook al is die niet nodig. (Om het wat duidelijker te laten zien, is de achtergrond van de pagina even blauw gekleurd.) Dit levert een kier op tussen de video en de eronder staande download-links.

Ten slotte kan een inline-element niet worden gecentreerd op de manier, zoals iets hieronder met margin: 0 auto; gebeurt.

Al deze droeve ellende kan met één toverspreuk worden verdreven: display: block;. <video> is nu een blok-element, waarmee alle bovenstaande problemen zijn opgelost.

width: 300px;

De kleine video's zijn 300 px breed, dus <video> ook zo breed maken.

Een hoogte wordt niet opgegeven, de reden daarvan staat gelijk hieronder bij max-width.

max-width: 100%;

Hierboven is een breedte van 300 px aan <video> gegeven. In browservensters smaller dan 300 px zou hierdoor niet de hele video te zien zijn. Daarom wordt hier een maximumbreedte opgegeven.

Een breedte in procenten is altijd ten opzichte van de ouder van het element. Dat is hier het blok-element <section>. Een blok-element wordt normaal genomen even breed als z'n ouder, dat is hier het blok-element <main>. Ook <main> wordt normal genomen even breed als z'n ouder, blok-element <body>, dat normaal genomen ook weer even breed wordt als de ouder daarvan: <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser.

Uiteindelijk wordt ook <video> dus nooit breder dan het venster van de browser.

De video zelf wordt nooit breder dan de <video>, waar hij in zit. Als dat nodig is, wordt de video verkleind.

Omdat <video> smaller kan worden dan 300 px, is geen hoogte opgegeven. De hoogte van de kleine video's is 200 px. Als wel een hoogte aan <video> zou worden gegeven, blijft in sommige browsers de hoogte van de video 200 px, terwijl de breedte in hele smalle browservensters wordt verkleind. Dat levert een soort lachspiegeleffect op: alles vervormt. In andere browsers vervormt de video niet, omdat de hoogte ook wordt aangepast, maar krijg je lelijke grijze balken onder en boven de video.

Door geen hoogte op te geven, schaalt de hoogte van de video automatisch in dezelfde verhouding als de breedte en vervormt de video niet.

margin: 0 auto;

Omdat voor onder en links niets is opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 0 auto 0 auto in de volgorde boven – rechts – onder – links. Boven en onder geen marge, links en rechts auto wat hier hetzelfde betekent als evenveel. <video> staat hierdoor altijd horizontaal gecentreerd binnen z'n ouder <section>, ongeacht hoe breed <section> is.

Omdat, zoals hierboven bij max-width beschreven, <section> even breed is als het venster van de browser, staan titel en links hierdoor ook altijd horizontaal gecentreerd binnen het venster. (Omdat title en links maximaal 302 px breed zijn, zie je hier pas iets van in browservensters die meer dan 302 px breed zijn.)

Deze manier van horizontaal centreren van een blok-element werkt alleen, als het te centreren element een breedte heeft.

border: black solid 1px;

Zwart randje rondom <video>, en daarmee ook rondom de in <video> zittende video zelf.

.groot span, .klein span

De <span>'s in de elementen met class="groot" en de <span>'s in de elementen met class="klein". In deze <span>'s zit de grootte van de video's.

font-size: 0.7em;

Iets kleinere letter.

Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.

.groot

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.

h2, .origineel, .groot, .klein {background: white; color: black; max-width: 294px; text-align: center; margin: 0 auto; border: black solid; border-width: 0 1px 1px; border-radius: 0 0 5px 5px; padding: 3px;}

De elementen met class="groot". De <p>'s waarin de download-links voor de grotere video's zitten.

display: none;

Verbergen. In browservensters minimaal 480 px breed worden ze verderop bij .groot weer zichtbaar gemaakt.

css voor vensters minimaal 480 px breed

@media screen and (min-width: 480px)

De css die hier tot nu toe staat, geldt voor alle browservensters.

De css die binnen deze media query staat, geldt alleen voor vensters die minimaal 480 px breed zijn. In deze bredere vensters wordt de grotere video gebruikt. Daarom moet ook de breedte van links, titel, en dergelijke worden aangepast. De download-links voor de kleinere video's worden zichtbaar gemaakt en die voor de kleinere video's juist verborgen.

@media: geeft aan dat het om css gaat die alleen van toepassing is, als aan bepaalde voorwaarden wordt voldaan. Al langer bestond de mogelijkheid om met behulp van zo'n @media-regel css voor bijvoorbeeld printers op te geven. css3 heeft dat uitgebreid tot bepaalde fysieke eigenschappen, zoals de breedte en hoogte van het venster van de browser.

screen: deze regel geldt alleen voor schermweergave.

and: er komt nog een voorwaarde, waaraan moet worden voldaan.

(min-width: 480px): het venster moet minimaal 480 px breed zijn. Is het venster smaller, dan wordt de css die binnen deze media-regel staat genegeerd.

Gelijk na deze regel komt een { te staan, en aan het einde van de css die binnen deze query valt een bijbehorende afsluitende }. Die zijn in de regel hierboven weggevallen, maar het geheel ziet er zo uit:

@media screen and (min-width: 480px) { body {color: silver;} (...) rest van de css voor deze @media-regel (...) footer {color: gold;} }

Voor de eerste css binnen deze media-regel staat dus een extra {, en aan het eind staat een extra }.

Als je nou 'n mobieltje hebt met een resolutie van – ik roep maar wat – 1024 x 768 px, dan geldt deze media query soms toch niet voor dat mobieltje. Terwijl dat toch echt meer dan 480 px breed is. Een vuig complot van gewetenloze multinationals? Voordat je je gaat beklagen bij Radar, zou ik eerst even verder lezen.

Steeds meer mobiele apparaten, maar ook steeds meer gewone beeldschermen, hebben een hogere resolutiedichtheid. Dat wil zeggen dat ze kleinere pixels hebben, die dichter bij elkaar staan. Daardoor zijn foto's, tekst, en dergelijke veel scherper weer te geven. Hoe kleiner de puntjes (de pixels) zijn, waaruit een afbeelding is opgebouwd, hoe duidelijker het wordt.

Er ontstaat alleen één probleem: als je de pixels twee keer zo klein maakt, wordt ook wat je ziet twee keer zo klein. En inmiddels zijn er al apparaten met pixels die meer dan vier keer zo klein zijn. Een lijntje van 1 px breed zou op die apparaten minder dan 'n kwart van de oorspronkelijke breedte krijgen en vrijwel onzichtbaar zijn. Een normale foto zou in een thumbnail veranderen. Kolommen zouden heel smal worden. Tekst zou onleesbaar klein worden. Allemaal fantastisch scherp, maar je hebt 'n vergrootglas nodig om 't te kunnen zien.

Om dit te voorkomen wordt een verschil gemaakt tussen css-pixels en schermpixels (in het Engels 'device pixels'). De css-pixels zijn gebaseerd op de – tot voor kort – normale beeldschermen van de desktop. 1 css-pixel is op zo'n beeldscherm 1 pixel. Het aantal schermpixels is het werkelijk op het apparaat aanwezige aantal pixels (dat is het aantal pixels, waarvoor je hebt betaald).

Dat eerder genoemde mobieltje van 1024 x 768 px heeft wel degelijk het aantal pixels, waarvoor je hebt betaald. Maar die zitten dichter bij elkaar. Op een gewoon beeldscherm zitten 96 pixels per inch, wat wordt uitgedrukt met de eenheid dpi ('dots per inch'). Als dat mobieltje een resolutie van 192 dpi heeft, 192 pixels per inch, zijn de pixels ervan twee keer zo klein als op een origineel beeldscherm. Er zijn per inch twee keer zoveel schermpixels aanwezig.

Om nu te voorkomen dat alles op dat mobieltje twee keer zo klein wordt, geeft het mobieltje niet het echte aantal schermpixels (1024 x 768), maar een lager aantal css-pixels door bij een media query. De 192 dpi van het mobieltje is twee keer zo veel als de 96 dpi van een normaal beeldscherm. Het aantal css-pixels is dan het aantal schermpixels gedeeld door 2. 1024 x 768 gedeeld door 2 is 512 x 384 px. Het aantal css-pixels is 512 x 384 px en zit daarmee dus in landschapsstand net boven de grens van deze media query, maar in portretstand ruim eronder.

Maar ook in landschapsstand zal het erom spannen, omdat de browser zelfs soms ook nog wat ruimte inneemt, en je daardoor net onder de 480 px uit zou kunnen komen. En sommige browsers geven niet helemaal het correcte aantal css-pixels door.

Je bent dus niet opgelicht, of in ieder geval niet wat betreft het aantal pixel.

Door deze truc is een lijn van 1 px breed op een normaal beeldscherm ook op het mobieltje nog steeds 1 px breed, alleen wordt die ene (css‑)pixel opgebouwd uit twee schermpixels (feitelijk vier, want het verhaal geldt voor breedte én hoogte). De dikte van het lijntje is hetzelfde, maar het is veel fijner opgebouwd. Bij lijntjes is dat verschil bijvoorbeeld in bochten goed te zien.

Hetzelfde verhaal geldt voor hogere resoluties, Een tablet met een breedte van 4096 schermpixels en een dpi van 384 (vier keer de originele dichtheid) geeft 4096 gedeeld door 4 = 1024 css-pixel door. Het lijntje van 1 px breedte op de originele monitor is nog steeds 1 css pixel breed op de tablet, maar die ene css-pixel is nu opgebouwd uit zestien schermpixel.

(Overigens kun je met behulp van media query's ook testen op de resolutie met gebruik van het sleutelwoord 'resolution'. Apple gebruikt het niet-standaard 'device-pixel-ratio', maar het idee is hetzelfde. Dit kan bijvoorbeeld handig zijn om te bepalen, hoe groot een foto moet zijn.)

Kort samengevat: omdat niet het aantal schermpixels (waarvoor je hebt betaald), maar het aantal css-pixels (de door de ontwerper bedoelde afmeting) wordt doorgegeven, wordt voorkomen dat een hogeresolutiescherm onleesbaar klein wordt.

h2, .origineel, .groot, .klein

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

h2, .origineel, .groot, .klein {background: white; color: black; max-width: 294px; text-align: center; margin: 0 auto; border: black solid; border-width: 0 1px 1px; border-radius: 0 0 5px 5px; padding: 3px;}

h2 {font-size: 1em; font-weight: normal; border-width: 1px 1px 0; border-radius: 5px 5px 0 0; padding-bottom: 0;}

.origineel {font-size: 0.85em; border-width: 0 1px; border-radius: 0; padding-top: 0;}

.groot {display: none;}

max-width: 474px;

Eerder hebben deze elementen een padding van 3 px gekregen. De breedte van deze elementen is dus 3 + 474 + 3 px = 480 px, precies even breed als <video> in deze bredere vensters.

video

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

video {background: white; color: black; display: block; width: 300px; max-width: 100%; margin: 0 auto; border: black solid 1px;}

Alle <video>'s. De elementen waar de eigenlijke video in staat.

width: 480px;

De grote video's zijn 480 px breed.

height: 320px;

De grote video's zijn 320 px hoog.

.groot

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

h2, .origineel, .groot, .klein {background: white; color: black; max-width: 294px; text-align: center; margin: 0 auto; border: black solid; border-width: 0 1px 1px; border-radius: 0 0 5px 5px; padding: 3px;}

.groot {display: none;}

h2, .origineel, .groot, .klein {max-width: 474px;}

De elementen met class="groot". De <p>'s waarin de download-links voor de grotere video's zitten.

display: block;

Eerder zijn deze <p>'s verborgen. Nu worden de download-links voor de grotere video's weer zichtbaar gemaakt.

.klein

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

h2, .origineel, .groot, .klein {background: white; color: black; max-width: 294px; text-align: center; margin: 0 auto; border: black solid; border-width: 0 1px 1px; border-radius: 0 0 5px 5px; padding: 3px;}

h2, .origineel, .groot, .klein {max-width: 474px;}

De elementen met class="klein". De <p>'s waarin de download-links voor de kleinere video's zitten.

display: none;

Omdat in deze bredere browservensters de grotere video's worden gebruikt, worden de download-links voor de kleinere video's verborgen.

css voor vensters minimaal 1000 px breed

@media screen and (min-width: 1000px)

De css die hier tot nu toe staat, geldt ook voor browservensters breder dan 1000 px. Dat geldt ook voor de css voor vensters met een minimale breedte van 480 px. Elk venster dat minimaal 480 px breed is, is immers ook 1000 px breed.

In deze bredere vensters kunnen twee video's naast elkaar worden geplaatst.

De css die hieronder staat, geldt alleen voor browservensters minimaal 1000 px breed. Voor een deel is dit nieuwe css, voor een deel wordt hierboven staande css aangepast.

De opbouw van de regel staat beschreven bij css voor vensters minimaal 480 px breed, het enige verschil is dat het hier om een minimumbreedte van 1000 px gaat: (min-width: 1000px).

body

Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

body {background: #ff9; color: black; font-family: Arial, Helvetica, sans-serif; margin: 0; padding: 0;}

Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.

max-width: 1500px;

Hieronder krijgen de <section>'s een breedte van 50%. Door de <body> een maximumbreedte van 1500 px te geven, komen in brede browservensters de video's niet onwijs ver uit elkaar te staan. De video's staan binnen de <section>'s, die maximaal 750 px breed kunnen worden.

margin: 0 auto;

Omdat voor onder en links niets is opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 0 auto 0 auto in de volgorde boven – rechts – onder – links. Boven en onder geen marge, links en rechts auto wat hier hetzelfde betekent als evenveel.

<body> staat hierdoor altijd horizontaal gecentreerd binnen z'n ouder <html>, ongeacht hoe breed <html> is. Omdat <html> het buitenste element is, is dit normaal genomen even breed is als het venster van de browser. Hierdoor staat <body> ook altijd horizontaal gecentreerd in het venster, ongeacht hoe breed dit venster is.

Deze manier van horizontaal centreren van een blok-element werkt alleen, als het te centreren blok-element een breedte heeft. Omdat hierboven een maximumbreedte van 1500 px is opgegeven, zie je van dit centreren pas iets in browserventers breder dan 1500 px.

section

Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)

section {margin-top: 20px;}

Alle <section>'s. Elke video met bijbehorende links, titel, en dergelijke staat in een eigen <section>.

width: 50%;

Een breedte in procenten is altijd ten opzichte van de ouder van het element. Dat is hier het blok-element <main>. Een blok-element wordt normaal genomen even breed als z'n ouder, hier het blok-element <body>. <body> heeft hier gelijk boven een maximumbreedte van 1500 px gekregen. <section> kan dus niet breder worden dan 50% van 1500 px, oftewel 750 px. Omdat <video> bij video horizontaal gecentreerd is binnen <section>, staan de video's netjes verdeeld over de pagina.

float: left;

Een <section> is een blok-element en komt daardoor op een nieuwe regel te staan. Door ze naar links te floaten, worden ze niet meer op een nieuwe regel, maar naast elkaar gezet. Als de regel vol is, komt de volgende weer op een nieuwe regel.

Omdat <section> hier gelijk boven een breedte van 50% heeft gekregen, passen er altijd precies twee naast elkaar. Op elke regel staan dus twee <section>'s (met in elk 'n video).

margin-top: 30px;

De eerder opgegeven marge aan de bovenkant wordt in deze bredere browservensters iets vergroot.

JavaScript

De code is geschreven in een afwijkende lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code) is in de hele uitleg blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)

Bij de uitleg van deze code zijn allerlei haakjes en dergelijke grotendeels weggelaten, want dat voert hier te ver. Als je je in dat soort dingen wilt verdiepen, kun je beter naar sites gaan die meer voor JavaScript zijn bedoeld.

Als je onderstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.

Als je bovenstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.

Hieronder wordt de werking van dit script uitgelegd, maar dit is zeker geen cursus JavaScript. Daar is deze site niet voor bedoeld. Als je alleen wilt weten, hoe je dit script kunt gebruiken en niet hoe het werkt, kun je dat vinden bij Korte handleiding hoe het script te gebruiken.

Als je deze uitleg gaat lezen, wordt dat heel lastig als je het script niet ernaast legt. Het is dan haast onmogelijk om te zien, waar een bepaald stuk code begint en eindigt. Het script staat hier gelijk boven, maar het is beter het als apart bestand te openen, zodat je niet steeds tussen uitleg en script heen en weer hoeft te vliegen. Het script is te vinden in de map 116-js.

Dit script wijzigt, in browservensters smaller dan 480 px, de html. Om dat te kunnen zien moet je niet de gewone broncode, maar de Gegenereerde code bekijken.

Normaal genomen is het heel belangrijk commentaar op te nemen in een script, zodat je over tien jaar ook nog weet, wat je hebt gedaan. Als anderen je code lezen, is commentaar waarom je iets hebt gedaan, of wat er gebeurt, ook absoluut noodzakelijk.

Commentaar in JavaScript geef je aan door aan het begin van de regel twee schuine strepen // te zetten, zoals hierboven bij // afbeelding.js is gebeurd. Commentaar dat meer regels beslaat, geef je zo aan: /* meerdere regels commentaar */. Commentaar wordt door de browser genegeerd.

Bij het script hierboven staat geen commentaar om de simpele reden dat hieronder een heel uitgebreid commentaar volgt. In de download zit wel een script met commentaar: 'afbeelding-116-met-commentaar.js'.

Om het script voor mensen leesbaar te houden, wordt ook gebruikt gemaakt van nieuwe regels, inspringen, en dergelijke. Voor de computer is dat niet nodig. Voordat een script naar de server wordt geüpload, wordt het vaak zo klein mogelijk gemaakt. Als je op internet zoekt naar 'minify javascript', vind je tal van sites, waar dat automatisch kan worden gedaan.

Je hebt dan in feite twee scripts: eentje met de voor mensen makkelijker vorm, waarin je wijzigingen kunt aanbrengen, en eentje in een voor mensen onleesbare vorm, die daadwerkelijk wordt gebruikt.

Op deze site zijn veel scripts niet geminificeerd, omdat ik ze makkelijk leesbaar wil houden voor mensen die de code willen bekijken.

Het script regel voor regel.

// afbeelding-116.js

Om vergissingen te voorkomen is het een goede gewoonte bovenaan het script even de naam neer te zetten. Voor je het weet, zit je anders in het verkeerde bestand te werken.

document.addEventListener("DOMContentLoaded", cssvSmallVideo);

Deze regel hoort eigenlijk niet helemaal bij de rest van het script. De rest van het script bestaat uit een zogenaamde 'functie': een stuk bij elkaar horende code dat je kunt uitvoeren door het aan te roepen. Deze regel doet niet meer dan die functie – op het juiste moment – aanroepen, zodat de code in de functie wordt uitgevoerd.

document: dit is een zogenaamd 'object'. Een object in JavaScript is iets, waarin onder andere allerlei gegevens zijn opgeslagen. In document is de hele pagina opgeslagen op een voor JavaScript toegankelijke manier. (Je hebt hele series objecten voor de wildste dingen, maar de meeste zijn hier verder niet van belang.)

Het voor JavaScript toegankelijke model van de pagina heet 'Document Object Model', afgekort tot 'DOM'. Dit wordt automatisch door de browser gemaakt, als de pagina wordt geladen. Door de regel te beginnen met document, weet het script waar de rest van de code op deze regel bij hoort: bij de hele pagina. (Je kunt ook code koppelen aan één specifieke <div>, of aan het indrukken van een toets, of ...)

addEventListener: er wordt een zogenaamde 'eventlistener' gekoppeld aan het voor de punt staande document, aan de pagina.

Een 'eventlistener' luistert naar een gebeurtenis. Die gebeurtenis, de 'event', kan van alles zijn: het indrukken van een toets, klikken, scrollen, de video is afgespeeld, van alles. Tussen de haakjes van addEventListener() staat, naar welke soort gebeurtenis moet worden geluisterd, en wat er moet gebeuren als die gebeurtenis zich voordoet. Zeg maar 'n soort rampenplan: áls gebeurtenis is 'doodsmak', dán handeling bel 112'.

"DOMContentLoaded": tussen aanhalingstekens, zodat het script weet dat dit een letterlijke naam is (dit is gewoon een van de taalkundige regels van JavaScript). Dit is de naam van de gebeurtenis, waarnaar wordt geluisterd, waarop wordt gewacht: 'DOMContentLoaded'. Als de inhoud van de hierboven genoemde DOM is geladen. In normale mensentaal: als de pagina door de browser is geladen. (Feitelijk nog niet de hele pagina, maar genoeg voor het script om met de pagina aan de slag te kunnen gaan.)

Deze regel roept de functie aan, die het eigenlijke script gaat uitvoeren. In die functie vraagt het script een lijstje op van alle op de pagina aanwezige <video>-elementen. De browser leest de html en plaatst aan de hand daarvan die <video>-elementen (en alle andere elementen op de pagina) in de DOM. Het script kan de <video>-elementen pas opvragen, als deze aanwezig zijn in de DOM. Als dat eerder zou gebeuren, stop het script er hevig teleurgesteld mee en doet het niets meer.

Daarom moet worden gewacht met het uitvoeren van de functie, tot de inhoud van de DOM is geladen.

Als de pagina opnieuw wordt geladen, wordt de DOM opnieuw opgebouwd en wordt de functie opnieuw uitgevoerd.

(Eigenlijk is dit niet nodig en zou je de functie ook op een andere manier kunnen aanroepen. Omdat de link naar het script helemaal onderaan de pagina met html staat, is de DOM namelijk hoe dan ook al opgebouwd, voordat het script wordt uitgevoerd. Maar iemand zou per ongeluk die link naar het script ook ergens hoger kunnen zetten, zoals jarenlang de gewoonte was, en dan zou het wel mis gaan.)

cssvSmallVideo: deze naam staat niet tussen aanhalingstekens, omdat het hier niet om een letterlijke naam of zo gaat. De naam verwijst naar een 'functie', iets wat moet gebeuren. Die functie staat hieronder. De naam ervan is 'cssSmallVideo'.

(Probeer op dit moment vooral niet de logica van wel of geen aanhalingstekens te begrijpen. Het makkelijkste is om dat soort dingen maar gewoon te accepteren. Nederlands heeft ook zo z'n eigenaardigheden...)

;: aan het eind van elke regel staat een puntkomma. Daarmee geef je aan dat de regel is afgelopen. In een gewoon boek zou je hier een punt gebruiken, om aan te geven dat een nieuwe zin begint.

De hele regel nog eens in gewone mensentaal: als de pagina is geladen, als de DOM is opgebouwd, voer dan de functie 'cssvSmallVideo' uit.

function cssvSmallVideo() {

function: het sleutelwoord waarmee het begin van een functie wordt aangegeven. Een functie is een stukje bij elkaar horende code.

cssvSmallVideo: de naam van de functie. Als het beestje geen naam heeft, kun je het ook niet aanroepen en heb je er dus niets aan. (Dit klopt niet helemaal. JavaScript kent ook equivalenten van 'hé!', 'hé, jij daar!', 'hé, jij daar in die zwarte jas', en dergelijke, maar die worden hier niet gebruikt. En het is zo al ingewikkeld genoeg.)

De naam van de functie is wat vreemd, maar de kans dat een of ander script of een bibliotheek (een verzameling scripts) van iemand anders toevallig dezelfde naam gebruikt, is daardoor uitermate klein.

(): tja, die haakjes horen nou eenmaal zo na de naam van een functie. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie. Maar in dit geval gebeurt dat niet.

{: geeft het begin van de code binnen de functie aan. Als je alle {'s en }'s uit het script in paren van twee zou nalopen, zou je zien dat deze { bij de allerlaatste } hoort. Hierdoor is voor de browser duidelijk, dat al deze code bij functie 'cssvSmallVideo' hoort.

var videoNodeList, len, i, width, screenWidth, sourceNodeList, len2, j, extension;

var: hiermee geef je aan dat hier één of meer 'variabelen' worden aangemaakt. In dit geval gaat het om negen variabelen, die worden gescheiden door een komma.

Het is gebruikelijk alle gebruikte variabelen bovenaan de functie te zetten. Dat maakt het overzichtelijker. (Bovendien, maar dat voert hier te ver, zorgt het gebruik van var ervoor dat de variabelen alleen binnen deze functie bestaan, zodat bij gebruik van meer scripts er niet een onoverzichtelijk oerwoud van variabelen ontstaat.)

videoNodeList, len, i, width, screenWidth, sourceNodeList, len2, j, extension: de namen van de variabelen, gescheiden door een komma.

De naam van een variabele mag je zelf bedenken, maar er zijn wel wat gewoontes. Zo wordt 'i' vaak gebruikt voor een simpele teller.

Een variabele is een soort portemonnee: je kunt er dingen in stoppen en uithalen, terwijl de portemonnee zelf, de variabele, niet wordt veranderd. Zo wordt verderop bijvoorbeeld de breedte van het browservenster opgevraagd en opgeslagen in de variabele 'screenWidth'. Als het venster 480 px breed is, is de inhoud van screenWidth '480', als het vensters 1024 px breed is, is de inhoud '1024'.

Als je zeker zou weten dat de vensterbreedte altijd 480 px is, zou je geen variabele nodig hebben. Je zou dan gewoon het getal '480' kunnen gebruiken. Maar omdat die breedte varieert, wordt hij opgeslagen in de variabele screenWidth. Je kunt dan allerlei dingen met screenWidth doen, ongeacht de precieze inhoud ervan. Als je er 100 bij op zou tellen, wordt er altijd 100 bij de inhoud van screenWidth opgeteld, ongeacht of het venster 480 of 1024 px breed is.

Je kunt hier gelijk een waarde aan de variabele geven, maar dat gebeurt hier niet. Dat gebeurt in dit script op de plaats, waar de variabele echt gebruikt gaat worden.

;: aan het eind van de regel staat weer een ;, zodat duidelijk is dat deze regel, het aanmaken van de variabelen, hier eindigt.

videoNodeList = document.getElementsByTagName("video");

videoNodeList: deze regel maakt een lijstje van alle <video>-elementen op de pagina.

Om met dat lijstje te kunnen werken, moeten ze ergens in worden opgeborgen. Dat gebeurt in de variabele videoNodeList. Niet alleen het <video>-element zelf wordt opgeslagen, dat zou wat zinloos zijn. Er worden ook allerlei gegeven van <video> opgeslagen, zoals de hoogte, de breedte, of controls aanwezig is of niet, enz. Er wordt een <video>-'object' opgeslagen: een hele serie gegevens.

(Je kunt ook nog allerlei dingen met zo'n <video>-object doen, zoals de video starten en pauzeren, maar dat gebeurt hier niet.)

=: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat, moet worden opgeslagen.

document: dit geeft aan, waaraan de code van de rest van deze regel gekoppeld moet worden. In document is de hele pagina opgeslagen op een voor JavaScript toegankelijke manier.

getElementsByTagName: zoek bepaalde elementen op aan de hand van de naam van de tag. Het maakt niet uit, hoeveel of hoe weinig van die elementen er zijn, ze worden allemaal opgezocht en in videoNodeList opgeslagen.

("video"): de tag waarnaar wordt gezocht, tussen aanhalingstekens. De in de html gebruikte < en > worden weggelaten, alleen de naam van de tag wordt gebruikt.

De hele regel nog eens in gewone mensentaal: haal alle <video>'s op en berg die op in videoNodeList.

Elk in videoNodeList opgeslagen <video>-object heeft een eigen volgnummer, zodat je elk <video>-object apart kunt opvragen, wijzigen, enz. Omdat computers dol zijn op het getal '0', heeft het eerste <video>-object als volgnummer '0'. In dit voorbeeld zijn vier <video>'s aanwezig, dus er zitten vier <video>-objecten in videoNodeList. Het eerste object kan worden opgevraagd met videoNodeList[0], het tweede met videoNodeList[1], het derde met videoNodeList[2] en het vierde en laatste met videoNodeList[3].

len = videoNodeList.length;

In dit voorbeeld zijn vier <video>'s aanwezig, maar dat kunnen er natuurlijk meer of minder zijn. Daarom wordt de lengte van videoNodeList opgevraagd. Dat levert het aantal gevonden <video>-objecten op. Dat aantal wordt in de variabele len opgeslagen. Op deze manier weten we, hoeveel <video>-objecten er verwerkt moeten worden.

In dit geval is len hetzelfde als het getal 4. Zouden er 38 <video>'s zijn gevonden, dan zou len hetzelfde zijn als het getal 38.

Dat is het handige van een variabele: je hoeft niet te weten, wat de inhoud ervan is, terwijl er toch bijvoorbeeld mee gerekend kan worden.

if (len === 0) return false;

Het kan natuurlijk zijn dat een of andere sufkont het script aanroept, maar dat er helemaal geen <video>'s in de html aanwezig zijn. In dat geval moet het script er op 'n beetje fatsoenlijke manier mee stoppen. Je kunt ook voor straf bloeddruppels over het beeldscherm laten lopen, of het geluid van een krijtje op 'n schoolbord laten horen, maar we houden het 'n beetje vriendelijk.

if: dat betekent gewoon 'als': als er aan de voorwaarde hierachter is voldaan. Die voorwaarde staat tussen haakjes, omdat dat nou eenmaal zo hoort.

(len === 0): de voorwaarde waaraan moet worden voldaan. In len is het aantal <video>-objecten opgeslagen. Als dat aantal 0 is, waren er dus geen <video>'s aanwezig. Er staan maar liefst drie isgelijktekens. Het voert te ver om de reden daarvan hier uit te leggen, maar het zorgt ervoor dat len echt zeker erewoord precies 0 is.

Als len meer dan 0 is, waren er kennelijk <video>'s aanwezig en wordt niet aan de volgorde van de if voldaan. De rest van de regel wordt dan overgeslagen en er wordt verdergegaan met de volgende regel.

Als len 0 is, is aan de voorwaarde van de if voldaan en wordt de rest van de code op de regel uitgevoerd.

return false: stop met deze functie en ga terug naar waar je vandaan kwam. Oftewel: voer de rest van dit script niet uit. false wil alleen maar zeggen, dat er niets wordt teruggegeven door het script.

;: de puntkomma geeft weer het eind van de regel aan.

De hele regel in gewone mensentaal: als er geen <video> aanwezig is op de pagina, stop dan met dit script.

screenWidth = window.innerWidth;

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarde is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

Als het browservenster smaller is dan een bepaalde breedte, moet een kleinere video worden gebruikt. Hier wordt de breedte van het venster opgevraagd.

screenWidth: in deze variabele wordt de breedte van het browservenster opgeslagen. Als het venster 480 px breed is, bevat deze variabele het getal 480, zonder 'px'. Als het venster 1024 px breed is, is de waarde van deze variabele 1024.

=: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat, moet worden opgeslagen.

window: de breedte van het browservenster is opgeslagen in het object met de naam window. Daarin zitten nog veel meer gegevens, maar hier is alleen de breedte van belang. Het eigenlijke gegeven waar het om gaat volgt op window, gescheiden door een punt.

innerWidth: de breedte van het browservenster zonder scrollbalk, toolbars, en dergelijke. Zeker in het verleden gaven browsers nogal eens een verkeerde breedte door. Dat is wel verbeterd, maar vooral oudere mobiele browsers willen nog wel 'ns 'n beetje jokken.

;: aan het eind van de regel staat weer de afsluitende puntkomma.

De hele regel in gewone mensentaal: vraag de breedte van het browservenster in px op en sla dit als een gewoon getal, zonder 'px' op in de variabele screenWidth.

Tot nu toe is alleen een aantal noodzakelijk gegevens opgevraagd. Vanaf nu gaat het script echt beginnen.

for (i = 0; i < len; i++) {

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarde is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

for: doe iets met iets, zolang iets waar is. Nou, is dat lekker vaag of niet? Wat er waarmee moet gebeuren, komt later. Dat staat tussen de {} aan het eind van de regel. (In de echte code staat de laatste } lager, achter wat er waarmee moet gebeuren.)

Hier eerst het deel dat ervoor zorgt dat elk eerder gevonden <video>-object netjes aan de beurt komt.

(: met dit haakje opent het deel dat ervoor zorgt, dat elk <video>-object aan de beurt komt. Aan het eind van de regel staat de bijbehorende ), waardoor het script weet dat dit het einde van dit deel van de code is.

i = 0;: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat, moet worden opgeslagen. In dit geval is dat resultaat heel simpel: het is het getal 0.

De variabele heet hier 'i'. Dat is een heel korte naam. 'i' wordt gebruikt als een teller (waarover later meer), en bij dit soort tellers is het gebruikelijk ze de naam 'i' te geven. Dat soort gewoontes maakt het voor mensen een stuk makkelijker elkaars code te lezen en te begrijpen.

Omdat i een variabele is, kan de waarde ervan veranderen, variëren. Wat later in de regel ook gaat gebeuren: elke keer als er een <video>-object is afgehandeld, wordt 'i' met 1 verhoogd. Dat gebeurt in het laatste deel van de regel.

De ; geeft aan dat dit stukje code, waarin de variabele 'i' z'n beginwaarde krijgt, hier eindigt.

i++: eerst het laatste deel, het middelste deel komt gelijk hieronder.

Elke keer als een in videoNodeList zittend <video>-object is afgehandeld, 1 optellen bij 'i'. Omdat programmeurs liederlijk lui zijn, wordt 'er 1 bij optellen' afgekort tot ++.

Als i 0 is, betekent i++: i wordt 0 + 1 ('1' dus).

Als i 1 is, betekent i++: i wordt 1 + 1 ('2' dus).

Als i 2 is, betekent i++: i wordt 2 + 1 ('3' dus).

Als i 3 is, betekent i++: i wordt 3 + 1 ('4' dus). En meer dan 4 wordt het niet, vanwege redenen die gelijk hieronder staan.

i < len;: het middelste deel. In len is eerder het aantal <video>-objecten in videoNodeList opgeslagen. Omdat er in dit voorbeeld vier <video>'s op de pagina staan, is de waarde van len 4.

i bevat een getal. Voordat het eerste <video>-object is verwerkt, is dat getal 0, want dat is hierboven opgegeven.

Het teken < betekent: kleiner dan.

De ; aan het einde geeft aan, dat dit stukje code, de voorwaarde waaraan moet worden voldaan, hier eindigt.

In gewone mensentaal staat hier: zolang teller i kleiner is dan len.

Als niet meer aan deze voorwaarde wordt voldaan, als teller i niet meer kleiner is dan len, stop dan met het uitvoeren van de code die tussen de {} staat. En omdat len even groot is als het aantal <video>-objecten in videoNodeList, geeft dit een mogelijkheid om elk <video>-object precies één keer te verwerken. En er, als ze allemaal verwerkt zijn, mee te stoppen.

): dit haakje hoort bij de ( gelijk achter for. Tussen deze twee haakjes staat de code, die ervoor zorgt dat elk <video>-object aan de beurt komt.

{: het laatste teken op de regel. Hiermee geef je aan dat hierna de code volgt die uitgevoerd moet worden. Tot nu toe is alleen gezorgd dat er bij elk <video>-object íéts moet gebeuren, maar nog niet wát. Dat wát volgt na deze {. Na de code die moet worden uitgevoerd staat nog een afsluitende }. Hiermee geef je aan dat het uitvoerende deel van de code hier stopt.

Dat uitvoerende deel is op een nieuwe regel gezet, net zoals de afsluitende }. Dat soort dingen zijn informele afspraken, omdat het de code voor mensen leesbaarder maakt. Wat de computer betreft zou je alles ook achter elkaar kunnen zetten op één onwijs lange regel. Alleen is niet alleen die regel dan onwijs, ook de gemiddelde programmeur zou heel snel bijzonder onwijs worden, als alles op één lange regel wordt gezet.

Elke keer als een <video>-object is behandeld (met het stukje code tussen de {}, wat hieronder aan de beurt komt), wordt i door middel van i++ met 1 verhoogd.

Aan het begin heeft i de waarde 0. Na de eerste ronde heeft i de waarde 1. Na de tweede ronde heeft i de waarde 2. Na de derde ronde heeft i de waarde 3. Na de vierde ronde heeft i de waarde 4. Waarmee i niet meer kleiner is dan len, dan het aantal <video>-objecten.

Omdat niet meer aan de voorwaarde i < len wordt voldaan, wordt gestopt met het behandelen van de <video>-objecten. En dat komt goed uit, want alle <video>-objecten zijn precies allemaal één keer aan de beurt gekomen. Niet meer, niet minder. Bij allemaal is de tussen de {} staande code één keer toegepast.

De code tussen de haakjes in gewone taal: zet teller i op 0 als de for de eerste keer wordt uitgevoerd. Herhaal de for zolang teller i lager is dan het aantal <video>-objecten. Verhoog teller i elke keer als de for wordt uitgevoerd met 1.

width = parseInt(videoNodeList[i].getAttribute("data-smscr"), 10);

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarde is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

Hier wordt gekeken of bij het <video>-object, dat aan de beurt is, in de html het attribuut data-smscr aanwezig is. Als dat zo is, wordt het erin zittende getal – als dat er is – opgeslagen in de variabele width.

width: in deze variabele wordt de in de html opgegeven waarde van data-smscr opgeslagen. Omdat de <video>-objecten één voor één worden afgewerkt, mag elke <video> desgewenst een andere waarde hebben. Het kan dus prima dat bij de eerste <video> al in een browservenster van 800 px breed een kleinere video wordt gebruikt, en bij de derde <video> pas als het venster smaller dan 480 px is.

parseInt: er moet gerekend gaan worden met de opgegeven breedte. Rekenen kan alleen met een getal. parseInt doet niets anders dan van een stukje tekst een getal maken. Eigenlijk nog iets meer: Int staat voor 'integer', dat wil zeggen dat het eindresultaat een heel getal is, zonder decimalen en zo.

In de html is opgegeven data-smscr = "480". Omdat dit tussen aanhalingstekens staat (dat kan niet anders in html), is dit wat JavaScript betreft geen getal, maar een stukje tekst. Net zoals het huisnummer 49 eigenlijk geen getal is, maar een aanduiding. Je gaat niet rekenen met huisnummers, ook al zijn het getallen. "480" is vergelijkbaar met een huisnummer. parseInt maakt van '480' een echt getal, waarmee gerekend kan worden.

Tussen de haakjes achter parseInt staat, waar parseInt het getal kan vinden. Dat staat in het deel voor de komma.

Achter de komma staat het getal 10. Dat wil zeggen, dat het om een gewoon tientallig getal gaat. 'Gewoon' voor mensen, want wat de computer betreft kan het even makkelijk 'n tweetallig of een achtendertigtallig getal zijn. Het praktische effect hiervan is dat '480' gewoon '480' blijft, en niet wordt omgezet naar iets engs als 111100000 (480 in een tweetallig stellig).

videoNodeList[i]: in videoNodeList zijn alle <video>-objecten opgeslagen. Elk <video>-object heeft een eigen volgnummer. Het eerste <video>-object heeft als volgnummer 0, het vierde 3, omdat computers nou eenmaal dol zijn op 0.

Deze regel maakt deel uit van de hierboven besproken for-lus. i is een teller. De eerste keer dat de code in de for-lus wordt uitgevoerd is i 0, de tweede keer is i 1, de derde keer 2 en de vierde en laatste keer 3.

(Omdat er maar vier <video>'s zijn in dit voorbeeld, stopt de for-lus na het vierde <video>-object. Als er meer of minder <video>'s op de html-pagina zijn, wordt dit automatisch aangepast.)

Eigenlijk staat hier dus de eerste keer dat de for-lus wordt uitgevoerd videoNodeList[0], de tweede keer videoNodeList[1], de derde keer videoNodeList[2] en de derde keer videNodeList[3]. videoNodeList[0] is het eerste <video>-object, videoNodeList[3] is het vierde <video>-object, en de twee ertussen liggende kun je zelf wel bedenken.

Elke keer dat code in de for-lus wordt uitgevoerd, wordt dus een volgend <video>-object bekeken. Tot ze allemaal – in dit voorbeeld vier – zijn bekeken.

getAttribute("data-smscr"): haal bij het <video>-object het attribuut met de naam 'data-smscr' op. Of eigenlijk: haal de inhoud daarvan op. In de html van het voorbeeld staat bij <video> data-smscr = "480", dus hier levert dat '480' op. Omdat gelijk hiervoor, gescheiden door een punt, videoNodeList[i] staat, gaat het om het attribuut bij het <video>-object dat bij videoNodeList[i] hoort.

De hele regel in gewone mensentaal: haal bij het <video>-object dat aan de beurt is de waarde van data-smscr op en maak daar een mooi geheel tientallig getal van.

if ((width > 0) && (screenWidth < width)) {

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarde is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

if: 'als'. Als aan de voorwaarden die achter de if staan is voldaan. Die voorwaarden staan tussen haakjes. In dit geval gaat het om twee voorwaarden, en aan beide moet worden voldaan: width > 0 en screenWidth < width. Alleen als aan beide voorwaarden is voldaan, wordt de code na de { aan het eind van de regel uitgevoerd.

Als dat niet zo is, wordt met het volgende <video>-object verder gegaan (als er nog een volgend object is).

(width > 0): dit is de eerste voorwaarde, waaraan moet worden voldaan. De voorwaarden achter de if staan tussen haakjes. Om de code duidelijker leesbaar te maken, zijn beide voorwaar afzonderlijk ook tussen haakjes gezet. Dit is de eerste voorwaarde.

In de variabele width is iets hierboven de in de html bij <video> opgegeven waarde van data-smscr opgeslagen. Althans: dat is geprobeerd. In data-smscr hoort een getal te zitten, dat de breedte van het browservenster aangeeft, waaronder de kleinere video moet worden getoond.

Als zo'n getal is gevonden, zit dat in de variabele width. Als zo'n getal niet is gevonden, omdat er helemaal geen data-smscr bij <video> staat, of omdat er geen waarde bij data-smscr is opgegeven, of omdat er foutief iets als data-smscr = "klein" (daar is geen getal van te maken) is opgegeven, of wat voor reden dan ook, is width geen getal.

Het teken > betekent 'groter dan'. width > 0 betekent: 'width groter dan 0'. width kan alleen groter dan 0 zijn, als er een getal in zit. Als er in data-smscr een getal was opgegeven. Als er geen getal in width zit, kan width nooit groter dan 0 zijn en wordt aan de eerste voorwaarde (width > 0) niet voldaan.

De tweede voorwaarde achter de && wordt dan niet eens meer bekeken, er wordt gelijk verder gegaan met het volgende <video>-object.

&&: dit is JavaScriptiaans voor én. Voor de && staat tussen haakjes de eerste voorwaarde, achter de && staat tussen haakjes de tweede voorwaarde. Alleen als aan beide voorwaarden is voldaan, wordt de code achter de { aan het eind van de regel uitgevoerd.

(screenWidth < width): dit is de tweede voorwaarde.. In de variabele screenWidth is eerder de breedte van het browservenster in pixels opgeslagen. In de variabele width is eerder de in de html bij data-smscr opgegeven vensterbreedte opgeslagen, waaronder de kleinere video moet worden getoond. < betekent 'kleiner dan'.

Hier staat dus: als de breedte van het browservenster minder is dan de in de html bij data-smscr opgegeven breedte. Alleen als aan deze voorwaarde is voldaan, wordt de code achter de { aan het eind van de regel uitgevoerd.

{: de code die wordt uitgevoerd, als aan deze if-voorwaarde wordt voldaan, is wat ingewikkelder. Daarom moet die code tussen accolades worden gezet. De browser weet dan, wat bij deze if hoort.

De regel in normale mensentaal: als er in de html bij data-smscr een minimumbreedte is opgegeven én als het browservenster smaller is dan die minimumbreedte, voer dan de code bij deze if uit.

sourceNodeList = videoNodeList[i].querySelectorAll("source");

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarden is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

– Er is een geldige minimumbreedte opgegeven in het data-smscr-attribuut van het <video>-object dat wordt verwerkt.

– Het browservenster is smaller dan die opgegeven minimumbreedte.

sourceNodeList: in deze variabele worden alle <source>'s opgeslagen, die horen bij het <video>-object dat wordt verwerkt. De <source>'s worden weer opgeslagen in de vorm van een object, waardoor ook attributen uit de <source> als src en type worden opgeslagen. En later door het script opgevraagd of veranderd kunnen worden.

=: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat, moet worden opgeslagen.

videoNodeList[i]: in videoNodeList zitten alle <video>-objecten opgeslagen. Elk <video>-object heeft een eigen volgnummer. Het eerste <video>-object heeft als volgnummer 0, het vierde 3, omdat computers nou eenmaal dol zijn op 0.

Deze regel maakt deel uit van de hierboven besproken for-lus. i is een teller. De eerste keer dat de code in de for-lus wordt uitgevoerd is i 0, de tweede keer is i 1, de derde keer 2 en de vierde en laatste keer 3. (Omdat er maar vier <video>'s zijn in dit voorbeeld, stopt de for-lus na het vierde <video>-object. Als er meer of minder <video>'s op de html-pagina zijn, wordt dit automatisch aangepast.)

Eigenlijk staat hier dus de eerste keer dat de for-lus wordt uitgevoerd videoNodeList[0], de tweede keer videoNodeList[1], de derde keer videoNodeList[2] en de derde keer videNodeList[3]. videoNodeList[0] is het eerste <video>-object, videoNodeList[3] is het vierde <video>-object, en de twee ertussen liggende kun je zelf wel bedenken.

Elke keer dat code in de for-lus wordt uitgevoerd, wordt dus een volgend <video>-object bekeken. Tot ze allemaal – in dit voorbeeld vier – zijn bekeken.

.querySelectorAll: hiermee worden alle elementen opgezocht die voldoen aan een bepaalde voorwaarde. Die voorwaarde staat tussen haakjes gelijk hierachter en wordt hieronder besproken.

Gelijk hiervoor staat, gescheiden door een punt, videoNodeList[i], waarbij in teller i het volgnummer zit van het <video>-object dat aan de beurt is. De totale zoekvoorwaarde is dus videoNodeList[i].querySelectorAll. Door dit aan elkaar koppelen met alleen een punt ertussen, geldt querySelectorAll alleen voor het videoNodeList[i], het <video>-object dat aan de beurt is, en niet voor de hele pagina of zoiets.

("source"): dit is waarnaar wordt gezocht: alle <source>'s. Maar alleen de <source>'s die horen bij het <video>-object dat aan de beurt is, en niet alle <source>'s op de pagina.

;: en weer de afsluitende puntkomma aan het eind van de regel.

De regel in normale mensentaal: berg alle <source>'s van het <video>-object dat aan de beurt is op in de variabele sourceNodeList.

len2 = sourceNodeList.length;

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarden is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

– Er is een geldige minimumbreedte opgegeven in het data-smscr-attribuut van het <video>-object dat wordt verwerkt.

– Het browservenster is smaller dan die opgegeven minimumbreedte.

In dit voorbeeld zijn vier <source>'s aanwezig in elk <video>-object, maar er kunnen er natuurlijk meer of minder zijn. Daarom wordt de lengte van sourceNodeList opgevraagd. Dat levert het aantal gevonden <source>-objecten op. Dat aantal wordt in de variabele len2 opgeslagen. Op deze manier weten we, hoeveel <source>-objecten er verwerkt moeten worden.

for (j = 0; j < len2; j++) {

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarden is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

– Er is een geldige minimumbreedte opgegeven in het data-smscr-attribuut van het <video>-object dat wordt verwerkt.

– Het browservenster is smaller dan die opgegeven minimumbreedte.

Deze for-lus werkt precies hetzelfde als de eerdere for-lus voor <video>-objecten. De uitleg is dus ook vrijwel hetzelfde. Deze is te vinden bij for (i = 0; i < len; i++) {. Enkele kleine verschillen:

Hier worden niet de <video>-objecten, maar de <source>-objecten bekeken.

Als teller wordt niet i gebruikt, maar j. Omdat i al als teller voor de video-objecten in gebruik is, is voor de <source>-objecten een andere teller nodig, en dat is j.

Bij de <video>-objecten is het aantal objecten opgeslagen in variabele len. Bij deze <source>-objecten is het aantal objecten opgeslagen in variabele len2, want je kunt niet één variabele voor twee getallen gebruiken. (Hmmm, dat kan wel, maar dat zou hier onnodig ingewikkeld zijn.)

if (sourceNodeList[j].getAttribute("data-smscr") === "small") {

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarden is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

– Er is een geldige minimumbreedte opgegeven in het data-smscr-attribuut van het <video>-object dat wordt verwerkt.

– Het browservenster is smaller dan die opgegeven minimumbreedte.

if: 'als'. Als aan de voorwaarde die achter de if staat is voldaan. Die voorwaarde staat tussen haakjes. Alleen als aan die voorwaarde is voldaan, wordt de code na de { aan het eind van de regel uitgevoerd.

Als dat niet zo is, wordt met het volgende <video>-object verder gegaan (als er nog een volgend object is).

sourceNodeList[j]: in sourceNodeList zitten alle <source>-objecten opgeslagen, die horen bij het <video>-object dat wordt verwerkt. Als er in de html vier <source>'s zijn bij een <video>, zoals in het voorbeeld het geval is, zijn er vier <source>-objecten.

Elk <source>-object heeft een eigen volgnummer. Het eerste <source>-object heeft als volgnummer 0, het vierde 3, omdat computers nou eenmaal dol zijn op 0.

Deze regel maakt deel uit van de hierboven besproken for-lus. j is een teller. De eerste keer dat de code in de for-lus wordt uitgevoerd is j 0, de tweede keer is j 1, de derde keer 2 en de vierde en laatste keer 3. (Omdat er maar vier <source>'s zijn in dit voorbeeld, stopt de for-lus na het vierde <source>-object. Als er meer of minder <source>'s op de html-pagina zijn bij een bepaalde <video>, zitten er meer of minder <source>'s in het bijbehorende <video>-object en wordt dit automatisch aangepast.)

Eigenlijk staat hier dus de eerste keer dat de for-lus wordt uitgevoerd sourceNodeList[0], de tweede keer sourceNodeList[1], de derde keer sourceNodeList[2] en de derde keer sourceNodeList[3]. sourceNodeList[0] is het eerste <source>-object, sourceNodeList[3] is het vierde <source>-object, en de twee ertussen liggende kun je zelf wel bedenken.

Elke keer dat code in de for-lus wordt uitgevoerd, wordt dus een volgend <source>-object bekeken. Tot ze allemaal – in dit voorbeeld vier – zijn bekeken.

getAttribute("data-smscr"): haal bij het <source>-object het attribuut met de naam 'data-smscr' op. Of eigenlijk: haal de inhoud daarvan op. In de html van het voorbeeld staat bij de <source>'s voor kleine video's data-smscr = "small", dus hier levert dat 'small' op. Omdat gelijk hiervoor, gescheiden door een punt, sourceNodeList[j] staat, gaat het om het attribuut bij het <source>-object dat bij sourceNodeList[j] hoort.

Tot nu toe is geprobeerd de inhoud van data-smscr bij deze <source> op te halen. Als die inhoud 'small' is, is deze video bedoeld voor smallere browservensters. Als data-smscr niet aanwezig is, gaat het om een grote video, en is er geen inhoud van data-smscr gevonden. (Het voert hier te ver om uit te leggen, wat er dan wel is gevonden, maar het zal duidelijk zijn dat in ieder geval niet spontaan het woord 'small' is gevonden, als dit niet in de html van deze <source> aanwezig is.)

Als in de html een ander woord dan 'small' als waarde bij data-smscr is opgegeven, wordt dat andere woord gevonden. Stel dat iemand per ongeluk data-smscr = "smal" in de html heeft gezet, dan wordt 'smal' gevonden.

Alleen als in de html bij de <source> exact data-smscr = "small" staat, wordt als resultaat van dit opvragen 'small' gevonden. In alle andere gevallen is het resultaat iets anders dan 'small'.

sourceNodeList[j].getAttribute("data-smscr") === "small": dit is de eigenlijke voorwaarde.

Het hele deel voor de drie isgelijktekens bevat de inhoud van het data-smscr-attribuut, dat bij het <source>-object hoort dat wordt verwerkt.

De drie isgelijktekens geven aan dat die inhoud écht éérlijk waar zéker weten precies hetzelfde moet zijn, als wat achter de drie isgelijktekens staat: 'small'. Alleen als de waarde van het opgevraagde data-smscr-attribuut precies 'small' is, wordt aan de voorwaarde bij deze if voldaan.

{: de code die wordt uitgevoerd, als aan deze if-voorwaarde wordt voldaan, is wat ingewikkelder. Daarom moet die code tussen accolades worden gezet. De browser weet dan, wat bij deze if hoort.

extension = sourceNodeList[j].src.substring(sourceNodeList[j].src.lastIndexOf(".") + 1);

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarden is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

– Er is een geldige minimumbreedte opgegeven in het data-smscr-attribuut van het <video>-object dat wordt verwerkt.

– Het browservenster is smaller dan die opgegeven minimumbreedte.

data-smscr="small" is aanwezig in het <source>-object dat wordt verwerkt.

De ingewikkeldste regel uit het script. Het enige wat deze regel doet: de extensie van de in de <source> staande video inlezen, zodat in de volgende regel gekeken kan worden, of de browser deze video kan afspelen. Als de browser de video niet af kan spelen, heeft het geen zin er verder naar te kijken.

(Je kunt die extensie op meerdere manieren opvragen, maar niet elke manier is waterdicht. Het zou bijvoorbeeld kunnen zijn dat er meerdere punten in de bestandsnaam voorkomen. Met deze methode wordt de laatste punt in de bestandsnaam opgezocht, en het deel daarachter wordt als extensie gezien. Bij 'ik.ben.een.video.webm' zou de extensie dan 'webm' zijn, ongeacht die eigenaardige punten ervoor.)

extension: achter het isgelijkteken wordt de extensie van de video opgevraagd. Deze wordt opgeslagen in de variabele extension, zodat die later kan worden gebruikt. Omdat die extensie allerlei waarden kan hebben (mp4, ogg, webm, ...), kan niet rechtstreeks iets als 'mp4' worden gebruikt. Door de extensie op te slaan in een variabele, kan de extensie worden gebruikt, ongeacht wat die extensie nou precies is.

=: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat, moet worden opgeslagen.

sourceNodeList[j]: in sourceNodeList zitten alle <source>-objecten opgeslagen, die horen bij het <video>-object dat wordt verwerkt. Als er in de html vier <source>'s zijn bij een <video>, zoals in het voorbeeld het geval is, zijn er vier <source>-objecten.

Elk <source>-object heeft een eigen volgnummer. Het eerste <source>-object heeft als volgnummer 0, het vierde 3, omdat computers nou eenmaal dol zijn op 0.

Deze regel maakt deel uit van de hierboven besproken for-lus. j is een teller. De eerste keer dat de code in de for-lus wordt uitgevoerd is j 0, de tweede keer is j 1, de derde keer 2 en de vierde en laatste keer 3. (Omdat er maar vier <source>'s zijn in dit voorbeeld, stopt de for-lus na het vierde <source>-object. Als er meer of minder <source>'s op de html-pagina zijn bij een bepaalde <video>, zitten er meer of minder <source>'s in het bijbehorende <video>-object en wordt dit automatisch aangepast.)

Eigenlijk staat hier dus de eerste keer dat de for-lus wordt uitgevoerd sourceNodeList[0], de tweede keer sourceNodeList[1], de derde keer sourceNodeList[2] en de derde keer sourceNodeList[3]. sourceNodeList[0] is het eerste <source>-object, sourceNodeList[3] is het vierde <source>-object, en de twee ertussen liggende kun je zelf wel bedenken.

Elke keer dat code in de for-lus wordt uitgevoerd, wordt dus een volgend <source>-object bekeken. Tot ze allemaal – in dit voorbeeld vier – zijn bekeken.

src: in src zijn pad naar en naam van de video opgeslagen. Dit is één van de gegevens die in het <source>-object is te vinden. De inhoud is hetzelfde als wat in de html bij <source> als src is opgegeven.

Omdat gelijk hiervoor, gescheiden door een punt, sourceNodeList[j] staat, gaat het om de src van het <source>-object dat bij sourceNodeList[j] hoort.

sourceNodeList[j].src levert dus het pad en de naam op van de video, die hoort bij het <source>-object dat wordt verwerkt. Omdat eerder als een van de voorwaarden is opgegeven dat in dit <source>-object data-smscr = "small" moet zitten, is dit een video die is bedoeld voor een smaller browservenster.

Het is leuk dat pad en naam van die kleine video zijn gevonden, maar op dit moment is alleen de extensie van die video interessant. Aan de hand van die extensie kan de browser vaststellen, of de video is af te spelen. De extensie is per definitie het deel van de bestandsnaam, dat achter de laatste punt staat. Bij plaatje.jpg is dat 'jpg', bij video.webm is het 'webm'. Dat stukje moet dus uit de gevonden pad‑ en bestandsnaam worden gepeuterd. Dit gebeurt met het tweede deel van deze regel: substring(sourceNodeList[j].src.lastIndexOf(".") + 1).

Omdat voor dit tweede deel, gescheiden door een punt, sourceNodeList[j].src staat, weet het script dat dit bij de in het eerste deel gevonden src hoort. (Waarom je twee keer sourceNodeList[j].src moet schrijven, is meer iets voor een cursus JavaScript.)

Dit tweede deel is iets beter te begrijpen, als hier niet precies de volgorde van de code wordt aangehouden.

lastIndexOf("."): de plaats van de laatste punt, geteld vanaf de voorkant van de te onderzoeken tekst. Omdat voor de punt sourceNodeList[j].src staat, weet het script dat het om het daarin zittende pad naar en naam van de video gaat.

Stel dat de naam van de video 'video.webm' is. In sourceNodeList[j].src is in dat geval 'video.webm' opgeslagen. Dan staat de punt op de vijfde plaats. De vijfde??? Ja, want de computer begint met 0 te tellen. Op plaats 0 staat de 'v', op plaats 1 staat de 'i', ..., en de punt staat op de vijfde plaats. sourceNodeList[j].src.lastIndexOf(".") levert dan als resultaat 5 op. Dat betekent dat je dat hele verhaal sourceNodeList[j].src.lastIndexOf(".") kunt vervangen door '5'.

Het tweede deel wordt nu een stuk overzichtelijker: substring(5 + 1).

Als de videonaam 'ik-ben-een-video.mp4' zou zijn, zou de punt op de zestiende plaats staan en zou je sourceNodeList[j].src.lastIndexOf(".") kunnen vervangen door '16', omdat de punt op de zestiende plaats staat.

substring(sourceNodeList[j].src.lastIndexOf(".") + 1): Hier gelijk boven is duidelijk geworden, dat je sourceNodeList[j].src.lastIndexOf(".") kunt vervangen door '5' (als de videonaam 'video.webm' zou zijn), omdat de punt op de vijfde plaats staat (de computer begint te tellen met 0).

Het ziet er dan zo uit: substring(5 + 1). Op de vijfde plaats staat de punt, de extensie begint dus gelijk ná die vijfde plaats. Vandaar de + 1: het gaat om de plaats gelijk na de punt. 5 + 1 = 6, dus de uitdrukking wordt nog simpeler: substring(6). Dit wil zeggen, dat het gaat om de tekst die op de zesde plaats begint. Bij 'video.webm' is dat 'webm'. (Als je meer getallen opgeeft bij substring kun je ook 'n stukje eruit halen, maar omdat hier alleen 6 is opgegeven, wordt alles tot het einde van de naam van de video gebruikt.)

;: als afsluiting van de regel weer de puntkomma.

In gewone mensentaal doet deze regel het volgende: zoek de laatste punt op in de bestandsnaam van de video. Daarachter staat per definitie de extensie van de video. Berg die extensie op in de variabele extension, zodat die later kan worden gebruikt.

if (videoNodeList[i].canPlayType("video/" + extension) !== "") {

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarden is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

– Er is een geldige minimumbreedte opgegeven in het data-smscr-attribuut van het <video>-object dat wordt verwerkt.

– Het browservenster is smaller dan die opgegeven minimumbreedte.

data-smscr="small" is aanwezig in het <source>-object dat wordt verwerkt.

Het is natuurlijk alleen maar zinvol om de gevonden kleine video te gebruiken, als de browser deze af kan spelen. In het voorbeeld worden twee formaten gebruikt voor elke video: 'webm' en 'mp4'. Hiermee wordt elke browser bestreken. Als de browser deze video kan afspelen, wordt niet verder gezocht. Als de browser dat niet kan, wordt met het volgende <source>-object verder gegaan, als er nog een volgende is.

Met behulp van canPlayType() kan aan de browser worden gevraagd, of de browser denkt dat de video afgespeeld kan worden. Hiervoor moet het zogenaamde MIME-type worden doorgegeven aan de browser. In het voorbeeld worden alleen webm‑ en mp4- video's gebruikt. Het MIME-type daar van is 'video/webm' en 'video/mp4'. Door dit door te geven aan de browser, kan deze kijken of de video afgespeeld kan worden.

Dit is geen waterdichte methode. De browser kan namelijk drie verschillende antwoorden geven. Als het antwoord "" is, kan de browser de video niet afspelen. "" is een zogenaamde lege string: het is wel tekst, maar er zit niets in. Ongeveer alsof de browser van verbijstering z'n mond open laat vallen en geen woord meer uit kan brengen, vanwege de idiote suggestie dat de browser déze video af zou kunnen spelen.

Het tweede mogelijke antwoord is maybe, 'misschien'. De browser kijkt naar het tweede deel van het MIME-type, 'webm' of 'mp4' en meldt: ja, dat zal misschien wel lukken. In de praktijk gaat dit vrijwel altijd goed. Maar 'webm', 'mp4', en dergelijke zijn eigenlijk zogenaamde containers: er kan van alles in zitten. Net zoals je in een zip-bestand afbeeldingen, tekst, video's, noem maar op kunt hebben zitten. Terwijl de extensie alleen maar 'zip' is. In een webm‑, mp4-, ogg‑, enz. bestand kunnen verschillende coderingen zijn gebruikt, om de video zo klein mogelijk te maken. Als een exotische codec is gebruikt, kan het zijn dat de browser wel webm, mp4, ogg, en dergelijke kan afspelen, maar net deze codec niet.

(Dit is ook de reden dat het een goede gewoonte is onder de video een link te zetten, waarmee de video kan worden gedownload. Als de browser de video niet af kan spelen, kan een ander programma dat allicht wel.)

Als je echt vrijwel zeker wilt weten, of de browser de video af kan spelen, moet je niet alleen het MIME-type, maar ook de gebruikte codec opgeven. Dat wordt vrijwel nooit gedaan. Het ziet er, voor een 'webm', bijvoorbeeld zo uit:

<source src="video.webm" type="video/webm; codecs='vp8, vorbis'">

De gebruikte codecs zijn hier 'vp8' en 'vorbis'. Als ook de codecs zijn opgegeven, kan de browser als antwoord de derde mogelijkheid geven: 'probably'. Dit script test niet op codecs, dus het derde antwoord 'probably' wordt nooit gegeven. (Overigen zit in 'probably', 'waarschijnlijk', ook al ingebakken dat zelfs dit geen waterdichte garantie is dat de video afgespeeld kan worden.)

Er blijven, wat dit script betreft, dus twee mogelijke antwoorden over: "" en maybe.

if: 'als'. Als aan de voorwaarde die achter de if staat is voldaan. Die voorwaarde staat tussen haakjes. Alleen als aan die voorwaarde is voldaan, wordt de code na de { aan het eind van de regel uitgevoerd.

Als dat niet zo is, wordt met het volgende <source>-object verder gegaan (als er nog een volgend object is).

videoNodeList[i]: hierboven is de extensie van de video opgezocht en opgeslagen in de variabele extension. Hier wordt gekeken, of de browser een video met deze extensie kan afspelen. Dat kan worden opgezocht met een stukje code, dat de browser gratis en voor niks toevoegt aan elk <video>-object. Dat is handig, want je kunt dat gewoon gebruiken, zonder dat je code moet schrijven om het op te zoeken.

De extensie is opgezocht in het <source>-object, de controle of dit afspeelbaar is zit in het <video>-object, waar dit <source>-object bij hoort. i is een teller die bijhoudt, welke video wordt verwerkt. Met videoNodeList[i] wordt het juiste <video>-object aangesproken, het <video>-object dat hoort bij het <source>-object met de kleine video.

canPlayType: dit stukje code kan controleren, of de browser de video wel of niet kan afspelen. Omdat gelijk hiervoor, gescheiden door een punt, videoNodeList[i] staat, gaat het om het resultaat van deze controle bij het <video>-object dat bij videoNodeList[i] hoort.

("video/" + extension): dit is waar het hierboven genoemde canPlayType op controleert.

"video/": gewoon een stukje tekst, dat letterlijk zo wordt gebruikt.

+: het stukje tekst hiervoor en het stukje tekst hierachter worden achter elkaar gezet.

extension: in deze variabele is hierboven de extensie van de video opgeslagen. In het voorbeeld worden alleen webm‑ en mp4-video's gebruikt, dus dit is 'webm' of 'mp4'.

Als je het aan elkaar plakt, staat hier dus 'video/web' of 'video/mp4'.

("video/" + extension) !== "": hierboven is uitgevonden dat, in dit voorbeeld, "video/" + extension kan worden vervangen door 'video/webm' of 'video/mp4'. Als de gebruikte video 'video.webm' heet, kun je dit dus vervangen door "video/webm". De haakjes doen niet meer mee, want die stonden er voornamelijk voor de leesbaarheid voor mensen.

Je houdt dan over "video/webm" !== "".

Als het stukje code ervoor er weer even bij wordt gepakt, staat er dan:

canPlayType("video/webm" !== ""). Zoals hierboven beschreven, kan canPlayType twee antwoorden opleveren: "" (de browser kan de video niet afspelen) en maybe (de browser kan de video hoogstwaarschijnlijk afspelen).

!== wil zeggen, dat iets niet zo mag zijn. Het uitroepen keert de werking van de isgelijktekens om. Als canPlayType als antwoord níét "" geeft, móét het antwoord dus maybe zijn, iets anders kan niet. Als het antwoord niet "" is, kan de browser de video hoogstwaarschijnlijk afspelen. En wordt verder gegaan met het uitvoeren van de code achter de { aan het eind van de regel.

{: de code die wordt uitgevoerd, als aan deze if-voorwaarde wordt voldaan, is wat ingewikkelder. Daarom moet die code tussen accolades worden gezet. De browser weet dan, wat bij deze if hoort.

De hele regel nog eens in gewone mensentaal: vraag aan de browser, met behulp van de gevonden extensie, of de video afgespeeld kan worden. Als dat zo is, voer dan de rest van het script uit.

videoNodeList[i].src = sourceNodeList[j].src;

Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarden is voldaan:

– Er is minstens één <video>-element aanwezig in de html.

– Er is een geldige minimumbreedte opgegeven in het data-smscr-attribuut van het <video>-object dat wordt verwerkt.

– Het browservenster is smaller dan die opgegeven minimumbreedte.

data-smscr="small" is aanwezig in het <source>-object dat wordt verwerkt.

– Dit type video kan door de browser worden afgespeeld.

videoNodeList[i]: i is een teller, die bijhoudt welk <video>-object wordt verwerkt.

src: in src zitten pad naar en naam van de in de html in <video> opgegeven video. Voor de punt staat videoNodeList[i], daarom gaat het hier om de src van het <video>-object dat nu wordt verwerkt.

Er is in de html helemaal geen src opgegeven bij <video>, dus in dit geval is videoNodeList[i].src gewoon helemaal leeg. Maar niet lang meer.

=: in het stukje voor het isgelijkteken wordt opgeborgen, wat rechts van het isgelijkteken staat. Voor het isgelijkteken staat de src die bij het <video>-object hoort dat wordt verwerkt. Als daar iets in wordt gezet, is het resultaat dat het uiteindelijk in de html bij de bijbehorende <video> wordt gezet. Als de video 'video.webm' zou heten, is dit het resultaat:

<video src="video.webm">

sourceNodeList[j].src: j is een teller, die bijhoudt welk <source>-object wordt verwerkt. In src zitten pad naar en naam van de video, die bij dit <source>-object hoort. Het script komt alleen maar hier aan, als dit een kleine video is die afgespeeld kan worden.

In gewone mensentaal: zet in de html bij <video> een src, met in die src pad naar en naam van de af te spelen kleine video. Omdat deze video nu helemaal bovenaan staat, zal deze video worden afgespeeld. Want de browser gebruikt altijd de eerste video die afgespeeld kan worden.

In dit voorbeeld ligt de grens van het browservenster op 480 px: als het venster smaller is, wordt de kleine video afgespeeld. In zulke smalle vensters kun je de veranderde html bekijken door de gegenereerde code te bekijken. (Als je de gewone broncode bekijkt, zie je geen verschil.) Als je het venster verkleint in een desktopbrowser, moet je de pagina wel even opnieuw laden.

break;

Hier gelijk boven is in de html een kleine video ingevoegd om af te spelen. Één kleine video is genoeg, verder zoeken is niet nodig. Met break wordt aangegeven dat deze for-lus. kan worden verlaten. Dat is de for-lus, waarin de <source>-objecten worden bekeken. Daarbuiten zit nog de for-lus, waarin de <video>-objecten worden bekeken. Door het verlaten van die binnenste for-lus wordt verder gegaan met het volgende <video>-object, dat bij de volgende <video> op de pagina hoort, als dat er nog is.

Achteraan de regel staat weer de afsluitende puntkomma.