Art direction: browser beste afbeelding laten kiezen voor scherm en/of venster - uitleg

Skip links en inhoudsopgave

Laatst aangepast: .

Afbeelding 1: links volledige afbeelding in groter vensters, rechts in kleiner venster uitsnede in portret- en landschapsstand

Korte omschrijving

Er wordt, afhankelijk van oriëntatie, grootte en resolutiedichtheid van browservenster en/of scherm, gekozen uit verschillende afbeeldingen, waarvan de grootte aan het venster wordt aangepast.

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 drie 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.

* Het kan zijn dat materiaal is gebruikt dat van anderen afkomstig is. Dat materiaal kan onder een bepaalde licentie vallen, waardoor het mogelijk niet onbeperkt gebruikt mag worden. Als dat zo is, wordt dat vermeld onder Inhoud van de download en licenties.

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

Achterliggend idee

Vroeger, toen het leven nog mooi en simpel en lieflijk was – vraag maar aan 'n ouder iemand hoe de tandarts vroeger voor kinderen was...–, hadden beeldschermen allemaal ongeveer dezelfde maat. In die Heerlijke Oude Wereld droegen kinderen ook allemaal ongeveer dezelfde saaie kleding, dus dat klopte wel.

Goed, ik begin opnieuw, want ik dwaal misschien 'n tikkeltje af.

Tot 'n paar jaar geleden waren alle beeldschermen ongeveer even groot. De eerste computers hadden schermen van 800 x 600 px, of nog kleiner (en geen kleuren). Geleidelijk aan werden beeldschermen groter en groter. Maar als je 'n site maakte voor 'n scherm van ongeveer 1000 px breed, zat je meestal wel ongeveer goed.

Tegenwoordig heb je beeldschermen in de wildste maten, van minieme smartphones tot joekels van breedbeeldschermen. Dat betekent dat een site zich moet aanpassen aan de breedte van het scherm. Of eigenlijk: aan de breedte van het venster van de browser. Op mobiele apparaten zal dat venster meestal even breed zijn als het scherm, maar zeker bij bredere beeldschermen hoeft dat niet zo te zijn.

Tegelijkertijd heb je hogeresolutieschermen gekregen. Op deze schermen zitten de pixels, de beeldpunten waar alles mee wordt weergegeven, dichter bij elkaar dan op oudere schermen: ze hebben een hogere resolutiedichtheid. Dat levert een (veel) betere kwaliteit weergave op.

Bij een bepaald soort afbeeldingen levert dit (grote) problemen op. Bitmap-afbeeldingen (ook wel raster-afbeeldingen genoemd) waren afgestemd op oudere beeldschermen. De meest gebruikte bitmap-afbeeldingen hebben het jpg‑, gif‑ of png-formaat. Voor elke pixel op het scherm was apart informatie aanwezig in de afbeelding.

Als je 'n groter scherm of 'n hogeresolutiescherm hebt, met meer pixels, is er stomweg te weinig informatie in de afbeelding aanwezig om de afbeelding in een (heel) goede kwaliteit weer te geven.

Tot voor kort kon dit niet of heel moeilijk worden opgelost, omdat het uiterst ingewikkeld was om naar een kleiner scherm of browservenster een kleinere afbeelding te sturen. Met de komst van html5 (of eigenlijk nog iets later, in de vorm van een aanvulling), kan dit relatief simpel met alleen html worden geregeld.

Het is zelfs mogelijk om naar een kleiner scherm of browservenster een andere afbeelding te sturen dan naar een groter scherm of venster. Dat heet 'art direction', waar helaas geen Nederlandse vertaling voor bestaat.

Het meer theoretische verhaal over resolutie, beeldschermen, afbeeldingen, en dergelijke wordt gelijk hieronder veel uitgebreider beschreven. De technische werking is te vinden bij <picture> en verder.

De voorvoegsels -moz-, -ms- en -webkit-

Voordat een nieuwe css-eigenschap wordt ingevoerd, is er in de regel een experimentele fase. Browsers passen het dan al toe, maar met een aangepaste naam. Tijdens deze fase kunnen problemen worden opgelost en worden veldslagen uitgevochten, over hoe de standaard precies moet worden toegepast.

Als iedereen het overal over eens is en alle problemen zijn opgelost, wordt de officiële naam uit de standaard gebruikt.

De belangrijkste browsers hebben elk een eigen voorvoegsel:

Firefox: -moz-, naar de maker: Mozilla.

Op webkit gebaseerde browsers, zoals Google Chrome, Opera, Safari en Android browser: -webkit-.

(Google Chrome is van webkit overgestapt op een eigen weergave-machine: blink. Blink gaat geen voorvoegsels gebruiken. Het is echter een aftakking van webkit, dus het zal nog wel even duren voor -webkit- hier helemaal uit is verdwenen. Ook Opera gebruikt blink.)

Internet Explorer: -ms-, naar de maker: Microsoft. (Edge gebruikt geen voorvoegsels, maar vanwege compatibiliteit met oudere sites kunnen er nog wat aanwezig zijn.)

In dit voorbeeld worden transform en user-select gebruikt.

Zodra de experimentele fase voorbij is, wordt het voorvoegsel weggelaten. Omdat dat moment niet bij alle browsers hetzelfde is, zet je nu ook al de officiële naam erbij. Deze wordt als laatste opgegeven. Bijvoorbeeld Android browser herkent -webkit-linear-gradient. Zodra Android browser linear-gradient gaat herkennen, zal dit -webkit-linear-gradient overrulen, omdat het er later in staat. Dat ze er beide in staan, is dus geen enkel probleem.

transform

Op dit moment moet je nog het volgende schrijven:

{-webkit-transform: ...; transform: ...;}

In de toekomst kun je volstaan met:

{transform: ...;}

user-select

Op dit moment moet je nog het volgende schrijven:

{-moz-user-select: ...; -ms-user-select: ...; -webkit-user-select: ...; user-select: ...;}

In de toekomst kun je volstaan met:

{user-select: ...;}

Inmiddels is de algemene mening dat 'vendor prefixes', zoals deze voorvoegsels in het Engels heten, geen groot succes zijn. Eén van de grootste problemen: veel sitemakers gebruiken alleen de -webkit-variant. Daar kwamen ze in het verleden nog mee weg, omdat Apple op mobiel zo'n beetje 'n monopolie had. Inmiddels is dat niet meer zo, maar deze gewoonte bestaat nog steeds. Waardoor 'n site alleen in op webkit georiënteerde browsers goed is te bekijken.

Dit is zo'n groot probleem dat andere browsers soms de variant met -webkit- ook maar zijn gaan implementeren, naast de standaard. Want als 'n site het niet goed doet in 'n bepaalde browser, krijgt in de regel niet de site maar de browser de schuld.

Vanwege alle problemen met 'vendor prefixes' worden deze door steeds meer browsers niet meer gebruikt. Nieuwe, experimentele css-eigenschappen zitten inmiddels in bijvoorbeeld Firefox, Google Chrome en Safari achter een zogenaamde vlag: de gebruiker moet iets veranderen in de instellingen, waarna de eigenschap gebruikt (en getest) kan worden. Als alles werkt, zoals het hoort te werken, schakelt de browsermaker de vlag standaard in.

Voorlopig zijn we echter nog niet van deze voorvoegsels af. Als je ze gebruikt, gebruik dan álle varianten, en eindig met de variant zonder voorvoegsel, zoals die uiteindelijk ooit gebruikt gaat worden. Als je alleen de -webkit-variant gebruikt, ben je in feite 'n onbetaalde reclamemaker voor Apple.

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 <header> en <main> 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.

<header>

Bedoeld om een header in te zetten.

Een <header> mag vaker op één pagina worden gebruikt. De <header> hoort altijd bij het element, waar de <header> in staat. In dit voorbeeld wordt maar één <header> gebruikt, waarvan de ouder <body> is. Die <header> is dus de <header> voor <body>, voor de hele pagina.

<main>

Hierbinnen staat de belangrijkste inhoud van de pagina (in dit voorbeeld is dat de afbeelding met onderschrift en dergelijke).

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 een <header> ziet dat er zo uit:

<header role="banner">

en voor <main>:

<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 worden in dit voorbeeld twee WAI-ARIA-codes gebruikt: aria-hidden en aria-haspopup.

aria-hidden

Met behulp van aria-hidden="true" kan een deel van de code worden verborgen voor schermlezers en dergelijke, zodat dit niet wordt voorgelezen. Op de normale weergave op het scherm heeft dit verder geen enkele invloed.

Onder het vraagteken linksboven zit een korte uitleg. Deze is verborgen, omdat anders in kleinere browservensters het grootste deel van de afbeelding hierachter weg zou vallen. En het gaat juist om de afbeelding. Pas na aanraken of ‑klikken van het vraagteken wordt de uitleg zichtbaar.

De uitleg wordt verborgen door deze links buiten het scherm te positioneren. Voor schermlezers maakt dat echter niets uit, die lezen de uitleg gewoon voor. Als de uitleg zou worden verborgen met display: none; of visibility: hidden; zouden schermlezers het niet voorlezen, maar een absolute positie buiten het scherm is geen enkel probleem.

Omdat het toch wordt voorgelezen en de <span> met het vraagteken alleen maar verwarrend is, wordt de hele <span> met vraagteken en al met aria-hidden verborgen:

<span id="uitleg" aria-hidden="true" aria-haspopup="true">?</span>

Voor gebruikers van de Tab-toets is een extra <input> aangebracht, omdat die anders de uitleg nooit zouden kunnen openen. Ook dit is overbodig voor schermlezers en schept alleen maar verwarring, dus ook dit wordt verborgen met aria-hidden:

<input id="voor-tab" aria-hidden="true">

aria-haspopup

In de hierboven al genoemde <span> met het vraagteken staat nog een andere WAI-ARIA-code: aria-haspopup:

<span id="uitleg" aria-hidden="true" aria-haspopup="true">?</span>

In Internet Explorer 11 en Edge op touchscreens opent de pop-up bij aanraking niet. Of hij opent pas na een hele tijd. Of het contextuele menu wordt geopend. 'n Soort loterij. Kortom: enorme kommer en kwel. Door het toevoegen van aria-haspopup="true" opent de pop-up gewoon.

Volgens de specificatie kan met aria-haspopup="true" worden aangegeven dat het element een contextueel menu of een submenu heeft. Microsoft gebruikt dit attribuut dus voor iets, waar het niet voor is bedoeld.

Mogelijk wordt in de toekomst de specificatie aangepast, zodat dit attribuut in de toekomst niet alleen meer voor menu's is bedoeld. Dan zou dit problemen kunnen gaan opleveren.

Omdat in dezelfde <span> echter ook aria-hidden="true" staat, wordt de hele <span> gelukkig genegeerd door schermlezers.

Tabindex

Links, invoervelden in formulieren, en dergelijke kunnen met behulp van de Tab-toets (of een soortgelijke toets) één voor één worden bezocht, in de volgorde waarin ze in de html voorkomen. Shift+Tab-toets keert de volgorde van de Tab-toets om. Dit is een belangrijk hulpmiddel voor mensen die om een of andere reden de muis niet kunnen of willen gebruiken. (En het is vaak ook veel sneller dan de muis, vooral in formulieren.)

In sommige browsers en/of besturingssystemen is dit vreemd genoeg standaard uitgeschakeld en is een zoektocht in de instellingen nodig om dit aan te zetten. Maar gebruikers van de Tab-toets zullen dit al hebben gedaan.

Als je met behulp van de Tab-toets een element hebt bereikt, heeft dit 'focus': als het een link is en je drukt op Enter, wordt de link gevolgd. Bij een tekstveld kun je tekst gaan invoeren. Enz.

De Tab-toets volgt normaal genomen de volgorde van de elementen in de html. Het maakt niet uit, in welke volgorde ze op het scherm staan. Als je met behulp van css de elementen van plaats verwisselt op het scherm, wordt toch gewoon de volgorde in de html gevolgd.

De volgorde van de Tab-toets kan worden veranderd met behulp van het tabindex-attribuut: <div tabindex="3">. Deze <div> zal nu als derde worden bezocht, ook al krijgt een simpele <div> normaal genomen nooit bezoek van de Tab-toets.

Normaal genomen is het gebruik van een tabindex niet nodig. Het is zeker niet bedoeld om de bezoeker als een kangoeroe op een hindernisbaan van onder via links over rechts naar boven te laten springen. Maar soms kan het handig zijn voor kleinere correcties, als de normale volgorde in de html niet optimaal is. Of om een element bereikbaar te maken voor de Tab-toets, zoals de hierboven genoemde <div>.

Schermlezers blijven altijd de volgorde van de html volgen, dus als de tabindex sterk afwijkt van de volgorde in de html, kan dat behoorlijk verwarrend zijn.

De tabindex kan drie verschillende waarden hebben: -1, 0 of een positief getal.

In principe is de volgorde bij gebruik van de Tab-toets als volgt: eerst worden alle positieve getallen in volgorde afgewerkt. Als twee tabindexen dezelfde waarde hebben, wordt de volgorde in de html aangehouden. Een waarde van '0' wordt, afhankelijk van browser en besturingssysteem, verschillend behandeld, waarover iets hieronder bij Tabindex="0" meer.

tabindex="-1"

Een negatieve waarde van -1 zorgt ervoor dat het element volledig wordt genegeerd door de Tab-toets. Zelfs een link met een negatieve tabindex wordt volledig genegeerd. Normaal genomen heeft een tabindex="-1" maar één nut: je kunt dan met behulp van JavaScript toch focus aan het element geven, zonder dat gebruikers van de Tab-toets erdoor worden gehinderd.

In dit voorbeeld wordt tabindex="-1" niet gebruikt.

tabindex="0"

Volgens de specificatie van html 4.01 moest een tabindex="0" pas worden bezocht, nadat tabindexen met een positief nummer waren bezocht. Sommige browsers hielden zich hier echter niet aan: een tabindex="0" werd gewoon tussen de positieve tabindexen gezet.

In html5 is de situatie nog fijner. Nu staat er alleen dat, wat betreft de volgorde, de gewoonte van het platform wordt gevolgd. Oftewel: doe maar raak. Maar hoe dan ook: als je tabindex="0" gebruikt, kan een element focus krijgen met behulp van de Tab-toets. Ook als dat element normaal genomen geen focus kan krijgen.

Deze waarde wordt in dit voorbeeld niet gebruikt.

tabindex="..."

Op de plaats van de puntjes moet een positief getal worden ingevuld: het volgnummer. Positieve tabindexen worden in dit voorbeeld niet gebruikt.

Door aanraken of ‑klikken van of hoveren over het vraagteken linksboven, opent een korte uitleg over de afbeelding. Het vraagteken zit in een <span>, en een <span> wordt genegeerd door de Tab-toets. Dit betekent dat gebruikers van de Tab-toets de uitleg nooit te zien krijgen.

Je zou, zoals hierboven beschreven, aan de <span> tabindex="0" kunnen toevoegen, zodat de Tab-toets de <span> toch bezoekt. Maar dat geeft problemen op iOS, omdat de uitleg daar dan weer heel lastig is te sluiten zonder extra JavaScript.

Het is in dit geval het gemakkelijkst om een <input> aan te brengen, speciaal voor gebruikers van de Tab-toets. Een <input> wordt wel bezocht door de Tab-toets en kan dus focus krijgen. Als de <input> focus heeft, kun je de uitleg zichtbaar maken. Door het nog 'n keer indrukken van de Tab-toets verliest de <input> de focus weer en sluit de uitleg.

Om de problemen op iOS te voorkomen, wordt de <input> ver links buiten het scherm gepositioneerd. Dat maakt voor de werking van de Tab-toets niets uit. En problemen op iOS geeft het nu ook niet, omdat de <input> buiten het scherm staat en dus helemaal niet aangeraakt kan worden.

Muis, toetsenbord, touchpad en touchscreen

In dit voorbeeld gaat dit hoofdstukje alleen over het hulpschermpje dat wordt geopend bij aanraken of ‑klikken van of hoveren over het vraagteken. Het heeft op geen enkele manier betrekking op de afbeeldingen, dus als het je alleen om de afbeeldingen gaat, kun je dit overslaan.

Vroeger, toen het leven nog mooi was en alles beter, waren er alleen monitors. Omdat kinderen daar niet af konden blijven met hun tengels, besloten fabrikanten dan maar touchscreens te gaan maken, omdat je die mag aanraken. Het bleek makkelijker te zijn om volwassenen ook te leren hoe je 'n scherm vies maakt, dan om kinderen te leren met hun vingers van de monitor af te blijven.

Zo ontstonden touchscreens en kreeg het begrip ellende een geheel nieuwe lading. In de perfecte wereld van vroeger, waarin alleen desktops bestonden, werkten dingen als hoveren, klikken en slepen gewoon. Zonder dat je eerst 'n cursus hogere magie op Zweinstein hoefde te volgen. Zelfs in JavaScript was het nog wel te behappen, ook voor mensen zoals ik die toevallig niet Einstein heten.

Op dit moment kun je computerschermen ruwweg in twee soorten indelen: schermen die worden aangeraakt, en schermen die worden bediend met hulpmiddelen als een toetsenbord, muis of touchpad. Omdat ook computerschermen zich kennelijk vermengen, bestaan er inmiddels ook schermen die zowel van aanraken als van muizen houden.

Hieronder staat een lijstje met dingen die zijn aangepast voor de verschillende soorten schermen, zodat dit voorbeeld overal werkt.

:hover

Omdat :hover mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :hover tonen.

Je hovert over een element, als je met behulp van muis of touchpad de cursor boven dat element brengt. Hoveren kan over álle elementen. Het wordt veel gebruikt om iets van uiterlijk te laten veranderen, een pop-up te laten verschijnen, en dergelijke.

Bij gebruik van een muis zit er een verschil tussen hoveren en klikken, maar op een touchscreen is dat verschil er niet: je raakt een touchscreen aan of niet. Dit levert problemen op in iOS en in Internet Explorer en Edge op een touchscreen.

Op iOS opent de pop-up met de uitleg alleen in Firefox en Opera Mini. Om de pop-up te laten openen en sluiten in de andere browsers is een klein stukje JavaScript nodig.

In Internet Explorer 11 en Edge op touchscreens opent de pop-up bij aanraking niet. Of hij opent pas na een hele tijd. Of het contextuele menu wordt geopend. Door het toevoegen van aria-haspopup = "true" aan de <span> met het vraagteken, opent de pop-up vlotjes. Meer hierover is te vinden bij WAI-ARIA-codes.

:focus

Omdat :focus mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :focus tonen.

De meeste mensen gaan met een muis naar een link, invoerveld, en dergelijke. Waarna ze vervolgens klikken om de link te volgen, tekst in te voeren, of wat ze ook maar willen doen. De link, het invoerveld, en dergelijke heeft 'focus'.

Er is echter 'n tweede manier om naar links, invoervelden, en dergelijke te gaan: met behulp van de Tab-toets (sommige browsers gebruiken andere toetsen, maar het principe is hetzelfde). Met behulp van de Tab-toets kun je naar links, invoervelden, en dergelijke 'springen'. (Over het gebruik van de Tab-toets staat meer bij Tabindex.)

De <span> met het vraagteken wordt genegeerd door de Tab-toets, want het is geen link, tekstveld, of zoiets. Daardoor zouden gebruikers van de Tab-toets de pop-up met de uitleg nooit kunnen zien. Je zou aan span#uitleg het attribuut tabindex="0" kunnen toevoegen, want dan doet de Tab-toets de <span> wel aan.

Maar span#uitleg reageert ook op hoveren, en een combinatie van :hover en :focus levert op iOS problemen op, die dan weer moeten worden opgelost. Daarom is het het simpelste om voor gebruikers van de Tab-toets een eigen <input> buiten het scherm neer te zetten. Daarmee voorkom je de problemen op iOS gewoon. Meer over deze <input> is te vinden bij <input id="voor-tab" aria-hidden="true">.

Resolutie en afbeeldingen

Het verhaal hieronder is een stuk simpeler, dan het in werkelijkheid is. Dat heeft twee redenen: het moet niet te ingewikkeld worden, en schrijver dezes is geen expert op het gebied van afbeeldingen. Dingen als (lossless) comprimeren, anti-aliasing en subpixels bijvoorbeeld, worden buiten beschouwing gelaten. Kennis daarvan is ook niet echt nodig voor dit voorbeeld.

In dit voorbeeld wordt 'venster', 'browservenster' of 'venster van de browser' gebruikt. Veel mensen noemen dit bij een mobiel apparaat gewoon 'scherm'. Op een mobiel apparaat is het venster inderdaad meestal even groot als het scherm, maar op de desktop is dat vaak niet het geval. Hier wordt daarom altijd de term 'venster' (of 'browservenster' of 'venster van de browser' gebruikt), als het venster wordt bedoeld. 'Scherm' of 'beeldscherm' wordt gebruikt, als het fysieke scherm (wat je aan kunt raken) wordt bedoeld.

De afbeeldingen die op websites worden gebruikt, zijn in twee grote groepen te verdelen: vector en bitmap. Bitmap wordt ook wel raster genoemd. Een veel gebruikt formaat van een vector-afbeelding is SVG. Veel gebruikte bitmap-formaten zijn jpg, gif en png. Elke van deze formaten heeft z'n eigen voor‑ en nadelen.

Bij een vector-afbeelding is er eigenlijk helemaal geen afbeelding. Er zijn alleen allerlei formules aanwezig, zoals 'trek een rode lijn van dit punt naar dat punt' of 'teken een cirkel met een doorsnede van zoveel, een rode achtergrondkleur en een zwarte rand'. Daarom zijn vector-afbeelding heel geschikt voor dingen als logo's, waarin vaak voornamelijk lijnen en vlakken worden gebruikt. Lijnen, vlakken, en dergelijke zijn goed met formules te beschrijven.

Voor foto's is een vector-afbeelding meestal niet het meest geschikt, omdat foto's meestal niet voornamelijk uit lijnen en vlakken bestaan. Een menselijk gezicht zou je kunnen beschrijven met formules, maar dan zou je waanzinnig veel formules nodig hebben om alle kleurnuances, rimpels, elke wenkbrauwhaar, noem maar op, te omschrijven.

Voor foto's is daarom een bitmap-afbeelding meestal geschikter. Een gif-afbeelding kan maar maximaal 256 kleuren bevatten en is daarom meestal ook niet geschikt voor een foto. Blijven over png en jpg (naast nieuwere formaten als WebP, dat nog onvoldoende door browsers wordt ondersteund). png heeft een aantal voordelen boven jpg, maar daardoor zijn de bestanden meestal (veel) groter dan jpg. En omdat elke afbeelding moet worden gedownload, wordt meestal jpg gebruikt. Ook in dit voorbeeld worden jpg-bestanden gebruikt. (Vanaf nu wordt de term 'bitmap-bestanden' of kortweg 'bitmap' gebruikt, omdat het hele verhaal niet alleen voor jpg, maar voor alle bitmap-bestanden geldt.)

Een vector-bestand kan uitstekend worden vergroot of verkleind. Dat is een van de grootste voordelen van zo'n bestand. Als 'n formule 'n cirkel van 100 px doorsnede laat verschijnen, hoef je alleen maar 100 in 200 te veranderen en de cirkel is, zonder enig kwaliteitsverlies, twee keer zo groot.

Een bitmap-afbeelding is fundamenteel anders opgebouwd. Hierdoor is het vrijwel onmogelijk een bitmap te vergroten, zonder dat dat tot (groot) kwaliteitsverlies leidt. Als een bitmap op een hogeresolutiescherm wordt weergegeven, is dat enigszins vergelijkbaar met wat er gebeurt, als een bitmap-afbeelding wordt vergroot. Vandaar dat in dit verhaal vergroten en hogeresolutieschermen enigszins door elkaar heen lopen.

Afbeelding 2: foto van wesp met veel kleine details

Ook een bitmap-afbeelding is in feite helemaal geen echte afbeelding. Wat voor het oog mooie, in elkaar overlopende kleuren en soepele rondingen zijn, bestaat in feite helemaal niet. In werkelijkheid bestaat de afbeelding uit kleine blokjes, die alleen maar zo soepel en vloeiend zijn, omdat mensenogen makkelijk voor de gek zijn te houden.

Op de afbeelding hiernaast staat een wesp. Omdat op deze foto kleine details aanwezig, zijn, is deze uitstekend geschikt om bij dit verhaal als illustratie te gebruiken.

Hieronder staat een stukje van een detail van de bovenste vleugel van de wesp, vijftien keer vergroot. Dat mooie ronde adertje (of hoe dat ook heet bij 'n insect) blijkt opgebouwd te zijn uit 'n verzameling rotsblokken, waar Stonehenge nog iets van kan leren.

Afbeelding 3: foto van wesp sterk vergroot

Maar als je de foto niet vergroot, ziet het er op een beeldscherm prima uit. Omdat mensenogen gewoon niet zo goed zijn. Mensen zien de afzonderlijke blokjes niet, als die maar klein genoeg zijn.

Omdat een bitmap is opgebouwd uit losse blokjes, is vergroten een probleem. Bij een vector-afbeelding bouwt de browser de afbeelding op aan de hand van de formules. Als de grootte verandert, verandert de formule en maakt de browser gewoon 'n andere, nieuwe afbeelding, zonder kwaliteitsverlies.

Bij een bitmap-afbeelding kan dit niet. Als je 'n bitmap-afbeelding vergroot, worden in feite de afzonderlijke blokjes vergroot. Als je maar ver genoeg vergroot, zoals op de afbeelding hierboven is gebeurd, ga je die blokjes zien.

De blokjes in een bitmap-afbeelding worden pixel genoemd, met als afkorting px. Elke pixel in een bitmap is opgebouwd uit drie kleuren: rood, groen en blauw. Elk van die drie kleuren kan 256 mogelijke waarden hebben: van volledig ontbrekend tot volledig aanwezig (knalrood bijvoorbeeld). Samen kunnen deze drie kleuren op 256 x 256 x 256 = 16.777.216 manieren worden gecombineerd. Dat levert 16.777.216 mogelijke kleuren op, ruim voldoende voor het menselijk oog. Van volledig wit (drie keer nul) tot volledig zwart (drie keer 255. 255, want een computer begint meestal bij nul te tellen).

Voor elke pixel in de afbeelding zijn drie bytes nodig: eentje voor elke kleur. Een afbeelding van 100 x 100 px heeft daardoor een bestandsgrootte van 3 x 100 x 100 = 30.000 byte, oftewel 30 kB (kilobyte). Soms is dat nog wat meer, omdat sommige soorten bitmap-afbeeldingen ook nog een waarde voor de doorzichtigheid van de pixel hebben.

Een afbeelding van 200 x 200 px, twee keer zo breed en hoog als een afbeelding van 100 x 100 px, heeft een bestandsgrootte van 3 x 200 x 200 = 120.000 byte, 120 kB. Dat is vier keer zoveel als de afbeelding van 100 x 100 px, want niet alleen de breedte verdubbelt, maar ook de hoogte.

(Als iemand dit nou gaat narekenen met twee afbeeldingen, dan blijkt bovenstaande berekening niet te kloppen. Door slimme compressiemethoden is een bestand uiteindelijk (veel) kleiner, dan je zou verwachten. Ook de inhoud van de afbeelding heeft invloed. Grote vlakken bijvoorbeeld zijn veel beter te comprimeren dan iets met veel krullen.)

Bitmap-afbeeldingen zijn opgebouwd uit pixels. Beeldschermen zijn op een enigszins gelijke manier opgebouwd uit pixels. En elke schermpixel is weer opgebouwd uit een soort subpixel voor rood, groen en blauw. Er bestaat een gigantische spraakverwarring over wat de juiste namen voor deze onderdelen zijn. De een noemt een subpixel een dot, en de ander noemt een dot een pixel. Gelukkig maakt dat voor het verhaal hier weinig uit.

De grootte van een beeldscherm, de resolutie, wordt normaal genomen in pixels opgegeven, net zoals bij een afbeelding. Een beeldscherm van 1280 x 1024 px is 1280 pixel breed en 1024 pixel hoog.

Een pixel kan groot of klein zijn. Van oudsher wordt de grootte van pixels, de resolutiedichtheid, uitgedrukt in dpi: dots per inch. Waarbij het in de eenheid dpi gebruikte 'dot' dus eigenlijk hetzelfde is als een pixel. Of dat nou helemaal juist is of niet, voor wat betreft dit verhaal zijn dots en pixels bij beeldschermen hetzelfde.

Tot niet zolang geleden had elke monitor een dpi van 96: 96 dots per inch. Van oudsher wordt helaas 'inch' gebruikt. Voor de theorie maakt het niets uit, maar het is wat lastiger als je niet aan 'n inch gewend bent. Eén inch is ongeveer 2,5 centimeter.

Apple had een iets afwijkende dpi, maar omdat 96 dpi het vaakst voorkwam, is dat gebruikt om de grootte van de pixel in css, html, en dergelijke vast te stellen. Vanaf nu noem ik een beeldscherm met een dpi van 96 een 'standaard' beeldscherm.

1 px in css, html, en dergelijke is even groot als 1 dpi. In iets andere woorden: 1 px in css is even groot als 1 px op een standaard beeldscherm met een dpi van 96. De in de css, html, en dergelijke gebruikte pixel heet een 'css-pixel'. Als je 96 css-pixels naast elkaar zet, heb je een breedte van 1 inch. Net zoals op een standaard beeldscherm met 96 dpi: 96 dots per inch.

Als je nu een bitmap op een beeldscherm gaat weergeven, komt in elke pixel op het beeldscherm één pixel van de afbeelding te staan. En omdat je jarenlang alleen maar beeldschermen had met 96 dpi, waren alle afbeeldingen tot niet zolang geleden hierop afgestemd. Als je 'n afbeelding 2 inch breed wilde weergeven, had de afbeelding in de breedte niet meer dan 192 pixels nodig, want er zaten in die 2 inch op het beeldscherm ook maar 192 pixels.

Omdat elke pixel in de afbeelding 3 of 4 byte aan ruimte inneemt (om de hoeveelheid rood, groen en blauw en eventueel de doorzichtigheid in op te slaan), is het van belang afbeeldingen met zo weinig mogelijk pixels te hebben. Als een afbeelding twee inch breed moet worden en er zitten op het beeldscherm maar 192 pixels in die twee inch, heeft het geen nut 384 pixels te sturen. Daar maak je alleen het bestand maar groter mee, en de browser moet de helft van de pixels weggooien, omdat er te weinig pixels op het scherm zijn om alle pixels te kunnen gebruiken.

Omdat menselijke ogen niet zo goed zijn, zien afbeeldingen die met 96 dpi werden weergegeven er best nog wel goed uit. Maar echt heel fijne details kun je er niet mee weergeven, omdat de pixels gewoon te groot zijn. Een heel dun lijntje is dunner dan zo'n pixel, dus dat lijntje wordt of helemaal niet, of met een dikte van 1 px en dus te dik weergegeven.

Maar goed, het werkte, mensen waren nog niet zo verwend en iedereen was gelukkig en tevreden en leefde nog lang en gelukkig.

Tot Apple het nodig vond om met een hogeresolutiescherm te komen: een scherm waar de pixels dichter op elkaar staan dan 96 dpi. Apple noemt zo'n scherm 'Retina', maar dat is gewoon de merknaam van Apple voor een hogeresolutiescherm. Het verhaal hier geldt voor alle hogeresolutieschermen, welke naam de Afdeling Marketing er ook voor heeft bedacht.

Stel dat je een afbeelding hebt van 96 bij 96 px. Als die op een standaardscherm wordt weergegeven, wordt elke px van de afbeelding op een px van het scherm gezet. De afbeelding is op het scherm ook 96 bij 96 px. En omdat het scherm een resolutiedichtheid van 96 dpi heeft, 96 dots per inch, is de afbeelding op het scherm 1 x 1 inch. Omdat de afbeelding voor die grootte is gemaakt, is de afbeelding goed te zien.

Bij een hogeresolutiescherm zitten de pixels dichter op elkaar dan bij een standaard beeldscherm met 96 dpi. Zelfs meer dan vier keer zo dicht op elkaar is inmiddels geen uitzondering meer. Dat betekent dat er soms meer dan 384 pixels in elke inch zitten. Die pixels zijn uiteraard veel kleiner dan de pixels van 96 dpi, want er moeten er nu 384 naast elkaar in diezelfde ene inch passen.

Een van de voor het testen gebruikte iPads heeft een scherm met een resolutie, een grootte, van 2048 x 1536 px. Als die een dpi van 96 zou hebben, zou die 2048 gedeeld door 96 is meer dan 21 inch breed zijn, dat is meer dan 'n halve meter. Dat is geen tablet meer, dat is een slagwapen. Die tablet heeft dan ook geen dpi van 96, maar van 264, bijna drie keer zo hoog als die van een standaard beeldscherm. De dots zijn bijna negen keer zo klein als die op een standaard beeldscherm, waardoor de tablet hanteerbaar blijft. (Negen keer: drie keer in de breedte en drie keer in de hoogte.)

Maar nu ontstaat een probleem met de afbeelding van 96 x 96 px. Als elke pixel van de iPad één pixel van de afbeelding zou krijgen, worden nog steeds 96 px gebruikt. Maar omdat de pixels op de tablet bijna negen keer zo klein zijn, is de afbeelding nu opeens bijna negen keer zo klein. Bij een resolutiedichtheid van 384 dpi, vier keer zo hoog als van een standaard beeldscherm, is de afbeelding zestien keer zo klein. De afbeelding was goed zichtbaar bij een breedte van 1 inch, maar op een breedte (en hoogte) van 'n halve of 'n kwart inch heb je 'n vergrootglas nodig om 'n nog goed te kunnen bekijken.

Als een hogeresolutiescherm zo zou werken, zou elke bestaande website onbruikbaar worden, omdat alles veel te klein zou worden. Althans: bitmaps.

Vector-afbeeldingen zijn relatief makkelijk te vergroten, omdat je gewoon de formules kunt aanpassen.

Hogeresolutieschermen passen dezelfde truc toe bij bitmap-afbeeldingen: ze vergroten de afbeelding. Daarbij wordt ervan uitgegaan dat 96 px uit de afbeelding 1 inch breed moeten worden, net zoals op het standaard beeldscherm het geval was. Als de afbeelding 96 px breed is, en dus op een standaard beeldscherm 1 inch breed wordt weergegeven, wordt die op de iPad met een dpi van 264 ook 1 inch breed. Alleen worden daarvoor 264 pixels van het beeldscherm gebruikt.

De 'css-pixel' is een min of meer vaste maat. De pixels van het beeldscherm worden 'schermpixels' genoemd (in het Engels 'device pixel') en hebben geen vaste maat. Bij een standaard beeldscherm van 96 dpi zijn de schermpixels even groot als de css-pixels. Maar bij de iPad van hierboven zijn de schermpixels bijna negen keer zo klein als een css-pixel (drie keer in de breedte en drie keer in de hoogte).

Veel mensen moeten erg wennen aan het verschil tussen css-pixels en schermpixels. Je zou het ook zo kunnen zien: css-pixels, de pixels die in css, html, en dergelijke worden gebruikt, zijn 'n soort vaste maat, net als een centimeter. Schermpixels zijn de pixels, waarvoor je hebt betaald. Het scherm is in css-pixels even groot als een standaard beeldscherm van dezelfde maat, maar hoe duurder het is, hoe meer schermpixels er meestal in zitten. (Als dat niet zo is, ben je mogelijk genept...)

Door het splitsen in css-pixels en schermpixels wordt voorkomen dat alle bitmaps onbruikbaar klein worden. Maar dit brengt weer een nieuw probleem met zich mee.

Bij 264 dpi zijn er bijna negen schermpixels voor elke pixel uit de afbeelding. Voor acht van de negen schermpixels is er dus geen informatie over kleur en eventuele doorzichtigheid. De browser lost dit op door de ontbrekende pixels zelf in te vullen. Dat is voor een behoorlijk deel raadwerk.

Er zit wel énige intelligentie in dit toevoegen van pixels. Tot op zekere hoogte kan de browser 'raden' wat een kleur moet zijn en zelf missende pixels invullen, bijvoorbeeld bij een geleidelijke overgang tussen twee kleuren. Maar hier zijn grenzen aan. Gespecialiseerde grafische programma's kunnen dit meestal (veel) beter dan een algemeen programma als een browser, maar ook die zijn niet perfect als het om het vergroten van een bitmap-afbeelding gaat.

De enige afdoende oplossing is het sturen van een grotere afbeelding naar een hogeresolutiescherm. Een afbeelding die op de iPad met 264 dpi, 264 dots per inch, 1 inch breed moet worden, moet 264 pixel breed zijn. En op een tablet met 384 dpi moet diezelfde afbeelding 384 px breed zijn. Dan is er voor elke schermpixel een eigen pixel uit de afbeelding beschikbaar.

Dit heeft nog een bijkomend voordeel. Als de schermpixels kleiner zijn, kunnen (veel) kleinere details worden weergegeven.

Afbeelding 4: foto van wesp in lage en hoge resolutie

Op de afbeelding hiernaast is weer een stukje vleugel van de wesp te zien. Het enige verschil tussen de afbeeldingen is de afmeting. De linkerafbeelding is 200 px breed, de rechterafbeelding is 400 px breed, maar is versmald tot 200 px. Er zijn nog steeds 400 px aanwezig in de rechterafbeelding, maar ze zijn twee keer zo klein gemaakt. Met andere woorden 96 dpi is veranderd in 192 dpi.

(Dit verhaal klopt niet helemaal, omdat het verschil tussen beide afbeeldingen ook op niet-hogeresolutieschermen te zien moet zijn. Daarom zijn beide afbeelding niet precies even groot. Nou ja, kuch, ook mede omdat er aan mij geen groot grafisch talent verloren is gegaan...)

Het verschil in kwaliteit is duidelijk zichtbaar: op de linkerafbeelding zijn de fijnere lijntjes binnen de vleugel stomweg afwezig. En wat niet aanwezig is, kan ook niet worden weergegeven door de browser, ook al doet deze nog zo haar best. Als het hogeresolutiescherm de linkerafbeelding zou weergeven, missen de lijntjes uit de vleugel daar ook. Een browser is geen entomoloog, dus die lijntjes kan de browser er niet zelf bij fantaseren.

Voor een 'gewoon' beeldscherm is de kwaliteit van de linkerafbeelding goed genoeg, want dat beeldscherm is toch niet in staat de fijne lijntjes weer te geven. Daar zijn de pixels te grof voor. Maar omdat menselijke ogen zo makkelijk te misleiden zijn, ziet het er toch nog redelijk goed uit.

Een hogeresolutiescherm, met z'n (veel) kleinere schermpixels, kan echter wel de fijne lijntjes uit de vleugel weergeven. Als de rechterafbeelding naar een hogeresolutiescherm wordt gestuurd, worden de lijntjes in de vleugel wel weergegeven. Er zitten genoeg pixels, genoeg informatie, in de afbeelding.

Bijkomend voordeel is dat de afbeelding bij vergroten niet zo snel blokkerig wordt, omdat het langer duurt voor de afzonderlijke pixels te zien zijn.

(Op papier is je oog trouwens minder goed voor de gek te houden, daarom zijn voor een afdruk ruwweg vier keer zoveel pixel nodig voor een enigszins acceptabele kwaliteit, als op een standaard beeldscherm. Daardoor zijn veel afbeeldingen op internet eigenlijk niet af te drukken: ze bevatten gewoon te weinig pixels voor een kwalitatief acceptabele papieren afdruk.)

Dat is dus opgelost: gewoon een grote afbeelding met lekker veel pixels gebruiken.

Maar helaas, daar maak je je niet populair mee. Als je zeker wilt weten dat de bitmap op élk scherm goed wordt weergegeven, moet je een afbeelding gebruiken die geschikt is voor een hogeresolutie-breedbeeldscherm met een breedte van 2500px of zo. Maar die afbeelding wordt dan ook naar dat goedkope mobieltje met z'n schermpje van 320 px breed en 'n dpi van 120 gestuurd. Voor die afbeelding is gedownload, heeft de gebruiker van dat mobieltje z'n ochtendgymnastiek gedaan, ontbeten en de hond uitgelaten. En als de gebruiker voor de bandbreedte moet betalen, is er 'n reëel gevaar voor spontaan volksoproer.

Kortom: dat is geen oplossing.

In het verleden is deze methode trouwens wel redelijk vaak toegepast: stuur overal dezelfde grote afbeelding naartoe. Meestal was dat dan wel 'n soort compromis, waardoor het op 'n hogeresolutiescherm niet de beste kwaliteit was, maar nog wel te downloaden voor een smartphone. Maar ideaal was dit beslist niet, want met dit compromis had helemaal niemand meer echt de beste afbeelding.

Inmiddels wordt internet meer mobiel gebruikt dan via de desktop, met meestal (veel) kleinere schermen dan op de desktop. Mede daardoor is het volledig achterhaald om dit op 'op te lossen' door naar mobieltjes en dergelijke te grote afbeeldingen te sturen.

Ook werd wel gekozen voor gruwelijk ingewikkelde oplossingen, zoals het laten herkennen van het apparaat door de server, en aan de hand daarvan de juiste afbeelding sturen. Los van de ingewikkeldheid daarvan ging dit ook regelmatig gewoon mis, omdat lang niet elke browser correcte informatie over naam, versie, enz. verstuurt. Bovendien is het bijhouden van gegevens als resolutiedichtheid, resolutie grootte), enz. van duizenden apparaten ook nogal tijdrovend.

Grootte zeg je? Ja, dat is nog helemaal niet aan de orde gekomen.

Stel dat een afbeelding schermvullend moet worden weergeven op een scherm met een dpi van 96 en een breedte van 600 px. (We gaan er even vanuit, dat het browservenster even breed is als het scherm). In een perfecte wereld zou je daar een afbeelding met een breedte van 600 px naar sturen. Als het scherm 1200 px breed is, zou je 'n afbeelding van 1200 px breedte sturen. Het heeft geen nut om die afbeelding van 1200 px naar het scherm van 600 px te sturen, want op dat scherm kan de helft van de pixels niet worden gebruikt.

Nou zijn browsers relatief goed in het verwijderen van overbodige pixels (ze kunnen ook vrij goed verkleinen), maar er wordt wel 'n (veel) te groot bestand naar het kleinere scherm gestuurd.

Eigenlijk is dat hetzelfde probleem als bij de resolutiedichtheid: er moet een afbeelding met voldoende pixels, maar niet te veel, worden gebruikt.

In css3 kun je met behulp van media query's de breedte, hoogte, en nog veel meer van het browservenster en/of het scherm opvragen. Afhankelijk van breedte, hoogte, enz. kan dan de css worden aangepast voor dat bepaalde venster en/of scherm.

Die mogelijkheid is er met html5 ook specifiek voor afbeeldingen gekomen. Maar de oplossingen hieronder werken alleen, als in de <head> van de pagina <meta name="viewport" ... staat. Als dat niet zo is, wordt voor elke pixel van de afbeelding één schermpixel gebruikt en is er een grote kans dat de afbeelding veel te groot of veel te klein wordt weergegeven. Of de browser probeert er het beste van te maken, waarbij 'het beste' vaak niet hetzelfde is als 'goed'.

Met behulp van het attribuut srcset kan een aantal afbeeldingen worden opgegeven, waarvan alleen de breedte verschilt. Met het attribuut sizes kan worden opgegeven, hoe breed de afbeelding moet worden weergegeven. Daarbij kun je die weergavebreedte afhankelijk maken van breedte, hoogte, resolutiedichtheid, en dergelijke van het browservenster en/of het scherm.

De browser weet de grootte, resolutiedichtheid, en dergelijke van het scherm en het browservenster. In de html staan de afbeelding (met breedte) en hoe breed de afbeelding moet worden weergegeven. Nu heeft de browser voldoende informatie om een afbeelding te kiezen, die het best bij de grootte en resolutiedichtheid van scherm en venster past. Hoe srcset en sizes precies werken, is te vinden bij <source> algemeen.

Als je niet meer wilt dan grootte en resolutiedichtheid aanpassen aan scherm en browservenster, zijn srcset en sizes voldoende. Deze kunnen zelfs in een gewone <img> worden gebruikt. Browsers die srcset en sizes niet kennen, negeren dat en geven gewoon de <img> weer, zoals ze dat altijd al deden.

Als een grote afbeelding heel sterk wordt verkleind, kan de afbeelding te klein worden, om alles nog goed te kunnen zien. Dat is in dit voorbeeld ook het geval. Als de afbeelding in een mobieltje met een breedte van 320 px wordt weergegeven, is er nauwelijks nog wat van de zandkastelen te zien. Html5 heeft ook de mogelijkheid om, afhankelijk van grootte, hoogte, resolutiedichtheid, enz. een volledig andere afbeelding te sturen.

Dat gebeurt in dit voorbeeld ook. Browservensters die minder dan 601 px breed zijn, krijgen een uitsnede van de volledige afbeelding. Er zijn zelfs twee alternatieve afbeeldingen: eentje voor kleine vensters in landschapsstand, en eentje voor kleine vensters in portretstand. Het op deze manier gebruiken van verschillende afbeeldingen heet 'art direction'. (Een Nederlandse vertaling hiervan bestaat niet.)

Binnen het <picture>-element staan <source>'s. Er kan bijvoorbeeld een <source> zijn voor browservensters minimaal 600 px breed in portretstand. Als het venster daaraan voldoet, wordt die <source> gebruikt. Binnen die <source> kunnen dan weer een srcset en sizes staan met afbeeldingen in verschillende groottes voor heel kleine vensters, iets minder kleine vensters, enz. Hoe dit precies werkt, is te vinden bij <source> algemeen.

Deze oplossingen betekenen wel dat je meerdere afbeeldingen moet maken. Dat is niet zo heel veel werk, elk grafisch programma kan dat op een simpele manier doen. Je kunt het ook vrij makkelijk automatiseren, als je veel afbeeldingen moet vergroten of verkleinen.

Het is ook niet nodig om voor elke mogelijke grootte, resolutiedichtheid, en dergelijke een exact passende afbeelding te maken. De browser zal, als er geen precies passende afbeelding is, de eerstvolgende afbeelding gebruiken die (iets) groter is, dan nodig is. En omdat een browser el vrij goed kan verkleinen, werkt dat prima.

Er is ook niet veel extra rekenwerk nodig met ellendige getallen als 264dpi, omdat de browser berekent hoeveel schermpixels er nodig zijn om een bepaalde breedte in css-pixels te bereiken. Pixels kunnen dus op dezelfde manier als altijd in de css, html, en dergelijke blijven worden gebruikt. Dat geldt ook voor alle andere eenheden, want een browser werkt intern alleen met pixels.

picturefill.js

picturefill.js is een zogenaamde 'polyfill'. Een polyfill is een JavaScript dat het mogelijk maakt nieuwere html en css in oudere browsers te gebruiken. Dat klinkt mooi, maar er zitten wel wat nadelen aan.

Lang niet elke polyfill werkt goed. Een van de hele leuke en hele vervelende kanten van internet: iedereen kan alles erop zetten. Er zijn dan ook nogal wat polyfills die gewoon ronduit slecht werken, of de browser ongelooflijk traag maken, of die wel werken maar andere onderdelen van de pagina slopen. Op de site van Modernizr staat een groot aantal goed werkende polyfills.

Als je meerdere polyfills gebruikt, kan dat het laden van de pagina behoorlijk vertragen. Zeker als ze niet op de juiste manier aan de pagina worden gelinkt.

De in dit voorbeeld gebruikte elementen <picture> en <source> en de attributen srcset en sizes werken niet in UC browser op Windows Phone 8.1 en Android, Opera Mini op Android en alle versies van Internet Explorer 11. Hierdoor tonen deze browsers altijd de afbeelding die bij <img> staat: de volledige afbeelding die 1000 px breed is. Door het gebruiken van de polyfill 'picturefill.js' werken <picture>, <source>, srcset en sizes ook in deze browsers.

In UC browser op Android werkt deze polyfill soms wel en soms niet. Als de polyfill niet werkt, wordt de afbeelding uit <img> van 1000 px breed getoond. Dat dit script soms wel en soms niet werkt, kan ook liggen aan het gebruik van de eenheid vh in de eerste <source>, want dat kent de sukkel ook al niet. Omdat deze browser heel actief wordt bijgehouden, is de polyfill hopelijk snel niet meer nodig.

Onderin de <head> staat de volgende regel:

<script src="117-js/picturefill.min.js" async></script>

Deze regel koppelt het script aan de pagina.

Normaal genomen wordt de pagina pas weergegeven, als alle scripts zijn verwerkt. Soms bevat een script informatie, over hoe de pagina moet worden opgebouwd, en dat moet eerst bekend zijn. In dit geval hoeft de pagina niet te wachten tot het script is verwerkt. Daarom is het sleutelwoord async toegevoegd aan <script>: nu wacht de browser niet op dit script.

De naam van het script is 'picturefill.min.js', en geen 'picturefill.js'. Dit is een gebruikelijke manier om aan te geven dat het script is geminimaliseerd. Alle overbodige nieuwe regels, spaties, commentaar, enz. zijn eruit gehaald, zodat het zo klein mogelijk is. Als je dit script bekijkt, is het voor mensen een grote onbegrijpelijke chaos (tenzij je het met behulp van speciaal gereedschap netjes laat weergeven). Maar de browser heeft er geen moeite mee.

Dit script is in de download bijgesloten. Het is uiterst belangrijk dat dit script niet zonder meer wordt gebruikt. Dit soort scripts wordt voortdurend uitgebreid en er worden voortdurend bugs uitgehaald. Het in de download bijgesloten script is versie 3.0.2. Het is afkomstig van scottjehl.github.io/picturefill. Op die pagina kan ook worden gekeken, of dit de meest recente versie van dit script is.

Omdat deze polyfill rechtstreeks is overgenomen van genoemde pagina, is in deze uitleg verder niets te vinden over dit script. Als je wilt weten, hoe het precies werkt, kun je dat op de hierboven genoemde pagina van dit script vinden.

Testen of de juiste afbeelding wordt gebruikt

Het testen of de juiste afbeelding wordt geladen, kan wat lastig zijn.

Binnen elke <source> staat media met daarachter voorwaarden, waaraan het browservenster en/of het scherm moet voldoen. De voorwaarden binnen media zijn bindend: de browser móét een afbeelding gebruiken uit de srcset in de <source>, die bij het venster en/of het scherm past.

Binnen elke <source> staat binnen srcset een serie afbeeldingen, waarvan er dus één moet worden gebruikt. Welke afbeelding wordt gebruikt, wordt mede bepaald door wat bij sizes is opgegeven. Maar in tegenstelling tot media zijn srcset en sizes niet bindend: de browser mag hier van afwijken. Het zijn alleen hints.

Als op bijvoorbeeld een tablet niet de juiste afbeelding voor een bepaalde maat of pixeldichtheid van het browservenster wordt geladen, kan dat ook aan een slechte internetverbinding liggen. In dat geval werkt alles goed, terwijl er ogenschijnlijk iets misgaat. De browser kiest alleen, vanwege de slechte verbinding, voor een kleiner bestand.

Het testen van dit voorbeeld is daarom wat lastiger dan het testen van bijvoorbeeld een kleur: zwart is altijd zwart, en als het geen zwart is, gaat er iets mis. Maar een ogenschijnlijk te kleine afbeelding kan toch een correcte keuze van de browser zijn.

Dingen om op te letten:

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 30 januari 2017.

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, enzovoort 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.

Alle browsers

Bij aanpassing van het browservenster wordt soms geen nieuwe afbeelding geladen

Dat hoort zo. De opgegeven afbeeldingen binnen srcset zijn slechts hints voor de browser. De browser neemt de uiteindelijke beslissing. Dat verschilt ook nog eens per browser.

Als het browservenster bijvoorbeeld 1280 x 1024 px is en dan wordt verkleind naar 800 x 600 px, waarom zou er dan een nieuwe afbeelding geladen moeten worden? Die afbeelding van 1280 x 1024 px kan prima worden verkleind naar 800 x 600 px.

Hoe je kunt testen, of het werkt, is te vinden bij Testen of de juiste afbeelding wordt gebruikt.

De juiste afbeelding voor een bepaalde grootte en dergelijke van het browservenster wordt niet geladen.

Dat hoeft geen fout te zijn. De browser móét een afbeelding gebruiken uit de <source> die bij het scherm en/of browservenster past. Maar de binnen die <source> opgegeven afbeeldingen binnen srcset zijn slechts hints voor de browser. De browser neemt de uiteindelijke beslissing. Dat verschilt ook nog eens per browser. Als bijvoorbeeld eigenlijk de afbeelding van 2000 x 1500 px geladen zou moeten worden in een tablet, kan de browser toch een kleinere afbeelding laden, als de internetverbinding slecht is.

Hoe je kunt testen, of het werkt, is te vinden bij Testen of de juiste afbeelding wordt gebruikt.

Alle browsers in vensters smaller dan 601 px in landschapsstand

De afbeelding is hoger dan het browservenster

Dat is geen probleem, maar boosaardige opzet. Met andere media condities zou dit kunnen worden voorkomen op ongeveer dezelfde manier, zoals dit door de eerste <source> bij grotere vensters wordt voorkomen.

Als de afbeelding in portretstand wordt bekeken, is de volledige afbeelding te zien. Maar die is wel vrij klein, omdat het browservenster dan nogal smal is.

In landschapsstand is het browservenster breder, maar ook (veel) lager dan in portretstand. Als de afbeelding daarin passend wordt gemaakt, wordt deze heel erg laag. En dus ook heel erg smal (als je 'n lachspiegel-effect wilt voorkomen). Kortom: de afbeelding wordt wel héél erg klein.

Door in landschapsstand de volle breedte te gebruiken, is de afbeelding groter. Alleen moet dan wel worden gescrold om de hele afbeelding te kunnen zien.

In portretstand zie je de hele afbeelding, maar kleiner. In landschapsstand moet je scrollen, maar is de afbeelding groter. De bezoeker kan nu kiezen. Als de afbeelding altijd in z'n geheel zou zijn te zien, is slechts de keuze tussen klein en wanstaltig klein.

UC browser op Windows Phone 8.1 en Android, Opera Mini op Android en alle versies van Internet Explorer 11

Alleen de afbeelding uit <img> van 1000 px breed wordt getoond

Deze browsers kennen <picture> niet, maar <img> kennen ze wel. Deze browsers tonen daarom altijd de afbeelding die bij <img> wordt opgegeven. Ongeacht grootte, oriëntatie, en dergelijke van het browservenster.

Dit kan worden verholpen met een zogenaamde 'polyfill': een stukje JavaScript dat nieuwere css, html, en dergelijke in oudere browsers mogelijk maakt.

Als het in deze browsers niet goed werkt, is mogelijk dit script niet goed gekoppeld of zoiets. Een uitgebreider verhaal staat bij picturefill.js.

In UC browser op Android werkt deze polyfill soms wel en soms niet. Als de polyfill niet werkt, wordt de afbeelding uit <img> van 1000 px breed getoond. Dat dit script soms wel en soms niet werkt, kan ook liggen aan het gebruik van de eenheid vh in de eerste <source>, want ook dat kent deze browser niet. Omdat deze browser heel actief wordt bijgehouden, is de polyfill hopelijk snel niet meer nodig.

Maar hoe dan ook: er wordt in ieder geval gewoon een afbeelding getoond, al is dat misschien niet de meest optimale.

Internet Explorer 11 en Edge

Afbeeldingen met bepaalde breedtes worden nooit gebruikt

Deze browsers schijnen problemen te hebben met sommige maten. Bij het testen is bij toeval dat afbeeldingen met een breedte van 1333 px gewoon worden genegeerd, alsof ze helemaal niet zijn opgenomen in de srcset. Diezelfde afbeelding werd wel gebruikt, als de breedte werd veranderd in 1332 of 1334 px (waarbij de rest van de code ongewijzigd bleef).

Als een bepaalde afbeelding alleen in deze browsers niet wordt gebruikt, zou je kunnen proberen de breedte te veranderen. Als ze zich verslikken in 1333 px, zullen er allicht nog meer breedtes zijn, waar ze problemen mee hebben.

Validatie

user-select valideert niet

De css-validator van kent user-select nog niet. Dit zit alleen nog in een ontwerp-specificatie. Daardoor levert dit een foutmelding op. Omdat de reden van de foutmelding bekend is, is dit geen probleem.

Alle browsers, op Opera Mini na, herkennen deze eigenschap al.

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-117-dl.html: de pagina met het voorbeeld.

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

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

117-css-dl:

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

117-js:

picturefill.min.js: het script dat <picture> laat werken in oudere browsers. Het in de download bijgesloten script is versie 3.0.2. Het is afkomstig van scottjehl.github.io/picturefill. Op die pagina kan ook worden gekeken, of dit de meest recente versie van dit script is. Dit soort scripts wordt voortdurend verbeterd en uitgebreid. Als je oudere versies gebruikt, zitten daar misschien nog bugs in die inmiddels zijn gerepareerd.

Dit script wordt verspreid onder de MIT-licentie. (Dit houdt ongeveer in dat je er alles mee mag doen, mits de licentie maar wordt vermeld. Meer info op opensource.org/licenses/mit-license.)

117-pics:

de tien gebruikte afbeeldingen (op de plaats van de puntjes staat de breedte in pixel):

zandkasteel-....jpg: drie volledige afbeeldingen.

zandkasteel-landschap-....jpg: drie liggende uitsnedes.

zandkasteel-portret-...jpg: vier horizontale uitsnedes.

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 wordt in kleinere vensters een kleinere afbeelding weergegeven. 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 kleinere browservensters wordt de afbeelding kleiner weergegeven. Er is op deze pagina niets, wat problemen kan opleveren in een smaller venster.

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.

<script src="117-js/picturefill.min.js" async></script>

Hiermee wordt het JavaScript 'picturefill.js' aan de pagina gekoppeld. Hierdoor werken <picture>, <source>, srcset en sizes ook in oudere browsers. Meer hierover is te vinden bij picturefill.js.

<input id="voor-tab" aria-hidden="true">

Als het vraagteken linksboven wordt aangeraakt of ‑geklikt, of als daarover wordt gehoverd, opent een korte uitleg over de afbeelding. Sommige mensen kunnen of willen de muis niet gebruiken, maar gebruiken de Tab-toets om links, tekstvelden, en dergelijke af te lopen. Omdat het vraagteken in een <span> staat, negeert de Tab-toets het vraagteken.

Voor deze gebruikers is een <input> aangebracht. Een <input> wordt wel bezocht door de Tab-toets. Bij #voor-tab wordt de <input> ver links buiten het scherm geparkeerd, zodat de lay-out niet wordt verstoord. Als de <input> door de Tab-toets wordt bereikt, als de input 'focus' heeft, wordt bij #voor-tab:focus ~ p, #uitleg:hover + p, header p:hover de uitleg zichtbaar.

Omdat deze <input> voor schermlezers niet nodig is en alleen maar verwarrend werkt, wordt hij voor schermlezers verborgen met aria-hidden="true".

Meer over de Tab-toets is te vinden bij Tabindex, meer over aria-hidden is te vinden bij WAI-ARIA-codes.

<span id="uitleg" aria-hidden="true" aria-haspopup="true">?</span>

Dit is de <span>, waar het vraagteken linksboven in zit. Bij aanraken of ‑klikken van of hoveren over dit vraagteken, opent een korte uitleg over de afbeelding.

Schermlezers lezen deze uitleg altijd, daarom wordt het vraagteken met aria-hidden="true" verborgen voor schermlezers. Als dat niet zou gebeuren, zou een schermlezer 'vraagteken' voorlezen, waarbij volstrekt onduidelijk zou zijn, waar dat vraagteken dan bij hoort.

aria-haspopup="true" is nodig voor Internet Explorer 11 en Edge op een touchscreen. Zonder dit attribuut opent de uitleg soms niet, soms heel traag en soms opent het contextuele menu.

Meer uitleg is te vinden bij WAI-ARIA-codes.

<figure>

Dit element is niet nodig voor het aanpassen van de afbeeldingen. Daarvoor is <picture> voldoende. Bij een afbeelding binnen <figure> kan echter met behulp van <figcaption> een bijschrift aan de afbeelding worden gekoppeld. Vandaar dat het hier wordt gebruikt.

<picture>

<picture> geeft de mogelijkheid volkomen verschillende afbeeldingen weer te geven, afhankelijk van dingen als breedte en/of hoogte van het browservenster, oriëntatie van het venster, resolutiedichtheid van het scherm, en nog een reeks andere eigenschappen.

Voor grotere browservensters of schermen met een hogere resolutiedichtheid kan bovendien een grotere afbeelding worden gebruikt dan voor kleinere vensters of schermen met een lagere resolutiedichtheid. Dat is in dit voorbeeld ook het geval: vensters maximaal 600 px breed krijgen een uitsnede van de volledige afbeelding.

Als de afbeelding altijd hetzelfde is, maar alleen in grootte varieert, is het veel makkelijker om een gewone <img> te gebruiken. Binnen die <img> kunnen dan srcset en sizes op dezelfde manier worden gebruikt, als hieronder bij <source> wordt beschreven.

Een veel uitgebreider verhaal over resolutie, resolutiedichtheid, en dergelijke is te vinden bij Resolutie en afbeeldingen. Hieronder staat de precieze werking van <source> en dergelijke.

<source> algemeen

Binnen <picture> kunnen meerdere <source>'s staan. Binnen elke <source> kunnen in srcset één of meer verschillende afbeeldingen worden opgegeven, waaruit de browser met behulp van sizes de meest geschikte kan kiezen voor een bepaald beeldscherm en/of browservenster.

Het eerste attribuut binnen <source> is media. Dit werkt precies hetzelfde als een losse media query in de css (zo'n media query wordt uitgebreid beschreven bij @media screen and (min-width: 601px) and (max-height: 800px) and(min-aspect-ratio: 5/4).

In dit voorbeeld worden vier <source>'s gebruikt, met in elk een set afbeeldingen. Elke <source> is voor een ander scherm en/of browservenster bedoeld.

Om op een groot scherm of browservenster een afbeelding duidelijk weer te kunnen geven, is een grotere afbeelding nodig dan op een klein scherm of venster. Hetzelfde geldt voor een hogeresolutiescherm: ook daar is een grotere afbeelding nodig dan op een scherm met een lagere resolutiedichtheid. Dit geldt alleen voor bitmap-afbeeldingen zoals jpg, gif en png. (Een uitgebreider verhaal hierover is te vinden bij Resolutie en afbeeldingen.)

De binnen <source> opgegeven media query bepaalt, welke <source> voor een bepaald scherm of browservenster wordt gebruikt. Voor dat bepaalde scherm of venster kan dan alleen één van de afbeeldingen uit de set, die binnen die <source> in srcset wordt opgegeven, worden gebruikt.

De media query in <source> is dwingend: de browser kan hier niet van afwijken. Als een bepaalde <source> voor een browservenster van maximaal 600 px breed is, en de kleinste afbeelding binnen de srcset van die <source> is 10000 px breed (om maar iets volslagen idioots te roepen), dan moet de browser hoe dan ook die afbeelding downloaden en weergeven. Hoe slecht de verbinding mogelijk ook is, of hoe leeg de accu van het mobieltje, of welke gewetensbezwaren de arme browser mogelijk heeft, of wat dan ook. Gewoon doen. Punt.

Zodra een bij beeldscherm en/of browservenster passende <source> wordt gevonden, wordt niet meer naar andere <source>'s gekeken. Daarom is de volgorde van de <source>'s belangrijk.

Als de bovenste <source> als voorwaarde heeft 'minimaal 601 px breed', en daaronder staat een <source> voor browservensters minimaal 1000 px breed, dan wordt die tweede <source> nooit bekeken. Elk venster dat minimaal 1000 px breed is, is immers ook minimaal 601 px breed.

Als daarentegen de <source> voor minimaal 1000 px breed als eerste staat, wordt de tweede <source> voor browservensters van minstens 601 px breed wel bekeken, als het venster geen 1000 px breed is.

Een browser werkt intern altijd met de eenheid pixel. Als de media query een breedte of hoogte bevat, wordt die door de browser altijd omgezet in pixels. Daarbij gaat het om 'css-pixels': de eenheid die van oudsher in css, html, en dergelijke wordt gebruikt. Een css-pixel heeft een vaste grootte, gebaseerd op oudere beeldschermen. Er passen 96 css-pixels in 1 inch.

Een hogeresolutiescherm heeft kleinere pixels die dichter op elkaar staan, waardoor een (veel) betere weergave mogelijk is. Die fysiek in het scherm aanwezige pixels heten 'schermpixels' (in het Engels 'device pixels'). Omdat die pixels kleiner zijn, gaan er (veel) meer in een inch. Als een hogeresolutiescherm een resolutiedichtheid heeft van twee keer die van een ouder beeldscherm en 1000 css-pixels breed is, zijn er 2000 schermpixels. Bij een resolutiedichtheid die vier keer zo hoog is, zitten er 4000 schermpixels in 1000 css-pixels.

Als in een media query voor breedte, hoogte, en dergelijke pixels worden gebruikt, gaat het altijd om css-pixels. Meer over het verschil tussen css‑ en schermpixels is te vinden bij Resolutie en afbeeldingen.

Als een browservenster (heel) klein is en de afbeelding (heel) groot, kan de afbeelding onduidelijk worden, omdat hij veel te klein wordt weergegeven. De media query in de <source>'s geeft de mogelijkheid, om voor verschillende vensters verschillende afbeeldingen te gebruiken. In dit voorbeeld is er een set afbeeldingen voor vensters minimaal 601 px breed. Daarnaast zijn er twee sets met afbeeldingen voor vensters maximaal 600 px breed. Die afbeeldingen zijn een uitsnede van de grote afbeelding. De grote afbeelding zou, in deze kleinere vensters, veel te klein worden om nog goed te kunnen zien.

Er zijn twee sets voor kleinere browservensters: één set voor vensters in portretstand, en één set voor vensters in landschapsstand.

In totaal zijn er dus drie verschillende sets met afbeeldingen. Sets, want binnen de groep browservensters van minimaal 601 px breed heb je allerlei verschillen. Een venster kan 601 px breed zijn, maar ook 2400. Of het venster kan 1000 px breed zijn, maar het scherm heeft een dubbele resolutiedichtheid (1000 css-pixels, maar 2000 schermpixels). Het kan breed zijn en tegelijk laag, zoals veel laptops.

De media query's binnen de <source>'s maken als het ware een ruwe selectie: de geschikte set afbeeldingen voor een bepaald scherm en/of browservenster. Binnen de <source> wordt vervolgens een meer specifieke keuze gemaakt uit de afbeeldingen, die binnen die <source> mogen worden gebruikt.

Als de site wordt gemaakt, is de breedte van een afbeelding bij de maker bekend. Ook kan worden opgegeven, hoe breed de afbeelding moet worden weergegeven. Die breedte wordt altijd in css-pixels opgegeven, net zoals dat altijd al gebeurde. Als een andere eenheid wordt gebruikt, rekent de browser dat om naar pixels.

De maker van de site weet echter niet, hoe breed het browservenster van de bezoeker van de site is, wat de resolutiedichtheid van het scherm is, wat de oriëntatie van het venster is, en meer van dat soort eigenschappen.

Die eigenschappen zijn echter precies, wat de browser wel weet, want die kent het scherm en het browservenster. Maar de browser weet weer niet, hoe breed een afbeelding is. En dus weet de browser ook niet, wat de beste afbeelding voor een bepaald scherm en/of venster is. Om dat te weten zou de browser eerst de html en/of css moeten verwerken om de breedte van de weergave op te zoeken. Daarna zouden alle afbeeldingen moeten worden gedownload, want de browser weet niet hoe breed de afbeeldingen zijn. En dan kan de juiste afbeelding eindelijk worden weergegeven. Tegen die tijd zijn bezitters van een mobieltje huilend weggelopen. Huilend omdat ze failliet zijn door de hoeveelheid data die is verbruikt, en weggelopen omdat het eindeloos duurt voor alles is gedownload.

Als je nu echter de kennis van de browser en die van de maker van de site combineert, kan dit worden voorkomen. En dat is precies wat er binnen een <source> gebeurt. De eerste <source> uit het voorbeeld heeft als één van de voorwaarden dat het browservenster minstens 601 px breed moet zijn. (De rest van de voorwaarden wordt hieronder bij de betreffende <source> behandeld.)

Als er is vastgesteld dat het browservenster aan die eis voldoet, wordt één van de afbeeldingen uit die <source> gebruikt. In het attribuut srcset in <source> worden de afbeeldingen, waaruit de browser kan kiezen, opgegeven. Achter elke afbeelding staat de breedte in pixels. Als de browser de html heeft verwerkt, weet de browser dus al – zonder dat alle afbeeldingen eerst moeten worden gedownload – hoe breed de afbeeldingen zijn.

Het laatste attribuut in <source> is sizes. Hierin wordt opgegeven, op welke breedte een afbeelding moet worden weergegeven. Daarbij kan ook bij een browservenster van een bepaalde breedte een bepaalde weergavebreedte worden opgegeven. Dit gebeurt binnen sizes op ongeveer dezelfde manier als bij een media query, maar er zijn wat minder mogelijkheden dan bij een echte media query. (Het heet hier ook geen media query, maar een 'media conditie', in het Engels 'media condition'.)

De browser heeft nu genoeg gegevens ter beschikking om, zonder dat alle afbeeldingen hoeven te worden gedownload, de voor dat scherm en browservenster beste afbeelding te gebruiken.

Op een ouder beeldscherm met een browservenster van 1000 px breed, zou dat de afbeelding van 800 px kunnen zijn. Maar op een hogeresolutiescherm met een venster van 1000 px breed zou het de afbeelding van 2000 px breedte kunnen zijn.

<source> legt dwingend een bepaalde set afbeeldingen voor een bepaald scherm en/of browservenster op. Maar welk van die afbeeldingen uit de srcset van een <source> uiteindelijk wordt gebruikt, beslist de browser. De browser kan, bijvoorbeeld bij een slechte internetverbinding, toch kiezen voor een kwalitatief slechtere, maar kleinere afbeelding.

Daarom is <source> geschikt om af te dwingen dat een bepaalde afbeelding wordt gebruikt, zoals een uitsnede van de volledige afbeelding voor een kleiner browservenster. De browser kan hier niet van afwijken. Zou je verschillende afbeeldingen binnen een srcset opgeven, dan weet je nooit zeker, welke afbeelding de browser gaat gebruiken. Daardoor zou in een groter venster de uitsnede voor kleinere vensters kunnen worden weergegeven. Bij een media query in een <source> kan dat niet, omdat die dwingend aan de browser wordt opgelegd.

In <picture> staat verplicht ook een <img>. Dat heeft twee redenen. Oudere browsers die <source> niet kennen, gebruiken gewoon de in de <img> opgegeven afbeelding.

Nieuwere browsers zoeken de meest geschikte afbeelding op aan de hand van de <source>'s met de daarin zittende srcset en sizes. Als die afbeelding is gevonden, wordt de afbeelding uit de <img> als het ware vervangen door de gevonden afbeelding. Hierdoor werkt css voor <img> net als altijd, ongeacht welke afbeelding wordt gebruikt.

Ook voor JavaScript is dit van belang. Als een script vraagt, welke afbeelding is gebruikt, wordt de daadwerkelijk gebruikte afbeelding opgegeven, en niet de afbeelding die in de html bij <img> is opgegeven.

Een nadeel van deze methode is wel dat je meerdere afbeeldingen moet maken, met van elke afbeelding waarschijnlijk ook nog verschillende maten. Maar dat is niet zo heel veel werk, elk goed grafisch programma kan dat op eenvoudige wijze. Je kunt het ook vrij makkelijk automatiseren, als je veel afbeeldingen moet vergroten of verkleinen.

Het is ook niet nodig om voor elke mogelijke grootte, resolutiedichtheid, en dergelijke een exact passende afbeelding te maken. De browser zal, als er geen precies passende afbeelding is, de eerstvolgende afbeelding gebruiken die (iets) groter is. En omdat een browser wel vrij goed kan verkleinen, werkt dat prima.

<source media="(min-width: 601px) and (max-height: 800px) and (min-aspect-ratio: 5/4)" srcset="117-pics/zandkasteel-2000.jpg 2000w, 117-pics/zandkasteel-1000.jpg 1000w, 117-pics/zandkasteel-800.jpg 800w" sizes="100vh">

De eerste <source>, en gelijk de meest ingewikkelde. Nou ja, dan kan de rest alleen maar meevallen.

(Ook hier wordt weer wordt 'venster', 'browservenster' of 'venster van de browser' gebruikt, als het venster van de browser wordt bedoeld. Veel mensen noemen dit bij een mobiel apparaat gewoon 'scherm'. Op een mobiel apparaat is het venster inderdaad meestal even groot als het scherm, maar op de desktop is dat vaak niet het geval. Hier wordt daarom altijd de term 'venster' (of 'browservenster' of 'venster van de browser' gebruikt), als het venster wordt bedoeld. 'Scherm' of 'beeldscherm' wordt gebruikt, als het fysieke scherm (wat je aan kunt raken) wordt bedoeld.

media =: hierachter staan de voorwaarden, waaraan het scherm en/of het browservenster moeten voldoen. Dit werkt precies hetzelfde als bij een media query in de css. Het scherm en/of het venster móéten aan deze eisen voldoen, de browser kan hier niet van afwijken. Als het scherm en/of het venster aan de eisen van deze media query voldoen, wordt dus altijd één van de in de hierachter staande srcset opgegeven afbeeldingen gebruikt.

Alle voorwaarden samen staan tussen aanhalingstekens. Elke aparte voorwaarde staat tussen haakjes. Dit moet gewoon zo van de specificatie, zeg maar 'n soort taalregels.

(min-width: 601px): het browservenster moet minstens 601 px breed zijn.

and: er komt nog een voorwaarde.

(max-height: 800px): het browservenster mag niet hoger zijn dan 800 px. De reden daarvan staat iets hieronder bij min-aspect-ratio.

and: er komt nog een voorwaarde.

(min-aspect-ratio: 5/4): hiermee wordt de verhouding tussen breedte en hoogte van het browservenster aangegeven.

De in deze <source> gebruikte afbeeldingen hebben een verhouding van 4:3. Als de afbeelding 1000 px breed is, is deze 750 px hoog. De breedte is 4 x 250 px, de hoogte 3 x 250 px: 4:3.

Als een browservenster breed en relatief laag is, zoals bij een laptop vaak het geval is, kan dit problemen opleveren. De voor het testen gebruikte laptop met Windows 8.1 heeft een scherm van 1366 x 768 px. Het browservenster vult het volledige scherm. In dat venster moet de afbeelding van 1000 x 750 px worden gebruikt. Dat zou in de hoogte net passen, alleen heeft de browser ook nog menubalken en dergelijke, en er staat een onderschrift onder de afbeelding. Hierdoor past de afbeelding in de hoogte niet meer binnen het venster en moet worden gescrold om de hele afbeelding te zien.

Het zelfde speelt op een tablet van 1024 x 768 px: de afbeelding van 1000 px breed wordt gebruikt, en die past met z'n hoogte van 750 px, onderschrift, rand van de browser, en dergelijke niet binnen het browservenster.

Het browservenster van 1366 x 768 px heeft een breedte van 1366 px en een hoogte van 768 px. (Mogelijk iets minder, omdat er mogelijk nog 'n menubalk en dergelijke vanaf gaat). De verhouding is 1366:768. Als je dat gaat delen, kom je uit op ongeveer 1,79.

In een media query heet de verhouding tussen breedte en hoogte aspect-ratio. Verder wordt de verhouding vanwege technische redenen niet geschreven als '5:4' of zoiets, maar als '5/4'.

In deze media query is min-aspect-ratio: 5/4 gebruikt: minstens een aspect-ratio van 5/4. Als je vijf door vier deelt, is de uitkomst 1,25. De minimale aspect-ratio, de minimale verhouding, tussen breedte en lengte moet 1,25 zijn. De laptop van hierboven komt uit op 1,79 en voldoet dus hieraan en valt dus binnen deze media query, want ook aan de eisen voor breedte en hoogte wordt voldaan.

De tablet van 1024 x 768 px heeft een aspect-ratio van 1024:768 = ongeveer 1,33. Omdat ook aan de eisen voor breedte en hoogte wordt voldaan, valt ook deze tablet binnen deze media query.

Een beeldscherm op de desktop is vaak 1280 x 1024 px. Dat is een aspect-ratio 1280:1024 = 1,25. Als de browser schermvullend is, voldoet ook dit browservenster aan de eis voor de minimale aspect-ratio van 1,25 (5/4 = 1,25). Maar dat is niet de bedoeling, want op dit venster past de afbeelding prima in de hoogte. Dat is de reden van (max-height: 800px) in de media query: deze media query geldt alleen voor lagere vensters.

De Mac waarop hier wordt getest heeft een scherm van 1680 x 1050 px. De afbeelding past daar natuurlijk ruimschoots in z'n geheel op. Maar de aspect-ratio (1680/1050) van de Mac is 1,6. Zonder de maximumhoogte in de media query, zou zelfs deze Mac binnen deze query vallen.

Zou de Mac 1680 px hoog zijn, maar slechts 700 px hoog, dan is de aspect-ratio 2,4 én de hoogte is minder dan 800 px. Nu zou de Mac wel binnen deze query vallen. En terecht, want de afbeelding zou dan veel te hoog zijn.

Door de combinatie van de aspect-ratio en de maximale hoogte vallen alleen bredere en relatief lage browservensters binnen deze media query. Dat zijn precies de vensters, waarin de afbeelding niet zonder scrollen in z'n geheel is te zien. Dit geeft de mogelijkheid om in deze vensters de afbeelding op een ander formaat weer te geven.

In het attribuut sizes verderop wordt de breedte van de afbeelding beperkt. De browser past de hoogte van de afbeelding automatisch aan de kleinere breedte aan, zodat een lachspiegel-effect wordt voorkomen. Bij een kleinere breedte wordt de hoogte ook kleiner en hocus pocus pilatus pas: de afbeelding past.

Je zou er ook voor kunnen kiezen niet de volledige afbeelding, maar een lagere uitsnede van de volledige afbeelding te gebruiken binnen deze <source>. In dit geval is dat niet gebeurd: alleen de grootte wordt aangepast.

(Overigens zijn de hier gebruikte afbeeldingen wel heel erg groot. Maar dat is expres gedaan, omdat dan ook iets als min-aspect-ratio gebruikt kan worden. Normaal genomen zul je afbeeldingen kiezen, die gewoon op 'n laptop passen.)

srcset: binnen srcset worden, gescheiden door een komma, één of meer afbeeldingen opgegeven, waaruit de browser een keuze kan maken. De browser kan alleen maar een goede keuze maken, als de breedte van de afbeeldingen bekend is. Om te voorkomen dat de browser alle afbeeldingen moet downloaden om achter de breedte te komen, wordt de breedte in pixels achter de afbeelding gezet. Alleen wordt niet de afkorting 'px' gebruikt, maar 'w':

117-pics/zandkasteel-1000.jpg 1000w

Deze afbeelding zit in de map '117-pics', de naam is 'zandkasteel-1000.jpg' en de breedte is 1000 px. De reden dat de letter 'w' wordt gebruikt in plaats van 'px': er waren eerst plannen om desgewenst ook de hoogte van de afbeelding aan te kunnen geven met een 'h'. De 'w' staat voor 'width': breedte. Misschien dat de 'h' ooit nog gebruikt gaat worden, vandaar dat de 'w' in gebruik is gebleven. Maar 1000w betekent dus precies hetzelfde als 1000px.

De browser is verplicht één van de drie hier opgegeven afbeeldingen te gebruiken. Als het scherm en/of het browservenster aan de media query voldoet, zit de browser aan één van de afbeeldingen uit deze srcset vast. Maar welke afbeelding wordt gebruikt, bepaalt de browser. Bij bijvoorbeeld een slechte internetverbinding kan de browser voor een kleinere afbeelding kiezen, omdat die sneller wordt gedownload. De kwaliteit is dan misschien wat slechter, maar je hoeft in ieder geval niet eindeloos te wachten.

Hoe de browser deze keuze maakt, staat uitgebreider beschreven bij Resolutie en afbeeldingen.

sizes: hierin wordt de breedte opgegeven, waarop de afbeelding moet worden weergegeven.

Afbeelding 5: in brede, maar lage vensters is de foto te hoog

In brede en lage browservensters verdwijnt een deel van de onderkant van de afbeelding onder het venster van de browser. De afbeelding is alleen in z'n geheel te zien, als wordt gescrold. Ook het onderschrift verdwijnt onder het venster.

Hiernaast staat een breed, maar laag browservenster. In de breedte is er geen enkel probleem: de afbeelding past ruim binnen het venster. Maar in de hoogte is er wel een probleem: het venster is te laag om de hele afbeelding weer te kunnen geven.

sizes werkt echter alleen in de breedte: de maten die daar worden opgegeven, hebben betrekking op de breedte van de afbeelding. Als de afbeelding te hoog is, heb je dus niets aan sizes.

Maar via een omweg lukt het toch: je kunt de hoogte van het browservenster opgeven als breedtemaat.

Pardon?

Ja, dat veroorzaakte ook in mijn hersenen even een verknoping.

Het probleem: het venster van de browser is te laag. De hoogte van het venster is echter bekend, want die is altijd 100 vh. vh is een wat onbekende eenheid, die echter in vrijwel alle browsers wordt ondersteund. De hoogte van het venster is altijd 100 vh. Als het venster 1000 px hoog is, is 100 vh gelijk aan 1000 px (en 1 vh is dan 10 px). Als het venster 600 px hoog is, is 100 vh gelijk aan 600 px (en 1 vh is dan 6 px).

Oftewel: de waarde van vh is gekoppeld aan de hoogte van het browservenster. Als je nou de breedte van de afbeelding in vh opgeeft, wordt de breedte van de afbeelding ook gekoppeld aan de hoogte van het venster. Daarom is de bij sizes opgegeven breedte hier 100 vh: even hoog als het venster. Als het venster lager is, is 100 vh minder dan wanneer het venster hoger is, en is de afbeelding dus minder breed dan bij een hoger venster.

Als de breedte van de afbeelding wordt verminderd, vermindert de browser automatisch ook de hoogte. Anders zou je 'n lachspiegel-effect krijgen.

Het blijkt dat 100 vh het gewenste effect heeft: in alle geteste browsers zijn de volledige afbeelding én het onderschrift nu te zien, terwijl de afbeelding niet kleiner wordt dan nodig is.

Hier wordt maar één breedte opgegeven bij sizes. Dat betekent dat alle afbeeldingen, welke de browser ook kiest, allemaal op dezelfde breedte worden weergegeven: 100 vh. In dit geval is dat voldoende, omdat deze media query alleen is bedoeld om een probleem in te lage browservensters op te lossen.

(En eigenlijk worden er toch meerdere breedtes opgegeven, want 100 vh is afhankelijk van de hoogte van het browservenster. Bij een lagere hoogte is er een smallere breedte en zal de browser dus eerder een smallere afbeelding gebruiken.)

De browser kan in deze <source> kiezen uit de drie in srcset zittende afbeeldingen, waarvan alleen de grootte verschilt: 2000 px breed, 1000 px breed en 800 px breed (met de daarbij passende hoogtes). De gekozen afbeelding wordt altijd weergegeven op een breedte van 100 vh. Over hoe de browser de afbeelding kiest, is meer te vinden bij <source> algemeen.

<source media="(min-width: 601px)" srcset="117-pics/zandkasteel-2000.jpg 2000w, 117-pics/zandkasteel-1000.jpg 1000w, 117-pics/zandkasteel-800.jpg 800w" sizes="(max-width: 800px) 800px, 1000px">

De tweede <source>.

media: hierachter staan weer de voorwaarden (in dit geval: voorwaarde), waaraan het scherm en/of het browservenster moeten voldoen.

(min-width: 601px): de enige voorwaarde: het browservenster moet minstens 601 px breed zijn.

Dat is dezelfde voorwaarde als bij de eerste <source>, maar daar mocht het browservenster maximaal 800 px hoog zijn en moet het venster een minimale aspect-ratio van 5/4 hebben. Als het venster minstens 601 px breed is, maar hoger dan 800 px is of een lagere aspect-ratio dan 5/4 heeft, voldoet het niet aan de eisen van de eerste <source>. Maar het valt dan wel binnen deze media query, want hier is de enige voorwaarde een minimumbreedte van 601 px.

Hieruit blijkt het belang van de volgorde van de <source>'s. Zou deze media query in de eerste <source> hebben gestaan, en die uit de eerste hier als tweede, dan zou die tweede <source> nooit worden bekeken. Als het browservenster breder dan 601 px is, zou het altijd voldoen aan de media query uit de eerste <source>. En zodra een <source> is gevonden die bij het venster past, wordt niet meer verder gekeken.

srcset: de gebruikte afbeeldingen zijn precies hetzelfde als die bij de eerste <source>. Omdat de afbeeldingen hetzelfde zijn, zou je de eerste en tweede <source> kunnen combineren. De media query test dan alleen op een minimumbreedte van 601 px, en de rest van de voorwaarden (hoogte en aspect-ratio) komt bij sizes te staan. Je krijgt dan echter een gruwelijk ingewikkelde sizes. Er zijn toch al meerdere <source>'s nodig, want bij de derde en vierde <source> worden wel andere afbeeldingen gebruikt. Daarom is het hier makkelijker om het te splitsen en gewoon nog 'n <source> toe te voegen.

sizes: de afbeelding kan op twee verschillende breedtes worden weergegeven: 800 px en 1000 px, afhankelijk van de breedte van het browservenster. Dit geef je op dezelfde manier aan als bij een media query, alleen zijn er hier wat minder mogelijkheden dan bij een echte media query, en het heet hier 'media conditie' (in het Engels 'media condition').

"(max-width: 800px) 800px, 1000px":

Net als bij een media query staat het geheel achter sizes tussen aanhalingstekens. De verschillende voorwaarden waaraan het scherm en/of het browservenster moeten voldoen worden, met de bijbehorende weergavebreedte, gescheiden door een komma.

(max-width: 800px) 800px: tussen de haakjes staat de voorwaarde, waaraan het browservenster moet voldoen: maximaal 800 px breed. Achter de haakjes staat de breedte, waarop de afbeelding moet worden weergegeven: 800 px. Omdat deze <source> alleen geldt voor browservensters die minimaal 601 px breed zijn, geldt dit dus voor vensters met een breedte van 601 tot en met 800 px. In vensters van deze breedte wordt de afbeelding 800 px breed weergegeven.

1000px: de tweede breedte. Omdat hier geen voorwaarde voor het browservenster staat, geldt deze breedte voor alle vensters die niet aan de eerdere condities voldoen (hier is maar één eerdere conditie: maximaal 800 px breed). Oftewel: in vensters breder dan 800 px wordt de afbeelding op een breedte van 1000 px weergegeven.

Dit zou problemen op kunnen leveren, want in een browservenster van bijvoorbeeld 650 px breed wordt de afbeelding 800 px breed weergegeven. En in een venster van 850 px breed wordt de afbeelding 1000 px breed weergegeven. Daardoor zou je heel vaak moeten scrollen om de hele afbeelding te zien.

Om dat te voorkomen heeft <figure>, waar de hele handel in zit, bij figure een maximumbreedte van 90% van de breedte van het browservenster gekregen.

De door de browser gebruikte afbeelding wordt gebruikt in de <img> in <picture>. Hierdoor werkt css voor de <img> ook voor de door de browser gebruikte afbeelding. Bij img krijgt <img> een maximumbreedte van 100%, waardoor de afbeelding nooit breder is dan <figure>. En omdat <figure> nooit breder dan 90% van het browservenster wordt, wordt ook <img> nooit breder.

In een browservenster van 650 px of 850 px breed, wordt de afbeelding gewoon versmald. De hoogte wordt automatisch mee verkleind, zodat een lachspiegel-effect wordt voorkomen.

De browser kan in deze <source> kiezen uit de drie in srcset zittende afbeeldingen, waarvan alleen de grootte verschilt: 2000 px breed, 1000 px breed en 800 px breed (met de daarbij passende hoogtes). De gekozen afbeelding wordt weergegeven op een breedte van 800 of 1000 px, of smaller als dat niet past. Bij een hogeresolutiescherm kan de browser kiezen voor de afbeelding met een breedte van 2000 px, die dan op een breedte van 800 of 1000 px wordt weergegeven. Over hoe de browser de afbeelding kiest, is meer te vinden bij <source> algemeen.

<source media="(orientation: landscape)" srcset="117-pics/zandkasteel-landschap-1200.jpg 1200w, 17-pics/zandkasteel-landschap-900.jpg 900w, 117-pics/zandkasteel-landschap-600.jpg 600w" sizes="600px">

De derde <source>.

media: hierachter staan weer de voorwaarden, waaraan het scherm en/of het browservenster moeten voldoen. In de eerste en tweede <source> zijn alle vensters die minstens 601 px breed zijn er al uit gehaald. Deze media condities kunnen dus alleen gelden voor vensters die hoogstens 600 px breed zijn.

(orientation: landscape): browservensters in landschapsstand: de breedte is groter dan de hoogte. Meer voorwaarden zijn er niet: dit geldt voor álle vensters in landschapsstand die maximaal 600 px breed zijn. Met andere woorden: mobieltjes die liggend worden vastgehouden.

srcset: binnen srcset worden, gescheiden door een komma, één of meer afbeeldingen opgegeven, waaruit de browser een keuze kan maken. De browser kan alleen maar een goede keuze maken, als de breedte van de afbeeldingen bekend is. Daarom wordt die in pixels achter de afbeelding gezet. Alleen wordt niet de afkorting 'px' gebruikt, maar 'w':

117-pics/zandkasteel-landschap-1200.jpg 1200w

Deze afbeelding zit in de map '117-pics', de naam is 'zandkasteel-landschap-1200.jpg' en de breedte is 1200 px. De reden dat de letter 'w' wordt gebruikt in plaats van 'px': er waren eerst plannen om desgewenst ook de hoogte van de afbeelding aan te geven met een 'h'. De 'w' staat voor 'width': breedte. Misschien dat de 'h' ooit nog gebruikt gaat worden, vandaar dat de 'w' in gebruik is gebleven. Maar 1200w betekent dus precies hetzelfde als 1200px.

Deze afbeeldingen zijn een uitsnede van de volledige afbeelding, waardoor ze geschikter zijn voor kleinere browservensters. De uitsnede is liggend, waardoor deze afbeeldingen geschikter zijn voor een klein venster in landschapsstand.

De browser is verplicht één van de drie hier opgegeven afbeeldingen te gebruiken. Als het scherm en/of het browservenster aan de media query voldoen, zit de browser aan één van de afbeeldingen uit deze srcset vast. Maar welke afbeelding wordt gebruikt, bepaalt de browser. Bij bijvoorbeeld een slechte internetverbinding kan de browser voor een kleinere afbeelding kiezen, omdat die sneller wordt gedownload. De kwaliteit is dan misschien wat slechter, maar je hoeft in ieder geval niet eindeloos te wachten.

Hoe de browser deze keuze maakt, staat uitgebreider beschreven bij Resolutie en afbeeldingen.

sizes: hierin wordt de breedte opgegeven, waarin de afbeelding moet worden weergegeven.

Omdat alleen de breedte 600 px wordt weergegeven, wordt de afbeelding altijd op een breedte van 600 px weergegeven.

Dit zou problemen op kunnen leveren, want in een browservenster van bijvoorbeeld 400 px breed wordt de afbeelding 600 px breed weergegeven. Daardoor zou je moeten scrollen om de hele afbeelding te zien.

Om dat te voorkomen heeft <figure>, waar de hele handel in zit, bij figure een maximumbreedte van 90% van de breedte van het browservenster gekregen.

De door de browser gebruikte afbeelding wordt gebruikt in de <img> in <picture>. Hierdoor werkt css voor de <img> ook voor de door de browser gebruikte afbeelding. Bij img krijgt <img> een maximumbreedte van 100%, waardoor de afbeelding nooit breder is dan <figure>. En omdat <figure> nooit breder dan 90% van het browservenster wordt, wordt ook <img> nooit breder.

In een browservenster van 400 px breed, wordt de afbeelding gewoon versmald. De hoogte wordt automatisch ook verkleind, zodat een lachspiegel-effect wordt voorkomen.

De browser kan in deze <source> kiezen uit de drie in srcset zittende afbeeldingen, waarvan alleen de grootte verschilt: 1200 px breed, 900 px breed en 600 px breed (met de daarbij passende hoogtes). De gekozen afbeelding wordt weergegeven op een breedte van 600 px, of smaller als dat niet past. Bij een hogeresolutiescherm kan de browser kiezen voor de afbeelding met een breedte van 900 of 1200 px, die dan op een breedte van 600 px wordt weergegeven.

(Feitelijk wordt de afbeelding hoogstens 540 px breed weergegeven, omdat het browservenster maximaal 600 px breed kan zijn en de afbeelding 90 procent daarvan. Maar omdat (vrijwel) elk mobieltje een hogere resolutiedichtheid heeft, kan de afbeelding van 600 px breed worden gebruikt voor mobieltjes met een slechts iets hogere dichtheid.)

De afbeelding wordt nooit breder dan het venster van de browser. Maar de hoogte is een ander verhaal. Als de afbeelding 600 px breed wordt weergegeven in een browservenster in landschapsstand, is de hoogte van het venster dus minder dan 600 px. Dat zal meestal zelfs veel minder zijn, omdat het meestal om 'n mobieltje zal gaan. Daardoor moet in de hoogte worden gescrold om de hele afbeelding te kunnen zien.

Dat zou voorkomen kunnen worden door een gelijksoortige constructie als bij de eerste <source>, waarbij de afbeelding zoveel wordt verkleind, dat deze altijd volledig is te zien. Maar de afbeelding zou dan op een liggend mobieltje wel héél klein worden. Nu heeft de gebruiker de keuze: een grotere afbeelding, waarbij gescrold moet worden, of een kleinere in een browservenster in portretstand (zie de <source> gelijk hieronder), waarbij niet gescrold hoeft te worden.

Over hoe de browser de afbeelding kiest, is meer te vinden bij <source> algemeen.

<source srcset="117-pics/zandkasteel-portret-1200.jpg 1200w, 117-pics/zandkasteel-portret-800.jpg 800w, 117-pics/zandkasteel-portret-500.jpg 500w, 117-pics/zandkasteel-portret-320.jpg 320w" sizes="(max-width: 320px) 320px, (max-width: 500px) 500px, 600px">

De vierde en laatste <source>.

media: dat ontbreekt hier. Bij de eerste twee <source>'s zijn alle browservensters die minstens 601 px breed zijn er al uitgepikt. Bij de derde <source> zijn de vensters in landschapsstand er uitgehaald. Alle vensters die hier niet in passen, komen bij deze vierde <source> uit. Daarom zijn hier geen voorwaarden voor het venster meer nodig: deze <source> geldt voor alle vensters, die niet binnen de eerste, tweede of derde <source> vallen. Dat zijn alle vensters in portretstand die maximaal 600 px breed zijn. Oftewel: mobieltjes die rechtop worden gehouden.

srcset: binnen srcset worden, gescheiden door een komma, één of meer afbeeldingen opgegeven, waaruit de browser een keuze kan maken. De browser kan alleen maar een goede keuze maken, als de breedte van de afbeeldingen bekend is. Daarom wordt die in pixels achter de afbeelding gezet. Alleen wordt niet de afkorting 'px' gebruikt, maar 'w':

117-pics/zandkasteel-portret-1200.jpg 1200w

Deze afbeelding zit in de map '117-pics', de naam is 'zandkasteel-portret-1200.jpg' en de breedte is 1200 px. De reden dat de letter 'w' wordt gebruikt in plaats van 'px': er waren eerst plannen om desgewenst ook de hoogte van de afbeelding aan te geven met een 'h'. De 'w' staat voor 'width': breedte. Misschien dat de 'h' ooit nog gebruikt gaat worden, vandaar dat de 'w' in gebruik is gebleven. Maar 1200w betekent dus precies hetzelfde als 1200px.

Deze afbeeldingen zijn een uitsnede van de volledige afbeelding, waardoor ze geschikter zijn voor kleinere browservensters. De uitsnede is staand, waardoor deze afbeeldingen geschikter zijn voor een klein venster in portretstand.

De browser is verplicht één van de vier hier opgegeven afbeeldingen te gebruiken. Als het scherm en/of het browservenster aan de media query voldoen, zit de browser aan één van de afbeeldingen uit deze srcset vast. Maar welke afbeelding wordt gebruikt, bepaalt de browser. Bij bijvoorbeeld een slechte internetverbinding kan de browser voor een kleinere afbeelding kiezen, omdat die sneller wordt gedownload. De kwaliteit is dan misschien wat slechter, maar je hoeft in ieder geval niet eindeloos te wachten.

Hoe de browser deze keuze maakt, staat uitgebreider beschreven bij Resolutie en afbeeldingen.

sizes: de afbeelding kan op drie verschillende breedtes worden weergegeven: 320px, 500 px en 600 px, afhankelijk van de breedte van het browservenster. Dit geef je op dezelfde manier aan als bij een media query, alleen zijn er hier wat minder mogelijkheden dan bij een echte media query, en het heet hier 'media conditie' (in het Engels 'media condition').

"(max-width: 320px) 320px, (max-width: 500px) 500px, 600px"

Net als bij een media query staat het geheel achter sizes tussen aanhalingstekens. De verschillende voorwaarden waaraan het scherm en/of het browservenster moeten voldoen worden, met de bijbehorende weergavebreedte, gescheiden door een komma.

(max-width: 320px) 320px: tussen de haakjes staat de voorwaarde, waaraan het browservenster moet voldoen: maximaal 320 px breed. Achter de haakjes staat de breedte, waarop de afbeelding moet worden weergegeven: 320 px.

(max-width: 500px) 500px: de tweede mogelijkheid. Tussen de haakjes staat weer de voorwaarde, waaraan het scherm en/of het browservenster moeten voldoen: maximaal 500 px breed. Bij de eerste media conditie zijn de vensters met een maximumbreedte van 320 px er al uitgehaald, dus deze media conditie geldt voor vensters met een breedte van 321 tot en met 500 px.

600px: de derde en laatste breedte. Omdat hier geen voorwaarde voor scherm of browservenster staat, geldt deze breedte voor alle vensters die niet aan de eerdere condities voldoen (hier: maximaal 320 of 500 px breed). Oftewel: in vensters breder dan 500 px wordt de afbeelding op een breedte van 600 px weergegeven.

Dit zou problemen op kunnen leveren, want in een browservenster van bijvoorbeeld 550 px breed wordt de afbeelding 600 px breed weergegeven. En in een venster van 400 px breed wordt de afbeelding 500 px breed weergegeven. Daardoor zou je heel vaak moeten scrollen om de hele afbeelding te zien.

Dat zou ook inderdaad zo zijn, als <figure>, waar de hele handel in zit, niet bij figure een maximumbreedte van 90% van de breedte van het browservenster had gekregen.

De door de browser gebruikte afbeelding wordt gebruikt in de <img> in <picture>. Hierdoor werkt css voor de <img> ook voor de door de browser gebruikte afbeelding. Bij img krijgt <img> een maximumbreedte van 100%, waardoor de afbeelding nooit breder is dan <figure>. En omdat <figure> nooit breder dan 90% van het browservenster wordt, wordt ook <img> nooit breder.

In een venster van 550 px of 400 px breed, wordt de afbeelding gewoon versmald. De hoogte wordt automatisch mee verkleind, zodat een lachspiegel-effect wordt voorkomen.

De browser kan in deze <source> kiezen uit de vier in srcset zittende afbeeldingen, waarvan alleen de grootte verschilt: 1200 px breed, 800 px breed, 500 px breed en 320 px breed (met de daarbij passende hoogtes). De gekozen afbeelding wordt weergegeven op een breedte van 320, 500 of 600 px, of smaller als dat niet past. Bij een hogeresolutiescherm kan de browser kiezen voor de afbeelding met een breedte van 800 of 1200 px, die dan op een breedte van 320, 500 of 600 px wordt weergegeven. Over hoe de browser de afbeelding kiest, is meer te vinden bij <source> algemeen.

<img src="117-pics/zandkasteel-1000.jpg" alt="Afbeelding 1">

Binnen <picture> moet een <img> aanwezig zijn.

Binnen een <img> kunnen ook srcset en sizes worden gebruikt. Daarom kun je, als alleen de grootte van de afbeelding moet worden aangepast, beter <img> gebruiken dan <picture>, want dat is veel simpeler.

In dit voorbeeld worden echter drie verschillende sets met afbeeldingen gebruikt, en dan heb je <picture> nodig.

Omdat de <img> binnen <picture> een doodgewone <img> is, met alles erop en eraan, gebruiken browsers die <picture> en <source> niet kennen deze <img>. Ook oudere browsers geven dus in ieder geval een afbeelding weer, als is dat misschien niet de meest optimale.

Maar ook voor nieuwere browsers is een <img> binnen <picture> verplicht. De browser zoekt binnen een van de <source>'s de meest geschikte afbeelding op. Die afbeelding wordt vervolgens als het ware in de <img> gestopt en gebruikt. Als de afbeelding 'zandkasteel-2000.jpg' wordt gebruikt ziet de code er eigenlijk als volgt uit:

<img src="117-pics/zandkasteel-2000.jpg" alt="Afbeelding 1">

Dit is in de code niet te zien, ook niet als de code wordt bekeken met behulp van het ontwikkelgereedschap van de browser (als code met behulp van JavaScript wordt gewijzigd, is dat daarin wel te zien).

Dit heeft twee voordelen: je kunt gewoon css gebruiken voor de <img>, ongeacht welke afbeelding wordt gebruikt. Zo wordt hier bijvoorbeeld bij img een border aan de afbeelding gegeven.

Het tweede voordeel: als je met JavaScript opvraagt, welke afbeelding wordt gebruikt, krijg je de naam en eigenschappen van de daadwerkelijk gebruikte afbeelding.

Als <img> ontbreekt binnen <picture>, zie je helemaal geen afbeelding.

Om aan de afbeelding een bijschrift te kunnen koppelen, is <picture> binnen een <figure> gezet. Hierdoor kan voor het bijschrift <figcaption> worden gebruikt, waarmee het bijschrift aan de <figure> is gekoppeld. Helaas is dit niet voldoende voor schermlezers.

Omdat onder de afbeelding een omschrijving in de <figcaption> staat, is er eigenlijk geen tekst in de alt van de <img> nodig. Een alt is echter verplicht. Als er geen beschrijving nodig is, moet je alt="" gebruiken als attribuut. Maar als je dat invult, negeren schermlezers de afbeelding volledig, omdat alt="" betekent, dat de afbeelding alleen voor opleuken wordt gebruikt, niet voor informatie.

Het bijschrift uit de <figcaption> wordt wel voorgelezen, maar dat hangt dan volledig in de lucht, omdat op geen enkele manier duidelijk is dat dit bij een afbeelding hoort.

Daarom is aan de <img> alt="Afbeelding 1" toegevoegd. Schermlezers lezen nu netjes 'Afbeelding 1' voor. En omdat de tekst in <figcaption> begint met 'Afbeelding 1', is duidelijk dat de tekst uit <figcaption> bij de afbeelding hoort.

Het zou natuurlijk veel logischer zijn als je gewoon alt="" bij een <img> in een <figure> zou kunnen gebruiken en de <img> aan de <figcaption> zou worden gekoppeld, maar dat gebeurt dus (nog) niet.

<figcaption>Afbeelding 1: de zandkastelen op de foto waren op 16 augustus 2008 in Den Haag te zien bij een demonstratie zandkastelen bouwen</figcaption>

Omdat <picture> binnen een <figure> staat, kan het onderschrift bij de afbeelding aan de <picture> worden gekoppeld met behulp van <figcaption>.

'Afbeelding 1' aan het begin is een koppeling naar de alt-tekst bij de <img>, de reden hiervan wordt uitgebreider besproken bij Om aan de afbeelding... iets hierboven.

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, enzovoort, 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. Op de pagina met links kun je onder Gereedschap → Snelheid, testen, gzip, comprimeren links naar sites vinden, waar je bestanden kunt comprimeren.

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

css voor alle vensters

/* afbeelding-117-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.

header

Alle <header>'s. Dat is er maar eentje. In <header> zit de korte uitleg over de afbeelding, die opent bij aanraken of ‑klikken van of hoveren over het vraagteken.

max-width: 1050px;

Maximumbreedte.

<header> is een blok-element, waardoor het normaal genomen even breed wordt als z'n ouder. Die ouder is hier <body>, ook een blok-element, dat normaal genomen ook weer even breed wordt als z'n ouder <html>. <html> is het buitenste element en wordt daardoor normaal genomen even breed als het venster van de browser.

<header> wordt hierdoor normaal genomen even breed als het venster van de browser. De <span> met het vraagteken staat links in <header>, waardoor het vraagteken normaal genomen links in het venster van de browser komt te staan.

De afbeelding kan niet breder worden dan 1000 px. Als het browservenster breder dan 1000 px is, kan het vraagteken (heel) ver links van de afbeelding komen te staan. Door de breedte van <header> te beperken, blijft het vraagteken ook op bredere vensters bij de afbeelding in de buurt staan.

De maximumbreedte is geen 1000 px, maar 1050 px, zodat het vraagteken deels buiten de afbeelding komt te staan. (Dat hele vraagteken zou je 'in het echt' nooit gebruiken, maar de uitleg moest ergens een plaats krijgen. En 'n marge zou te veel ruimte innemen, vandaar dat het deels over de afbeelding staat.)

margin: 0 auto;

Omdat voor onder en links geen waarde is ingevuld, 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. Hierdoor staat <header> altijd horizontaal gecentreerd binnen z'n ouder <body>.

<body> is een blok-element en wordt daardoor normaal genomen even breed als z'n ouder <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser. Hierdoor staat <header> altijd horizontaal gecentreerd binnen het venster, ongeacht hoe breed dit venster is.

Deze manier van horizontaal centreren van een blok-element werkt alleen, als het te centreren element een breedte heeft. Dat mag ook een maximumbreedte zijn, zoals hierboven opgegeven. Omdat die maximumbreedte 1050 px is, wordt het centreren pas zichtbaar in browservensters breder dan 1050 px.

position: relative;

Om nakomelingen van een element te kunnen positioneren ten opzichte van dat element, moet het element zelf zijn gepositioneerd. Omdat verder niets voor top en dergelijke wordt opgegeven, heeft dit verder geen enkele invloed op <header> zelf.

#voor-tab

Het element met id="voor-tab". De <input> speciaal voor gebruikers van de Tab-toets. Over de werking hiervan is meer te vinden bij <input id="voor-tab" aria-hidden="true">.

position: absolute;

Om de <input> te kunnen positioneren. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een positie heeft. Dat is hier <header>.

left: -10000px;

Ver links buiten het scherm parkeren. Deze <input> is alleen van belang voor gebruikers van de Tab-toets. Door de <input> links buiten het scherm te zetten, wordt de lay-out niet verpest.

Verbergen met display: none; of visibility: hidden; is geen goed idee, want dan negeert de Tab-toets de <input>. En daar is de <input> nou juist voor bedoeld.

#uitleg

Het element met id="uitleg". De <span> waarin het vraagteken zit. Bij aanraken of ‑klikken van of hoveren over dit vraagteken, opent de korte uitleg over de afbeelding.

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.

width: 1em;

Breedte.

em is gebaseerd op de lettergrootte binnen de <span>. Als de lettergrootte verandert, verandert de breedte van de <span> mee. Bij een absolute maat als px zou dat niet gebeuren. De hoogte wordt hier iets onder bij line-height geregeld.

font-size: 1.8em;

Grote 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.

line-height: 1em;

Regelhoogte.

em is gebaseerd op de lettergrootte binnen de <span>. Als de lettergrootte verandert, verandert de regelhoogte van de <span> mee. Bij een absolute maat als px zou dat niet gebeuren.

Omdat geen hoogte aan de <span> is gegeven, is dit gelijk ook de hoogte van de <span>. Iets hierboven is de breedte van de <span> ook 1 em gemaakt, waardoor de <span> vierkant is.

In dit geval heeft regelhoogte een voordeel boven hoogte. Tekst wordt automatisch verticaal gecentreerd binnen de regelhoogte. Het vraagteken staat nu verticaal netjes in het midden van de <span>.

text-align: center;

Tekst horizontaal centreren.

border: black solid 1px;

Randje.

border-radius: 0.5em;

Ronde hoeken. Omdat maar één maat is opgegeven, worden alle hoeken in beide richtingen 0,5 em lang. Dat is precies de helft van de breedte en hoogte van de <span>, waardoor een cirkel ontstaat.

em is gebaseerd op de lettergrootte binnen de <span>. Als de lettergrootte verandert, verandert de grootte van de hoeken mee. Bij een absolute maat als px zou dat niet gebeuren.

position: absolute;

Absoluut positioneren.

Omdat geen top en dergelijke worden opgegeven, komt de <span> met het vraagteken op dezelfde plaats te staan, als wanneer niet zou zijn gepositioneerd. Hier heeft een absolute positie twee voordelen. Hmmm, eigenlijk anderhalf, want het ene voordeel is niet zo groot.

De <span> neemt normaal genomen ruimte in beslag. Hierdoor komt de afbeelding ónder de <span> met het vraagteken te staan. Door de <span> absoluut te positioneren, trekt de afbeelding zich er niets meer van aan.

Dat was het ene hele voordeel. Het halve voordeel: een <span> is van zichzelf een inline-element. Daardoor zijn eigenschappen als breedte niet te gebruiken. Door de <span> absoluut te positioneren, verandert de <span> in een soort blok-element en zijn dit soort eigenschappen wel te gebruiken. Het telt maar half, omdat je dit ook zou kunnen bereiken met display: block; of display: inline-block;.

-moz-user-select: none; -ms-user-select: none; -webkit-user-select: none; user-select: none;

Hier staat in feite vier keer hetzelfde: user-select: none;. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.

Als op een touchscreen het vraagteken iets langer wordt aangeraakt, opent de uitleg niet, maar wordt het vraagteken geselecteerd. Dit maakt het onmogelijk het vraagteken te selecteren.

Vooral in Internet Explorer en Edge kan alleen een Olympisch deelnemer aan de kampioenschappen vinger terugtrekken selectie van het vraagteken voorkomen. Maar er is niets op tegen om dit ook in andere browsers te voorkomen, vandaar dat alle vormen van user-select worden gebruikt.

(O, niet aan gedacht: en een Olympisch deelnemer wíl natuurlijk helemaal geen selectie voorkomen.)

header p

Alle <p>'s in een <header>. Er is maar één <header> en daar staat maar één <p> in. De korte uitleg over de afbeelding zit erin.

Dit is een wat listige selector, want vaak zal er meer dan één <p> aanwezig zijn. Maar in dit geval kan het, want het is zeker dat er maar één <p> in <header> zit.

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.

width: 80%;

Breedte.

Een breedte in procenten is altijd ten opzichte van de ouder van het element. Dat is hier <header>, die even breed is als het venster van de browser. (Daar is meer over te vinden bij header onder max-width.) Het hulpschermpje heeft dus 80% van de breedte van het browservenster.

max-width: 20em;

Hier gelijk boven heeft het hulpvenstertje 80% van de breedte van het browservenster gekregen. In bredere vensters levert dat nauwelijks leesbare, veel te lange regels op. Daarom wordt hier de breedte begrensd.

Als eenheid is em genomen, want dat verandert mee met de lettergrootte. Bij een absolute eenheid als px is dat niet het geval.

border: black solid 1px;

Zwart randje.

padding: 5px;

Kleine afstand tussen tekst in en rand om de <p>.

position: absolute;

Om het hulpvenstertje op de juiste plaats neer te kunnen zetten. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een positie heeft. Dat is hier <header>.

top: -16px;

Op deze hoogte komt de bovenkant van het hulpschermpje gelijk te staan met de bovenkant van de afbeelding.

-webkit-transform: translateX(-20000px); transform: translateX(-20000px);

Hier staat in feite twee keer hetzelfde: translateX(-20000px);. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.

Met behulp van de transform-functie translateX() kan een element horizontaal worden verplaatst. In dit geval wordt de <p> ver links buiten het scherm geparkeerd. Pas bij aanraken of ‑klikken van of hoveren over het vraagteken wordt de <p> binnen het scherm gezet en daardoor zichtbaar.

Dit kan ook met position: absolute; worden bereikt, maar transform is veel makkelijker voor de browser, wat voor mobieltjes en dergelijke niet onbelangrijk is.

Verbergen met display: none; of visibility: hidden; kan ook, maar dan negeren schermlezers de <p> volledig, waardoor gebruikers van een schermlezer de hulp niet meer kunnen horen.

#voor-tab:focus ~ p, #uitleg:hover + p, header p:hover

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.

header p {background: white; color: black; width: 80%; max-width: 20em; border: black solid 1px; padding: 5px; position: absolute; top: -16px; -webkit-transform: translateX(-20000px); transform: translateX(-20000px);}

Hier staan drie selectors, gescheiden door een komma.

De eerste selector, voor de eerste komma: #voor-tab:focus ~ p:

#voor-tab:focus: als het element met id="voor-tab" focus heeft. input#voor-tab is een speciaal voor gebruikers van de Tab-toets aangebrachte <input>. Als mensen niet de muis, maar de Tab-toets gebruiken om links, tekstvelden, en dergelijke te bezoeken, zouden die de uitleg nooit kunnen openen zonder deze <input>. Meer hierover is te vinden bij Tabindex.

~: het hierachter staande element moet ergens in de html staan, na het voor de ~ staande element. Het hoeft er, anders dan bij de +, niet gelijk op te volgen, als het maar ergens na het eerste element in de html staat.

De enige voorwaarde is verder dat het voor en het na de ~ staande element dezelfde ouder hebben. Dat is hier het geval: #voor-tab voor de ~ en p na de ~ hebben beide als ouder <header>.

p: alle <p>'s. Dat is er hier maar eentje, want er is maar één <p> die dezelfde ouder heeft als input#voor-tab. In deze <p> zit de korte uitleg bij de afbeelding.

De tweede selector, tussen de komma's: #uitleg:hover + p:

#uitleg:hover als over het element met id="uitleg" wordt gehoverd. In span#uitleg zit het vraagteken. Op een touchscreen kun je niet hoveren, maar op iOS en Android opent de pop-up toch bij aanraken van het vraagteken. Bij iOS is wat JavaScript nodig, omdat de pop-up niet opent. Op touchscreens met Windows is de WAI-ARIA-code aria-haspopup nodig om de pop-up te kunnen openen.

+: het hierachter staande element moet in de html gelijk na het voor de + staande element staan. Voor de + staat #uitleg, achter de + staat p, dus het gaat om de <p> die gelijk na span#uitleg in de html staat. Dit is de <p>, waar de korte uitleg bij de afbeelding zit.

p: alle <p>'s. Dat is er hier maar eentje, want er is maar één <p> die in de html direct op span#uitleg volgt.

De derde selector, na de tweede komma: header p:hover:

header p: alle <p>'s in een <header>. Dat is er hier maar eentje: de <p> waar de korte uitleg over de afbeelding in zit.

:hover: als over deze <p> wordt gehoverd. Dit is alleen van belang als een muis wordt gebruikt.

Als over het vraagteken wordt gehoverd, opent het hulpschermpje. Maar de <span> waar dat vraagteken in zit is klein. Als je van die <span> afglipt, sluit de pop-up weer. Nu blijft het schermpje ook open, als over het schermpje zelf wordt gehoverd.

Alles bij elkaar: als input:voor-tab focus heeft, of als over span#uitleg met het vraagteken wordt gehoverd, of als over de <p> met het hulpschermpje wordt gehoverd, doe dan iets met de <p> met het hulpschermpje.

-webkit-transform: translateX(25px); transform: translateX(25px);

Hier staat in feite twee keer hetzelfde: translateX(25px);. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.

Bij header p is de <p> met het hulpschermpje ver links buiten het scherm geparkeerd, waardoor het onzichtbaar is. Hier wordt de <p> met het hulpschermpje op het scherm gezet.

figure

Alle <figure>'s. Dat is er hier maar eentje: de afbeelding zit erin.

display: block;

<figure> is een blok-element. Maar oudere browsers kennen het niet, en onbekende elementen zijn standaard inline-elementen. Daardoor kan een eigenschap als breedte niet worden gebruikt. Door van <figure> hier expliciet een blok-element te maken, is het in alle browsers een blok-element.

width: 90%;

Breedte.

Een breedte in procenten is altijd ten opzichte van de ouder van het element. Dat is hier <main>. <main> is een blok-element en wordt daardoor normaal genomen even breed als z'n ouder <body>. Ook <body> is een blok-element en wordt daardoor normaal genomen even breed als z'n ouder <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser.

<figure> krijgt hierdoor een breedte van 90% van het browservenster.

max-width: 1000px;

De breedste afbeelding wordt op een breedte van 1000 px weergegeven. <figure> heeft hier gelijk boven een breedte van 90% van het browservenster gekregen. In bredere vensters wordt <figure> daardoor breder dan 1000 px. In een venster van bijvoorbeeld 1280 px breed wordt <figure> 90% daarvan, dat is 1152 px breed.

In <figure> zit in <figcaption> een onderschrift bij de afbeelding. <figcaption> wordt even breed als <figure> en zou daardoor breder dan de afbeelding worden. Door de breedte van <figure> te beperken tot de breedte van de breedste afbeelding, wordt dit voorkomen.

line-height: 0; Afbeelding 6: regelhoogte veroorzaakt kier tussen afbeelding en onderschrift

Op de afbeelding hiernaast is de achtergrond van de pagina rood gemaakt, zodat de kier tussen afbeelding en onderschrift duidelijker is te zien. Die kier ontstaat, als je de regelhoogte niet weghaalt. 'n Beruchte kier, die hele volksstammen tot wanhoop heeft gedreven, want je zoekt je soms ongans naar waar die vermaledijde kier vandaan komt. De reden daarvan kun je namelijk snel over het hoofd zien.

Een afbeelding is een inline-element. Een bijzonder inline-element, maar het blijft een inline-element. Ook tekst is een inline-element. Omdat sommige letters iets onder de tekst uitsteken, wordt wat ruimte vrijgelaten onder de tekst. Dat gebeurt ook, als de 'tekst' alleen uit een afbeelding bestaat.

Door de regelhoogte weg te halen, verdwijnt de kier.

text-align: center;

Tekst in de <figure> horizontaal centreren. Feitelijk niet alleen tekst, maar alle inline-elementen. Maar het effect is alleen zichtbaar bij het onderschrift in de <figcaption>.

margin: 10px auto 0;

Omdat voor links geen waarde is ingevuld, krijgt links automatisch dezelfde waarde als rechts. Hier staat dus eigenlijk 10px auto 0 auto in de volgorde boven – rechts – onder – links.

Aan de bovenkant een kleine marge tussen de bovenkant van het browservenster en <figure> met de daarin zittende afbeelding.

Links en rechts auto, wat hier hetzelfde betekent als evenveel. Hierdoor staat <figure> altijd horizontaal gecentreerd binnen 'n ouder <main>. <main> is een blok-element en wordt daardoor normaal genomen even breed als z'n ouder <body>. Ook <body> is een blok-element en wordt daardoor normaal genomen even breed als z'n ouder <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser.

<figure> staat hierdoor horizontaal gecentreerd binnen het venster van de browser.

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

img

Alle afbeeldingen. Dat is er hier maar eentje.

Als de browser binnen een van de <source>'s een afbeelding heeft gevonden die gebruikt gaat worden, wordt deze afbeelding feitelijk binnen <img> gezet. Hierdoor werkt css voor <img> ongeacht welke afbeelding wordt gebruikt. En als je met JavaScript de naam van de gebruikte afbeelding opvraagt, krijg je de naam van de daadwerkelijk gebruikte afbeelding.

Een uitgebreider verhaal over <img> is te vinden bij <img src="117-pics/zandkasteel-1000.jpg" alt="Afbeelding 1">.

box-sizing: border-box;

Normaal genomen komen padding en border bij de breedte van het element. Hier gelijk onder wordt een maximumbreedte van 100% opgegeven. Daardoor wordt de <img> nooit breder dan <figure>. (<picture>, dat tussen <figure> en <img> inzit, is een wat eigenaardig element dat hierin geen rol speelt.)

Iets hieronder wordt een border aan <img> gegeven. Daardoor komt er links en rechts 1 px bij de breedte van de <img>, waardoor deze 2 px breder wordt dan de <figcaption> met het onderschrift.

In dit geval is het daarom makkelijker als de border rondom <img> binnen de breedte komt te staan. <img> en <figcaption> blijven dan even breed en sluiten netjes op elkaar aan.

max-width: 100%;

Een breedte in procenten is altijd ten opzichte van de ouder van het element. Die ouder is hier <picture>. Maar <picture> is een wat vreemd element, omdat het alleen bedoeld is om de <source>'s aan de <img> te koppelen. Bovendien is het een inline-element, waardoor het feitelijk geen eigen breedte heeft: het wordt even breed als de <img> die erin zit. Hierdoor is dit een zeldzame uitzondering: de maximumbreedte is hier niet ten opzichte van de ouder <picture>, maar ten opzichte van <figure>, de ouder van <picture>.

In de verschillende <source>'s is de breedte opgegeven, waarop de afbeelding moet worden weergegeven. Bij een browservenster maximaal 600 px breed in portretstand is dat bijvoorbeeld 600 px. Maar als het venster maar 400 px breed is, moet je scrollen om de hele afbeelding te kunnen zien, als die afbeelding 600 px breed is.

Daarom wordt met deze maximumbreedte de breedte van de afbeelding beperkt tot de breedte van <figure>, zoals die is opgegeven bij figure.

In een browservenster met een breedte van 400 px wordt in principe de afbeelding van 600 px breed gebruikt, maar die wordt nu versmald tot 400 px. De browser past ook de hoogte automatisch aan, zodat een lachspiegeleffect wordt voorkomen.

border: black solid 1px;

Zwart randje rondom de afbeelding.

figcaption

Alle <figcaption>'s. Dat is er hier maar eentje. Het onderschrift onder de afbeelding staat erin.

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.

line-height: normal;

Bij figure is de regelhoogte op 0 gezet. Dat geldt ook voor <figcaption>, want de regelhoogte wordt geërfd. Bij de tekst hier moet de regelhoogte weer de standaardhoogte van ongeveer 1,2 em krijgen.

border: black solid 1px;

Zwart randje.

border-top: none;

Aan de bovenkant staat <figcaption> tegen de afbeelding. Die heeft bij img een rand rondom gekregen. Als <figcaption> aan de bovenkant ook een rand zou hebben, staan daar twee randen van 1 px dik tegen elkaar aan, waardoor daar een rand van 2 px komt te staan. Daarom wordt de rand aan de bovenkant weggehaald.

padding: 10px 5px;

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

Aan alle kanten wat ruimte tussen rand om en tekst in de <figcaption>. Boven en onder iets meer, omdat de <figcaption> anders bij weinig tekst wat zielig oogt.

css voor vensters minimaal 601 px hoog, maximaal 800 px hoog en minimaal aspect-ratio 5/4

@media screen and (min-width: 601px) and (max-height: 800px) and (min-aspect-ratio: 5/4)

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

De css die binnen deze media query staat, geldt alleen voor browservensters die minimaal 601 px breed, maximaal 800 px hoog én minimaal een aspect-ratio van 5/4 hebben. In deze vensters is de afbeelding te hoog, daarom wordt de grootte van de afbeelding aangepast. In deze media query wordt de breedte van <figure> aangepast, zodat het onderschrift in <figcaption> niet breder dan de afbeelding wordt.

@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: 601px): het browservenster moet minimaal 601 px breed zijn. Is het venster smaller, dan wordt de css die binnen deze media-regel staat genegeerd.

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

(max-height: 800px): het browservenster mag hoogstens 800 px hoog zijn. Is het venster hoger, dan wordt de css die binnen deze media-regel staat genegeerd.

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

(min-aspect-ratio: 5/4): aspect-ratio is de verhouding tussen breedte en hoogte van het browservenster. Als die kleiner is dan 5/4, dan wordt de css die binnen deze media-regel staat genegeerd.

(Bij de eerste <source> staat een uitgebreidere uitleg van de reden van deze media query. Ook staat daar een uitleg over aspect-ratio.)

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: 601px) and (max-height: 800px) and (min-aspect-ratio: 5/4) { 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 }.

Soms lijkt het erop dat een scherm en/of browservenster binnen een media query zouden moeten vallen, terwijl dat toch niet gebeurt. Als je 'n mobieltje hebt met een resolutie van – ik roep maar wat – 1024 x 768 px, dan zou dat binnen bijvoorbeeld een media query voor een minimale breedte van 760 px moeten gelden. Toch gebeurt dat soms niet. 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 ruim onder de 760 px van de media query. 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.

figure

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.)

figure {display: block; width: 90%; max-width: 1000px; line-height: 0; text-align: center; margin: 10px auto 0;}

Alle <figure>'s. Dat is er hier maar eentje: de afbeelding zit erin.

width: 60%; width: 100vh;

Hier wordt twee keer de breedte opgegeven. De eerste keer met als eenheid het al jaren bestaande %, de tweede keer met de nieuwere eenheid vh.

Elke browser kent de eenheid %, dus dat werkt in alle browsers. Browsers die de eenheid vh kennen, gebruiken de tweede breedte, omdat die later in de css staat. En wat later in de css staat, overrulet in de regel wat eerder in de css staat.

UC browser op Android, oudere versies van Android browser en sommige versies van Opera Mini op Android kennen vh niet. Deze browsers negeren de tweede breedte en gebruiken de 60% uit de eerste breedte.

Bij de eerste <source> wordt de breedte, en daarmee ook de hoogte, van de afbeelding aangepast aan browservensters die minimaal 600 px breed zijn en tegelijk relatief laag, zoals laptops. Anders kan de afbeelding in de hoogte niet zonder scrollen worden bekeken.

Onder de afbeelding staat in <figcaption> een onderschrift. Dit onderschrift is even breed als de afbeelding. Als de breedte van de afbeelding wordt aangepast, maar niet de breedte van de <figcaption>, steekt het onderschrift links en rechts buiten de afbeelding uit.

Bij de eerste <source> wordt de afbeelding in de hierboven genoemde browservensters smaller, en daarmee ook lager, weergegeven. Door <figure> in deze brede, maar lage browservensters precies dezelfde breedte te geven als de afbeelding, wordt ook <figcaption>, een kind van <figure>, even breed als de afbeelding. Daardoor sluiten onderschrift en afbeelding netjes op elkaar aan.

Het probleem bij de afbeelding zit in de hoogte. De breedte past wel, maar de afbeelding is te hoog. 100 vh is de hoogte van het browservenster. Als dat venster bijvoorbeeld 500 px hoog is, is 100 vh hetzelfde als 500 px. Door de afbeelding in zo'n venster te versmallen tot 500 px, wordt ook de hoogte van de afbeelding automatisch minder. Hierdoor passen afbeelding en onderschrift binnen het venster.

Hoe lager het browservenster, hoe lager de waarde van 100 vh. Als 100 vh minder is, is de breedte van de afbeelding ook minder. En omdat ook de hoogte automatisch wordt verminderd, passen afbeelding en onderschrift binnen het venster. (Onder sizes bij de eerste <source> staat een uitgebreider verhaal over vh en dergelijke.)

Voor browsers die vh niet kennen, wordt als breedte 60% genomen. Dat is minder netjes dan 100 vh, omdat het probleem in de hoogte zit. En de 60% geldt ten opzichte van de breedte. Soms zal 60% te veel zijn, soms te weinig. Maar in ieder geval is de hele afbeelding inclusief onderschrift nu zonder scrollen te zien.

Een breedte in procenten is altijd ten opzichte van de ouder van het element. Dat is hier <main>. <main> is een blok-element en wordt daardoor normaal genomen even breed als z'n ouder <body>. <body> is ook een blok-element en wordt daardoor normaal genomen ook even breed als z'n ouder <html>. <html> is het buitenste element en wordt daardoor normaal genomen even breed als het venster van de browser. De breedte van 60% van <figure> is hierdoor ten opzichte van het venster van de browser.

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.

<script> document.getElementsByTagName("body")[0].addEventListener("touchstart", function () {return null; }); </script>

iOS heeft nogal moeite met het omzetten van :hover en dergelijke naar aanrakingen op een touchscreen. Applefans zullen ongetwijfeld zeggen dat het veel beter werkt dan op andere systemen, maar normale mensen worden er knettergestoord van.

Zonder deze code opent en sluit, behalve in Firefox en Opera Mini, de pop-up niet.

<script> en </script>

Dit is gewone html: het zijn de openings- en sluittag voor het script. In html5 is de toevoeging type="text/javascript" niet meer nodig.

document.getElementsByTagName("body")[0].addEventListener("touchstart", function () {return null; }):

document.getElementsByTagName("body"): zoek naar de elementen met de tag <body>. Jij en ik weten dat er maar één <body> is, maar een browser is nou eenmaal niet zo slim, dus die zoekt trouwhartig naar álle <body>'s. En vindt er uiteraard maar eentje.

[0]: de gevonden tags worden geretourneerd in de vorm van een lijst. Als er bijvoorbeeld honderd <div>'s zouden worden gevonden, heeft deze lijst honderd ingangen. Zo'n ingang kun je aanspreken door het volgnummer te gebruiken. En omdat computers dol zijn op '0', is het volgnummer van de eerste ingang '0', en geen '1'.

Uiteraard is er maar één <body> gevonden. Het volgnummer van die <body> is dus '0', de eerste ingang.

document.getElementsByTagName("body")[0]: beide samen: doe iets met het element <body>.

addEventListener: voeg aan <body> een 'eventlistener' toe. Dat is een ding dat luistert, of er iets gebeurt. Zo'n gebeurtenis kan een aanraking van het scherm zijn, een liefdevolle aai van de muis, een ram op het toetsenbord, van alles.

"touchstart": in dit geval wordt naar het begin van een aanraking van het touchscreen geluisterd. Dat is nog niet zo interessant, het wordt pas echt opwindend wat er ná die eerste, inleidende aanraking gaat gebeuren... Vinden zij elkaar, of wordt het moord- en doodslag?

function () {return null; }: helaas, ze vinden elkaar niet én het wordt geen moord- en doodslag.

function() is gewoon een soort aankondiging dat er iets gaat gebeuren. Erachter tussen de accolades staat, wat er gaat gebeuren: return null;. Doe niets. Helemaal niets. Vanavond niet, schat, ik heb hoofdpijn. Of, afhankelijk van opvoeding, omgeving, enz.: blijf met je gore rotpoten van me af, viespeuk.

Dit script is gekoppeld aan <body>, maar je zou het ook kunnen koppelen aan span#uitleg met het vraagteken. Daarvoor hoef je alleen getElementsByTagName("body")[0] te vervangen door getElementById("uitleg"). ([0] is niet meer nodig, want er is maar één element met een bepaald id.)

De pop-up opent nu wel, maar sluit pas als een ander element zoals een link of tekstveld focus krijgt. Door dit script aan <body> te koppelen, opent de pop-up bij aanraken van het vraagteken, en sluit weer als het scherm ergens buiten de pop-up wordt aangeraakt.