Skip links en inhoudsopgave

Navigatie site

Naar begin tekstSla alle (onzichtbare) links in de inhoud over en ga naar het begin van de tekst

Eerste actie geeft meer infor­matie, tweede actie volgt link - uitleg

Laatst aangepast: .

Het raster met thumbnails met één thumbnail vergroot

Korte omschrijving

Bij hoveren over, aanraken van of tabben naar de thumbnail wordt meer informatie getoond. Bij klikken op of nogmaals aanraken van de thumbnail, of door Enter in te drukken, wordt de link achter de thumbnail gevolgd.

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.

Als je deze handleiding graag uitprint (zonde van het bos), gebruik dan de pdf in de download. Deze pagina is niet geoptimaliseerd voor printen, de pdf kan wel makkelijk worden geprint.

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 Visual Studio Code, 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:
Naar site van War Child Nederland

Achterliggend idee

Een serie kleine thumbnails wordt vertoond, waarop een afbeelding van – in dit geval – een voorbeeld op de site is te zien. De bedoeling is dat in eerste instantie wat extra informatie verschijnt in de vorm van een iets grotere thumbnail en een korte omschrijving. Daarna kan dan eventueel een link naar het betreffende voorbeeld worden gevolgd. (Omdat dat vrij zinloos is in dit voorbeeld, wordt een link naar lege hulppagina's gevolgd.)

Een simpel idee, dat iets minder simpel uit is te voeren.

Als je alleen rekening houdt met een muis, is het simpel. Zet in een link een afbeelding en als over de link wordt gehoverd, toon dan de extra informatie. Bij een klik wordt de link gevolgd.

Dat werkt echter niet op touchscreens. Soms verschijnt geen extra informatie en wordt de link gelijk gevolgd. Soms verschijnt wel extra informatie, maar wordt de link vervolgens alsnog gelijk gevolgd. En soms werkt het zoals bedoeld. Dit is afhankelijk van besturingssysteem en browser. Kortom: een zootje ongeregeld waar zelfs een cum laude geslaagd anarchist diep ongelukkig van wordt. Het wordt dus iets ingewikkelder.

Elke thumbnail staat met de bijbehorende link in een eigen <div>. De omschrijving van de thumbnail staat in een <span> binnen die link.

De link zelf wordt in eerste instantie verborgen, zodat op touchscreens alleen de thumbnail wordt aangeraakt. Pas als over de thumbnail wordt gehoverd, of als deze wordt aangeraakt, wordt de link getoond. Dat verbergen van de link gebeurt niet met iets als display: hidden;, want dan negeren schermlezers de link. Het verbergen gebeurt door de link 0,1 x 0,1 px groot te maken. Pas als over de thumbnail wordt gehoverd, of als deze wordt aangeraakt, wordt de link even groot gemaakt als de thumbnail en daaroverheen gezet. Als de thumbnail nogmaals wordt aangeraakt of wordt aangeklikt, wordt nu feitelijk de boven de thumbnail staande (onzichtbare) link aangeraakt of -geklikt, en dus gevolgd.

(Waarom 0,1 x 0,1 px en geen 0 x 0? Dat komt door het fantastische werk van de Vereniging ter Bevordering van de Verschillen Tussen Browsers. Enkele browsers negeren de link helemaal, als deze 0 x 0 px is. Er zijn tal van dit soort kleine aanpassingen nodig voor enkele ellendepukkels, pardon browsers. Andere browsers blijken bijvoorbeeld een link van 0,1 x 0,1 px juist altíjd gelijk te volgen. Bij de beschrijving van de code worden dit soort aanpassingen vermeld.)

De in de link staande omschrijving van de thumbnail wordt gelijktijdig met het plaatsen van de link onder de thumbnail gezet. Omdat die omschrijving in een eigen <span> binnen de link zit, kan die omschrijving op precies de juiste plaats worden neergezet. Terwijl de link toch de hele thumbnail kan bedekken.

Dit blijkt te werken.

Schermlezers lezen de alt-tekst bij de thumbnail voor, gevolgd door de tekst in de link.

Gebruikers van de Tab-toets kunnen met de Tab-toets van link naar link gaan. Als een link focus heeft, kan de tekst uit de link worden getoond. Met behulp van de selector div:focus-within (als een element binnen de <div> focus heeft) kan de in dezelfde <div> zittende thumbnail worden vergroot. Bij indrukken van Enter wordt de link desgewenst gevolgd.

Bij hoveren over de thumbnail kan de thumbnail worden vergroot en de gelijk achter de thumbnail zittende link boven de thumbnail worden gezet. De omschrijving in de <span> in de link wordt onder de thumbnail gezet.

Op een touchscreen gebeurt bij de eerste aanraking van de thumbnail hetzelfde als bij hoveren over de thumbnail. (Als bij een element :hover en :focus worden gebruikt, levert dat op een touchscreen vaak problemen op. Omdat hier alleen :hover wordt gebruikt, speelt dat niet.) Bij de tweede aanraking wordt in feite de link aangeraakt en wordt die dus gevolgd.

Oudere browsers, Internet Explorer en Edge ondersteunen :focus-within niet. Om dit te simuleren, is een beetje JavaScript nodig. In principe werkt dit voorbeeld ook zonder JavaScript, maar het werkt dan niet goed voor gebruikers van de Tab-toets in die browsers.

Voor Internet Explorer en Edge op touchscreens waren enkele WAI-ARIA-codes nodig.

Voorwaarden waaraan de html moet voldoen

Om dit voorbeeld in alle browsers op alle systemen ook voor gebruikers van de Tab-toets toegankelijk te maken, wordt gebruik gemaakt van de pseudo-class :focus-within. Oudere browsers en Internet Explorer en Edge ondersteunen dit niet. Voor deze browsers wordt :focus-within met behulp van een beetje JavaScript geïmiteerd.

Los hiervan zijn voor Internet Explorer en Edge op touchscreens enkele WAI-ARIA-codes nodig.

Hieronder staat een overzichtje van de voorwaarden, waaraan de html moet voldoen.

Structuur en id's

Om het script goed te laten werken, moet de html aan enkele simpele voorwaarden voldoen. Als je je daar niet aan houdt, moet je het script (en soms ook de css) aanpassen. Op de plaatsen waar die wijzigingen nodig zijn, staat dat aangegeven bij de uitleg van het script.

De opbouw van de hele constructie moet als volgt zijn:

<div id="wrapper"> <div><img><a></a></div> (...) andere <div>'s (...) <div><img><a></a></div> </div>
  • De hele constructie moet in een element met id="wrapper" staan. Dat is in het voorbeeld een <div>, maar het mag ook een <section> of zoiets zijn, als de id maar 'wrapper' is.
  • Elke <img> met z'n bijbehorende <a> moeten een direct kind van dezelfde <div> zijn.
  • Elke <a> moet direct volgen op de <img>, waar deze bij hoort. Samen met de voorwaarde gelijk hierboven levert dat dus de regel <div><img><a></a></div> op. Bínnen elke <a> en <img> kun je doen en laten wat je wilt, als <a> en <img> maar gelijk op elkaar volgen.

WAI-ARIA-codes

Bij div#wrapper wordt de WAI-ARIA-code aria-haspopup="true" gebruikt. Bij elke <a> wordt de WAI-ARIA-code aria-haspopup="false" gebruikt. Deze hebben hier eigenlijk geen functie, maar zijn nodig voor Internet Explorer 11 en Edge op touchscreens. Deze codes worden besproken bij WAI-ARIA-codes.

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

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.

In dit voorbeeld worden hyphens en transform gebruikt.

hyphens

Op dit moment moet je nog het volgende schrijven:

{-ms-hyphens: ...; -webkit-hyphens: ...; hypens: ...;}

In de toekomst kun je volstaan met:

{hypens: ...;}

transform

Op dit moment moet je nog het volgende schrijven:

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

In de toekomst kun je volstaan met:

{transform: ...;}

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

Door het op de goede manier gebruiken van semantische elementen, kunnen zoekmachines, schermlezers, enzovoort 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 wordt hiervan alleen <main> gebruikt. <main> gedraagt 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. De meeste schermlezers kunnen dit soort elementen ook gebruiken om snel over de pagina te navigeren.

<main>

Hierbinnen staat de belangrijkste inhoud van de pagina (in dit voorbeeld is dat alleen de constructie met thumbnails en links).

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

<main role="main">

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

WAI-ARIA-codes

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

Er worden in dit voorbeeld één WAI-ARIA-code gebruikt: aria-haspopup.

aria-haspopup

Elke thumbnail en bijbehorende link zitten in een eigen <div>. Die <div>'s zitten met z'n allen weer in een div#wrapper.

Als op een touchscreen een thumbnail wordt aangeraakt, moet de thumbnail worden vergroot, het onderschrift moet eronder worden gezet en de link moet boven de thumbnail worden gezet.

In Internet Explorer en Edge op Windows en Windows 10 Mobile, en in UC Browser op Windows 10 Mobile, gebeurt dit echter niet. De thumbnail wordt even groter, maar dat verdwijnt gelijk weer, en met link en onderschrift gebeurt helemaal niets.

Door het toevoegen van aria-haspopup="true" aan div#wrapper werkt het wel:

<div id="wrapper" aria-haspopup="true">

Nu moet je in deze browsers echter de link twee keer aanraken, voordat de link wordt gevolgd. De sukkels denken nu dat élke link een pop-up heeft. De eerste aanraking is om die (niet-bestaande) pop-up te openen, de tweede om de link te volgen. Dit wordt opgelost door aan elke <a> aria-haspopup="false" toe te voegen:

<a href="127-files-dl/lay-out-1-dl.html" aria-haspopup="false">

Nu wordt een link met één aanraking gevolgd.

Volgens de WAI-ARIA-specificatie 1.0 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.

In versie 1.1 van de specificatie is de waarde 'true' bij aria-haspopup vervallen, maar wordt vanwege terugwaartse compatibiliteit met versie 1.0 nog wel gedefinieerd op eenzelfde wijze als in versie 1.0. Hiermee lijken mogelijke toekomstige problemen voor dit oneigenlijke gebruik te worden voorkomen. Versie 1.2 is nog een ontwerp-specificatie, maar ook hierin is dit hetzelfde.

(Waar je die aria-haspopup's neer moet zetten, hoort trouwens tot de Grote Raadselen der Kosmos. Je zou denken dat aria-haspopup="true" bij de <div> met de thumbnail, of bij de <img> zou moeten staan. Dat heeft echter geen effect. En waarom er dan bij de <a> aria-haspopup=​"false" moet staan, is helemaal een raadsel, want bij die <a> wordt in de css helemaal geen :hover of zoiets gebruikt.)

Tabindex en Tab-toets

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

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

In dit voorbeeld hoeft tabindex niet te worden gebruikt. Als een link focus krijgt, wordt de voor die link staande thumbnail vergroot met behulp van de selector div:focus-within. Deze tamelijk onbekende selector kijkt, of een element bínnen de <div> focus heeft. Zodra de <a> binnen een <div> de focus krijgt, werkt deze selector. En kan dus met behulp van div:focus-within img iets met de <img> binnen de <div> worden gedaan.

Omdat de Tab-toets standaard al alle <a>'s bezoekt, is een tabindex niet nodig.

Voor oudere browsers en Internet Explorer en Edge, die :focus-within niet ondersteunen, wordt dit gesimuleerd met behulp van een beetje JavaScript.

Muis, toetsenbord, touchpad en touchscreen

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. Een touchpad werkt ongeveer hetzelfde als een muis. Als hieronder iets over een muis staat, geldt dit ook voor een touchpad.

: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. Als een element iets anders moet doen bij aanraken dan bij hoveren, ontstaan hierdoor vaak problemen op touchscreens, vooral op iOS.

Omdat die combinatie van aanraken en hover bij hetzelfde element in dit voorbeeld niet voorkomt, speelt dit soort problemen niet.

(In Internet Explorer en Edge op Windows en Windows 10 Mobile, en in UC Browser op Windows 10 Mobile speelt bij aanraken wel een ander probleem. Dit wordt opgelost met een WAI-ARIA-code.)

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

Er is echter 'n tweede manier om naar links, invoervelden, en dergelijke te gaan: 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 en Tab-toets.)

Waar je staat, wordt door alle browsers aangegeven met een of ander kadertje. De link en dergelijke met het kadertje eromheen 'heeft focus'. Dat wil zeggen dat je die link volgt, als je op de Enter-toets drukt, of dat je in dat veld tekst kunt gaan invoeren, enzovoort.

Het kadertje dat de focus aangeeft, moet nooit zonder meer worden weggehaald. Gebruikers van de Tab-toets hebben dan geen idee meer, waar ze zijn. In dit voorbeeld maakt dit echter weinig uit, omdat de focus op een andere manier wordt aangegeven: de thumbnail is vergroot en van een border en onderschrift voorzien.

In dit voorbeeld wordt, voor gebruikers van de Tab-toets, gebruikt gemaakt van de pseudo-class :focus-within.

Elke <a> staat binnen een <div>. Zodra een <a> met behulp van de Tab-toets focus heeft gekregen, kan bij die <div> de selector div:focus-within worden gebruikt: een element binnen de <div> heeft focus.

:active

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

Een element is actief, als de muis wordt ingedrukt boven dat element. Op sommige touchscreens is het element actief, als het wordt aangeraakt. :active wordt niet gebruikt in dit voorbeeld.

Gegenereerde code

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

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

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

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

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

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

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

De code aanpassen aan je eigen ontwerp

Toegankelijkheid en zoekmachines

De tekst in dit hoofdstukje is een algemene tekst, die voor elke pagina geldt. Eventueel specifiek voor dit voorbeeld geldende problemen en eventuele aanpassingen om die problemen te voorkomen staan bij Bekende problemen (en oplossingen).

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:

Getest in

Laatst gecontroleerd op 5 augustus 2019.

Onder dit kopje staat alleen maar, hoe en waarin is getest. Alle eventuele problemen, ook die met betrekking tot zoomen, lettergroottes, toegankelijkheid, uit staan van JavaScript en/of css, enzovoort staan iets 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!

Dit voorbeeld is getest op de volgende systemen:

Desktopcomputers

Windows 7 (1280 x 1024 px, resolution 96 dpi):
Firefox, UC Browser, Google Chrome, Opera en Internet Explorer 11, in grotere en kleinere browservensters.

OS X 10.11.6 ('El Capitan') (1680 x 1050 px, resolution: 96: dpi, device-pixel-ratio: 1):
Firefox, Safari, Opera en Google Chrome, in grotere en kleinere browservensters.

Linux (Kubuntu 18.04 LTS, 'Bionic Beaver') (2560 x 1080 px, resolution: 96 dpi):
Firefox, Opera en Google Chrome, in grotere en kleinere browservensters.

Laptops

Windows 8.1 (1366 x 768 px, resolution: 96 dpi):
Bureaublad-versie: Firefox, UC Browser, Google Chrome, Opera en Internet Explorer 11, in grotere en kleinere browservensters.
Startscherm-versie: Internet Explorer 11.

Windows 10 (1600 x 900 px, resolution: 96 dpi):
Firefox, UC Browser, Google Chrome, Opera, Internet Explorer 11 en Edge, in grotere en kleinere browservensters.

Tablets

iPad met iOS 9.3.5 (1024 x768 px, device-pixel-ratio: 1):
Safari, Chrome for iOS, UC Browser, Firefox (alle portret en landschap).
Opera Mini (Opera Turbo) portret en landschap.

iPad met iOS 12.4 (2048 x 1536 px, device-pixel-ratio: 2 ('retina'):
Safari, Chrome for iOS, Firefox, Microsoft Edge (alle portret en landschap).
Opera Mini (Opera Turbo) portret en landschap.

Android 4.4.2 ('Kitkat') (1280 x 800 px, resolution: 96 dpi):
UC Browser, Firefox, Opera en Chrome (alle portret en landschap).

Android 4.4.2 ('Kitkat') (2560 x 1600 px, resolution: 192 dpi):
Android browser, UC Browser, Firefox, Opera en Chrome (alle portret en landschap).

Android 6.0 ('Marshmallow') (1920 x 1200 px, resolution: 144 dpi):
Dolphin, Samsung Internet, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Android 9.0 ('Pie') (1920 x 1200 px, resolution: 144 dpi):
Dolphin, Samsung Internet, UC Browser, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

Smartphones

Windows 10 Mobile (1280 x 720 px, resolution: 192 dpi):
Edge en UC browser (portret en landschap).

Android 4.1.2 ('Jelly Bean') (800 x 480 px, resolution: 144 dpi):
Chrome, UC Browser, Opera en Firefox (alle portret en landschap).

Android 8.1.0 ('Oreo') (1280 x 720 px, resolution: 192 dpi):
Dolphin, Samsung Internet, UC Browser, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.

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- en uitzoomen en – voor zover de browser dat kan – een kleinere en grotere letter zijn ook 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 iOS, Android en Windows 10 Mobile, waar een touchscreen is gebruikt. Op Windows 8.1 en 10 is getest met touchscreen, touchpad, toetsenbord, muis, en – waar dat zinvol was – op een combinatie daarvan.

Als JavaScript is gebruikt, is op de desktop ook getest zonder JavaScript. Op iOS, Android 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. Ook in Edge is niet getest zonder JavaScript, omdat Microsoft het onmogelijk heeft gemaakt dit uit te zetten. Ten slotte is getest zonder css en – als afbeeldingen worden gebruikt – zonder afbeeldingen.

Schermlezers en dergelijke.

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

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 Windows7. (LET OP: kies voor 'Install WebbIE 4 Web Browser Now'. Dat is – op het moment van schrijven – de een na bovenste knop. Als je voor de bovenste download kiest, krijg je 'n hele berg hulpprogramma's erbij, waar je voor het testen niets aan hebt.)

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

TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome op Android 4.4,2, 6.0, 7.0 en 8.1.0.

VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS (9.3.5 en 12.4) en OS X 10.11.6.

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

Verteller (Narrator) is een in Windows 10 ingebouwde schermlezer. Er is getest in combinatie met Edge.

(Voor de bovenstaande programma's zijn links naar sites met uitleg en dergelijke te vinden op de pagina met links onder Toegankelijkheid → Schermlezers, tekstbrowsers, en dergelijke.)

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 problemen in schermlezers (en eventuele aanpassingen om die te voorkomen) staan iets hieronder bij Bekende problemen (en oplossingen).

Alleen op de hierboven genoemde systemen en browsers is getest. Er is dus niet getest op bijvoorbeeld 'n Blackberry. Er is een kans dat dit voorbeeld niet (volledig) werkt op niet-geteste systemen en apparaten. Om het wel (volledig) werkend te krijgen, zul je soms (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 Samsung Internet op Android 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 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. Anders is er 'n redelijke kans 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! Dat kan op het forum.)

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.

Bij toegankelijkheid is er vaak geen goed onderscheid te maken tussen oplossing en probleem. Zonder (heel simpele) aanpassingen heb je vaak 'n probleem, en omgekeerd. Daarom staan wat betreft toegankelijkheid aanpassingen en problemen hier bij elkaar in dit hoofdstukje.

Voor zover van toepassing wordt eerst het ontbreken van JavaScript, css en/of afbeeldingen besproken. Vervolgens problemen en aanpassingen met betrekking tot toegankelijkheid voor specifieke groepen bezoekers, zoals zoomen en andere lettergrootte, Tab-toets, tekstbrowsers en schermlezers. Als laatste volgen algemene problemen in alle of in specifieke browsers.

Als in een onderdeel één of meer problemen worden besproken, staat in een breed rood kadertje een korte samenvatting daarvan. Bij een onderwerp over toegankelijkheid zijn er soms geen problemen, maar alleen aanpassingen. In dat geval staat in een smal groen kadertje 'Geen problemen'.

Zonder JavaScript

Probleem: in Edge, Internet Explorer en UC Browser werkt dit voorbeeld niet goed voor gebruikers van de Tab-toets.

Deze browsers ondersteunen de css-pseudo-class :focus-within niet. Met behulp van JavaScript wordt dit voor deze browsers geïmiteerd. zodat het ook in deze browsers goed werkt voor gebruikers van de Tab-toets. Een uitgebreidere beschrijving is iets hieronder te vinden onder het kopje Gebruikers Tab-toets.

Probleem: in Safari, Chrome for iOS en UC browser op iOS gaat het weer verkleinen van de thumbnails lastig.

In Safari, Chrome for iOS en UC browser kun je een thumbnail alleen weer verkleinen door een andere thumbnail te vergroten. Met behulp van 'n regel JavaScript kan ook in deze browsers een thumbnail weer worden verkleind door het scherm op een willekeurige plaats aan te raken.

Zonder css

Geen problemen.

Alle thumbnails staan onder elkaar. De thumbnails zijn niet verkleind. Achter elke thumbnail staat de bijbehorende link met de tekst uit de <span>. Het ziet er niet uit, maar het werkt.

Zonder afbeeldingen

Geen problemen.

Ook zonder afbeeldingen werkt dit voorbeeld. De links werken gewoon bij klikken, aanraken of Enter, en de omschrijving onder de afbeelding is gewoon te zien. In plaats van de afbeelding wordt de alt-tekst getoond.

Zonder afbeeldingen én zonder css

Geen problemen.

Meestal wordt de alt-tekst uit de <img> getoond, gevolgd door de link met de tekst uit de <span>. Soms wordt de alt-tekst niet getoond, maar alleen de tekst uit de link.

Gebruikers Tab-toets

Probleem: zonder JavaScript is het slecht toegankelijk in UC Browser, Internet Explorer en Edge.

Vergrote thumbnail is niet zichtbaar door ontbreken van :focus-within

Om de constructie toegankelijk te maken voor gebruikers van de Tab-toets, wordt gebruik gemaakt van de pseudo-class :focus-within. UC Browser, Internet Explorer en Edge ondersteunen dit niet. Daarom wordt dit voor deze browsers gesimuleerd met behulp van wat JavaScript. Als JavaScript uitstaat, werkt dit niet.

Het resultaat is op de afbeelding te zien. Of eigenlijk: niet te zien. De thumbnail wordt niet vergroot en de brede border verschijnt niet. De link wordt wel gewoon boven de thumbnail gezet, en ook de in de link zittende tekst wordt netjes onder de (afwezige) thumbnail gezet.

De afbeelding is in Firefox gemaakt. Dat de link gewoon focus heeft, is te zien aan de zwarte stippellijn. Deze geeft de grootte van de link aan. De link wordt ook gewoon gevolgd bij aanraken, klikken of Enter. Maar erg toegankelijk kun je dit uiteraard niet noemen.

Tekstbrowsers

Geen problemen.

Lynx toont de alt-tekst uit de <img> én de tekst uit de <span> in de link.

WebbIE toont alleen de tekst uit de <span>.

Schermlezers

Geen problemen.

Alle geteste schermlezers lezen alt-tekst en tekst in de link voor. De links kunnen in alle schermlezers worden gevolgd.

Afhankelijk van schermlezer en instellingen wordt de thumbnail wel of niet vergroot en kan het onderschrift bij de thumbnail wel of niet worden getoond. Maar ook als dit onderschrift niet wordt getoond, wordt het altijd voorgelezen, omdat het gewoon de tekst binnen de link is.

Zoomen en lettergroottes

Geen problemen.

Als door inzoomen (vergroten) in kleine browservensters thumbnail en/of onderschrift buiten het venster komen te staan, kunnen deze gewoon weer binnen het venster worden gescrold.

Elke thumbnail is altijd direct bereikbaar, ook als een andere thumbnail is vergroot. Maar bij een lettergrootte van meer dan 120% worden sommige thumbnails volledig afgedekt door de vergrote thumbnail. Om de afgedekte thumbnail toch te kunnen bereiken, moet je de cursor even buiten de vergrote thumbnail brengen, of het scherm ergens aanraken of -klikken buiten de vergrote thumbnail.

Safari op OS X

Probleem: de cursor verandert pas in een pointer, nadat deze is bewogen.

Als een cursor boven een link staat, verandert deze in een soort handje. In dit voorbeeld is de link in eerste instantie verborgen. Pas na hoveren over, aanraken van of tabben naar de thumbnail wordt de link na een hele korte vertraging actief.

Alle browsers veranderen, ook met een hele korte vertraging, de standaardcursor in een handje. Alleen Safari op OS X doet dat pas, nadat de cursor is bewogen. Het uitproberen van cursor: pointer; op 387 verschillende plaatsen had daar geen enkel effect op.

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

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

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

127-css-dl:

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

afbeelding-127-hulp-dl.css: stylesheet voor de achttien hulppagina's achter de links.

127-files-dl:

achttien hulppagina's voor achter de links.

127-pics:

achttien thumbnails.

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 grootte. En dat is een probleem. Sites waren, in ieder geval tot enkele jaren geleden, 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, enzovoort, 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 bijvoorbeeld worden nooit meer thumbnails naast elkaar gezet, dan binnen het venster passen.

Maar die stomme mobiele browser weet dat niet, dus die gaat ervan uit dat ook deze 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.

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

<div id="wrapper" aria-haspopup="true">

div#wrapper is de <div>, waar de hele constructie in zit. Door alles in één overkoepelende wrapper-<div> te zetten, kan gebruik worden gemaakt van flexbox om de <div>'s met de thumbnails en links op de juiste plaats te zetten.

In dit voorbeeld had deze <div> mogelijk gecombineerd kunnen worden met <main>, omdat er in <main> nauwelijks meer staat dan in div#wrapper. Maar normaal genomen zal er wel meer binnen <main> staan.

aria-haspopup="true" is een toevoeging voor Internet Explorer en Edge op touchscreens met Windows en Windows 10 Mobile, en voor UC Browser op Windows 10 Mobile. Zonder deze toevoeging werkt het niet goed in deze browsers. Een uitgebreider verhaal hierover staat bij WAI-ARIA-codes.

<div>

<img src="127-pics/lay-out-001.jpg" alt="Lay-out 1"> <a href="127-files-dl/lay-out-1-dl.html" aria-haspopup="false"> <span>Twee kolommen met vaste header en <span lang="en">footer</span>.</span> </a> </div>

Deze constructie komt in het voorbeeld in totaal achttien keer voor. Uiteraard met elke keer een andere afbeelding, een andere alt-tekst en een andere link.

Van buiten naar binnen:

<div>: elke <img> staat met de bijbehorende <a> in een eigen <div>. Deze <div>'s zijn simpel op de juiste plaats te zetten, en daarmee ook de erin zittende <img>'s en <a>'s.

<img src="127-pics/lay-out-001.jpg" alt="Lay-out 1">: een gewone <img>. In elke <img> zit één van de achttien thumbnails.

De alt-tekst wordt getoond, als om een of andere reden de thumbnails niet worden getoond. Schermlezers lezen de alt-tekst voor.

<a href="127-files-dl/lay-out-1-dl.html" aria-haspopup="false">: een gewone link. aria-haspopup="false" is een toevoeging voor Internet Explorer en Edge op touchscreens met Windows en Windows 10 Mobile, en voor UC Browser op Windows 10 Mobile. Zonder deze toevoeging moet je in deze browsers de link twee keer aanraken, voordat deze wordt gevolgd. Een uitgebreider verhaal hierover staat bij WAI-ARIA-codes.

<span>Twee kolommen met vaste header en <span lang="en">footer</span>.</span>: de tekst in de link wordt in een <span> gezet. Daardoor kan de <a> zelf even groot worden gemaakt als de bijbehorende thumbnail, terwijl de tekst onder de thumbnail kan worden geplaatst.

(In deze <span> zit toevallig het Engelstalige woord 'footer'. Om aan schermlezers duidelijk te maken dat dit op z'n Engels moet worden uitgesproken, staat het woord in een geneste <span> met het attribuut lang="en".)

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

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 het kopje Gereedschap → Snelheid, testen, gzip, comprimeren (inclusief theorie) links naar sites vinden, waar je bestanden kunt comprimeren.

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

css voor alle vensters

css voor alle vensters

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

height: 97vh;

Hoogte.

Normaal genomen wordt <body> niet hoger, dan nodig is om de inhoud ervan weer te geven. Dat is in dit geval iets hoger dan de thumbnails, omdat div#wrapper aan de onderkant bij #wrapper een marge van 8 em krijgt.

Op iOS levert dit problemen op. Als een thumbnail door aanraken is vergroot en een border en onderschrift krijgt, zijn mensen gewend dat ze dat weer ongedaan kunnen maken door het scherm ergens anders aan te raken. Op iOS werkt dit niet. Je kunt de ene thumbnail alleen maar weer verkleinen, door een andere te vergroten. Er blijft dus altijd één thumbnail vergroot.

Om ook op iOS de thumbnail weer te kunnen verkleinen door een aanraking elders op het scherm, wordt een klein beetje JavaScript gebruikt. Dit JavaScript is aan <body> gekoppeld: het werkt alleen binnen <body>.

Als <body> niet even hoog is als het browservenster, heeft een aanraking onder de thumbnails geen effect. Daarom wordt <body> hier even hoog gemaakt als het venster van de browser.

1 vh is 1% van de hoogte van het venster van de browser. 97 vh is dus 97 % van de hoogte van het venster. Geen 100%. Is die 3% zonder <body> aan de onderkant om mensen met korte vingers tot razernij te drijven? Nee. Dat is weliswaar leuk meegenomen, maar dat is niet de eigenlijke reden.

Eén van de meer lastige dingen van css zijn verticale marges. Verticale marges gedragen zich soms totaal anders dan je zou verwachten. Daar zijn goede redenen voor, maar het is lastig om er mee te leren werken. Zelfs ervaren sitebouwers zoeken zich soms ongans naar waar een plotselinge kier vandaan komt.

Het eerste kind in <main> is een <h1> die bij h1 een marge van 20 px aan de bovenkant krijgt. Die <h1> is het eerste kind van <main>. <main> zelf heeft helemaal geen eigen inhoud, geen tekst, geen padding, niets. Alle inhoud van <main> staat binnen andere elementen. Als een ouder helemaal leeg is, wordt de marge van het eerste kind (hier de <h1>) naar de bovenkant van de ouder verplaatst. Oftewel: de <h1> heeft geen marge aan de bovenkant meer, maar <main> nu wel. Ook al heb je die niet zelf opgegeven.

<main>, die nu aan de bovenkant een marge van 20 px heeft, is weer het eerste kind van <body>. En ook <body> heeft geen eigen inhoud, want alles binnen <body> staat binnen het element <main>. Dus wordt de marge van de bovenkant van <main> verplaatst naar de bovenkant van <body>. Als je <body> 100 vh hoog zou maken, even hoog als het venster van de browser, komt daar nog een marge van 20 px aan de bovenkant bij. Waardoor <body> 20 px te hoog wordt. Afhankelijk van besturingssysteem en/of browser levert dat een verticale scrollbalk op. Overbodig en lelijk.

Door <body> iets minder hoog te maken dan 100 vh, levert die marge geen problemen op.

En nog iets wat mensen op het verkeerde been kan zetten: als je aan <body> een achtergrondkleur geeft, vult die achtergrondkleur altijd het volledige venster van de browser. Ongeacht breedte en hoogte van <body>. Dit is anders dan bij vrijwel alle andere elementen. Vrijwel, want bij <html> werkt net het zo. Behalve als je <html> en <body> beide een andere achtergrondkleur geeft, want dan vult die van <htm> het hele venster en die van <body> alleen maar de breedte en hoogte van <body>.

De achtergrondkleur van <body> zegt dus helemaal niets over de daadwerkelijke hoogte van <body>. Mogelijk lijkt dit lastig, maar in 99,99% van de gevallen is dit precies wat je wilt en gebruik je dit zonder er zelfs maar over na te denken.

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.

(Mogelijk is padding niet meer nodig, maar in het verleden verschilde de standaard-padding tussen browsers. Het is simpeler om dit gewoon te blijven gebruiken dan om een uitgebreide test uit te gaan voeren om te kijken, of dit nog wel nodig is.)

h1

Alle <h1>'s. Dat is er maar één: de belangrijkste kopregel van de pagina staat erin.

In dit geval zit in die kopregel gelijk een kleine gebruiksaanwijzing.

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.

font-size: 1.2em;

Van zichzelf heeft een <h1> een behoorlijke grote letter. Hier wordt die lettergrootte teruggebracht tot iets meer dan normaal.

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

font-weight: normal;

Van zichzelf is een <h1> vet. Hier wordt dat veranderd naar normaal.

outline: black solid 1px;

Zwart randje.

Anders dan een border neemt een outline geen eigen ruimte in. Bij een border met een breedte van 1 px zouden de elementen onder de <h1> 1 px lager komen te staan, bij een outline niet.

De elementen onder de <h1> hebben aan de bovenkant ook een randje. Nu komen deze gewoon over deze outline heen te staan. Bij een border zou je aan de onderkant een lijntje van 2 px krijgen, nu is dat gewoon 1 px.

margin: 20px 0 0;

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

Rechts, onder en links geen marge. Aan de bovenkant een marge van 20 px. Dit is de marge die zorgt voor wat afstand tussen de bovenkant van het browservenster en het voorbeeld.

Deze marge aan de bovenkant wordt van de <h1> verplaatst naar de bovenkant van <body>. Over hoe dit werkt is meer te vinden bij body bij de eigenschap: height: 97vh;.

padding: 5px;

Kleine afstand aan alle kanten tussen tekst in en buitenkant van de <h1>.

main

Alle <main>'s. Dat is er maar één: de belangrijkste inhoud van de pagina staat erin. (Hier is dat alleen het voorbeeld.)

display: block;

Oudere browsers kennen <main> niet. Een onbekend element is standaard een inline-element, waardoor eigenschappen als breedte niet kunnen worden gebruikt. Nu weten alle browsers dat dit een blok-element is.

width: 720px;

Breedte. Deze breedte is vrij willekeurig gekozen, je zou ook meer of minder kunnen nemen.

max-width: 78%; Ook in smalle vensters is het onderschrift volledig te zien

Hier gelijk boven is een breedte van 720 px opgegeven. In browservensters die smaller zijn dan 720 px, moet daardoor worden gescrold om alles te kunnen zien. Om dat te voorkomen wordt hier een maximumbreedte opgegeven.

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

Uiteindelijk wordt <main> hierdoor nooit breder dan 78% van de breedte van het venster van de browser, ongeacht de breedte van het venster.

Door de breedte te beperken tot 78% is er zelfs in de smalste browservensters links en rechts altijd voldoende ruimte om het volledige onderschrift te kunnen zien. Op de afbeelding is te zien dat in heel smalle vensters een deel van de border wegvalt, maar het onderschrift is volledig zichtbaar.

margin: 0 auto;

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

Boven en onder geen marge, links en rechts auto, wat hier hetzelfde betekent als evenveel. Hierdoor staat <main> altijd horizontaal gecentreerd binnen z'n ouder <body>, ongeacht de breedte van <body>.

Zoals iets hierboven bij max-width beschreven, is <body> altijd even breed als het venster van de browser. Hierdoor staat <main>, en daarmee de tekst en dergelijke erin ook, altijd horizontaal gecentreerd binnen het venster, ongeacht de breedte van het venster.

#wrapper

Het element met id="wrapper". De <div> waar alle thumbnails met de bijbehorende links in zitten.

display: flex;

Hiermee wordt div#wrapper in een zogenaamde 'flex container' veranderd. Dit maakt het veel makkelijker om de directe kinderen van dit element, de 'flex items', op een bepaalde plaats neer te zetten.

De directe kinderen van div#wrapper zijn hier de achttien <div>'s, waarin de thumbnails met bijbehorende links zitten. Deze <div>'s hebben div#wrapper als ouder en veranderen daardoor in flex items. Hierdoor zijn de <div>'s heel makkelijk op de juiste plaats te zetten, en daarmee ook de erin zittende thumbnails en links. Met slechts drie regels css staan de <div>'s goed, ongeacht de breedte van het browservenster.

Standaard worden flex items naast elkaar weergegeven, ook blok-elementen zoals een <div>. Als je verder helemaal geen flexbox-eigenschappen meer zou gebruiken, zouden door alleen display: flex; nu al alle <div>'s netjes naast elkaar komen te staan.

In dit geval komen de <div>'s naast elkaar te staan, omdat dat de standaardinstelling van flex-direction is. Dat betekent dat later gebruikte eigenschappen als justify-content invloed hebben op de horizontale positie van de flex items. Zou je hier flex-direction: column; gebruiken, dan komen de flex items onder elkaar te staan en hebben eigenschappen als justify-content invloed op de verticale positie van de flex items.

flex-wrap: wrap; Alle divs op één regel

De standaardwaarde bij flex-wrap is no‑wrap: zat alle flex items, hier de achttien <div>'s binnen div#wrapper, naast elkaar op één regel. Als ze niet meer passen, maak ze dan smaller. Dat is wat op de afbeelding gebeurt: de achttien <div>'s zijn zo smal gemaakt dat ze naast elkaar op één regel passen. Dat ziet er heel knus en gezellig uit en je voelt je haast een bruut als je dat gaat verstoren, maar toch is dat precies wat er gaat gebeuren.

Bij #wrapper div iets hieronder worden de <div>'s 120 px breed gemaakt. Bij main is <main> 720 px breed gemaakt, dus er passen zes <div>'s naast elkaar. Bij meer dan zes <div>'s naast elkaar, moeten ze dus smaller worden gemaakt.

De waarde wrap voorkomt dit smaller worden: als de <div>'s niet meer naast elkaar op één regel passen zonder ze te versmallen, worden ze op meerdere regels gezet.

(Overigens kun je ook bijvoorbeeld opgeven dat slechts één of enkele <div>'s smaller mogen worden. Maar dat soort eigenschappen wordt hier niet gebruikt.)

justify-content: center; De divs staan altijd horizontaal gecentreerd

De flex items, hier de achttien <div>'s, horizontaal centreren binnen de flex container div#wrapper. Horizontaal, want dat is de standaardrichting van flexbox, en die is niet veranderd.

Op de afbeelding is div#wrapper 540 px breed. Om dat zichtbaar te maken, heeft div#wrapper een zwarte stippellijn gekregen. Binnen deze breedte passen vier <div>'s van 120 px breed naast elkaar op één regel. Die vier <div>'s worden met behulp van justify-content horizontaal gecentreerd binnen div#wrapper, ongeacht de breedte van div#wrapper. De twee <div>'s die overblijven worden ook horizontaal gecentreerd, maar op een eigen regel onder de andere <div>'s.

justify-content heeft een aantal waarden, die allemaal even makkelijk werken. Zo kun je bijvoorbeeld ook de overblijvende ruimte alleen tussen de <div>'zetten.

margin-bottom: 8em;

Tamelijk grote marge aan de onderkant.

Als een thumbnail wordt vergroot, komt daar nog een onderschrift onder te staan. Aan de onderkant van het browservenster kunnen thumbnail en onderschrift gedeeltelijk onder het venster komen te staan. Op het moment dat de vergrote thumbnail zichtbaar wordt, kun je omlaag scrollen, maar dat is wat onhandig.

Door aan de onderkant voor voldoende ruimte te zorgen, kun je desgewenst al omlaag scrollen, voordat de vergrote thumbnail zichtbaar wordt.

#wrapper div

Alle <div>'s in een element met id="wrapper". Dit zijn hier de achttien <div>'s met thumbnails en links.

width: 120px; height: 106px;

Breedte en hoogte.

In elke <div> zit een <img> met een thumbnail. Die thumbnails hebben allemaal dezelfde grootte: 180x161 px. (De thumbnails werden al gebruikt voor de site en hebben toevallig die grootte.)

Iets hieronder wordt bij #wrapper img een breedte en hoogte van 100% aan de <img>'s met de thumbnails gegeven. Normaal genomen gelden een breedte en hoogte in procenten ten opzichte van de ouder van het element. De ouder van de <img> is de <div>, waar deze in zit. Hierdoor worden de thumbnails even breed en hoog als de <div>'s: 120 x 108 px.

Om vervorming van de thumbnails te voorkomen, moet de verhouding tussen breedte en hoogte hetzelfde zijn bij de <div> als bij de thumbnail. Als die verhouding niet hetzelfde is, krijg je een lachspiegel-effect.

Deze <div>'s zijn directe kinderen van div#wrapper, die bij #wrapper met display: flex; in een flex container is veranderd. Hierdoor zijn de <div>'s flex items, die met behulp van de css bij #wrapper op de juiste plaats worden gezet. Omdat flexbox zo flexibel is, kunnen hoogte en breedte van de <div>'s zonder enig probleem worden aangepast. Welke hoogte of breedte je ook gebruikt, ze worden altijd netjes op het scherm gezet.

Uiteraard moet je wel de verhouding tussen hoogte en breedte in de gaten houden om een lachspiegel-effect bij de thumbnails te voorkomen.

float: left;

Oudere browsers kennen flexbox niet. <div>'s zijn blok-elementen en worden normaal genomen onder elkaar gezet. Met behulp van een aantal eigenschappen van flexbox is iets hierboven bij #wrapper geregeld dat de <div>'s naast elkaar komen te staan. Maar als een browser flexbox niet ondersteunt, worden de <div>'s onder elkaar gezet.

Door de <div>'s naar links te floaten, worden ze ook in oudere browsers naast elkaar gezet. Niet netjes horizontaal gecentreerd binnen div#wapper, want dat is geregeld met de flexbox-eigenschap justify-content. Maar ze staan in ieder geval naast elkaar en de hele constructie met vergroten en zo werkt.

Deze <div>'s zijn directe kinderen van div#wrapper, die bij #wrapper met display: flex; in een flex container is veranderd. Hierdoor zijn de <div>'s flex items. float: left; werkt niet voor flex items. Op browsers die flexbox ondersteunen, heeft deze regel dus geen enkel effect.

outline: black solid 1px;

Zwart randje aan alle kanten.

Anders dan een border neemt een outline geen eigen ruimte in, daarom is dat hier makkelijker.

Bij een voldoende breed browservensters passen er precies zes <div>'s naast elkaar. Bij gebruik van een border zou je de breedte moeten gaan aanpassen of zoiets, bij een outline hoeft dat niet.

Op de raakvlakken tussen divs is de border te breed

De <div>'s grenzen aan elkaar. Bij gebruik van een border zou je op de grens tussen twee <div>'s een dubbele border krijgen, omdat er twee borders tegen elkaar aan komen te staan. Omdat een outline geen ruimte inneemt, worden die gewoon over elkaar heen gezet.

Op de afbeelding is in plaats van een outline een border gebruikt. Om het verschil duidelijker te maken, is die border 10 px breed gemaakt. Nu is duidelijk te zien dat de border, waar twee <div>'s elkaar raken, twee keer zo breed is als de andere borders.

position: relative;

Relatief positioneren.

Er zijn hier twee reden om de <div>'s relatief te positioneren.

* Als een vergrote thumbnail met onderschrift moet worden weergegeven, moet deze boven de andere thumbnails komen te staan. Om dat voor elkaar te krijgen, wordt aan de <div> met de vergrote thumbnail een hogere z-index gegeven. Een z-index werkt alleen onder bepaalde omstandigheden. Eén van die omstandigheden is een relatieve positie.

* De tweede reden is iets ingewikkelder. Eén van de directe kinderen van deze <div>'s is de <img> met de thumbnail. Deze wordt gelijk hieronder bij #wrapper img absoluut gepositioneerd en krijgt daar een breedte en hoogte van 100%: even breed en hoog als deze <div>'s. Althans: dat is de bedoeling.

Normaal genomen worden een breedte en hoogte in procenten genomen ten opzichte van de ouder van het element. Bij de <img> zou dat dus deze <div> zijn. Maar bij een absoluut gepositioneerd element worden een breedte en hoogte in procenten genomen ten opzichte van de eerste voorouder die het zogenaamde 'containing block' vormt. Een aantal eigenschappen kan ervoor zorgen dat een element in zo'n containing block verandert. Eén van die eigenschappen is position met een andere waarde dan static.

Omdat de <div>'s nu het containing block zijn voor de <img>'s, worden breedte en hoogte van de <img>'s nu bepaald door deze <div>'s.

#wrapper img

Alle <img>'s binnen een element met id="wrapper". De achttien <img>'s met de thumbnails.

width: 100%; height: 100%;

Breedte en hoogte.

Normaal genomen zijn een breedte en hoogte in procenten ten opzichte van de ouder van het element. Hier gelijk onder worden de <img>'s echter absoluut gepositioneerd, en dan is dat niet zo.

Bij een absoluut gepositioneerd element worden een breedte en hoogte in procenten genomen ten opzichte van de eerste voorouder, die een zogenaamd 'containing block' vormt. Zo'n containing blockwordt door bepaalde eigenschappen gevormd, waaronder position met een andere waarde dan static. Elke <img> staat in een <div>. Deze <div>'s hebben bij #wrapper div met position: relative; een relatieve positie gekregen. De breedte en hoogte van de <img> gelden dus ten opzichte van deze <div>.

Omdat breedte en hoogte een waarde van 100% hebben, zijn de <img>'s precies even groot als de <div>'s. De breedte en hoogte die de <div>'s bij #wrapper div hebben gekregen, heeft dan ook dezelfde verhouding als de breedte en hoogte van de thumbnails. Als dat niet zo zou zijn en de breedte zou bijvoorbeeld in verhouding meer worden verkleind dan de hoogte, zou de thumbnail vervormen en zou je een lachspiegel-effect krijgen.

(In het algemeen is het verkleinen van een afbeelding trouwens een bijzonder slecht idee: er wordt een groter bestand gedownload, dan nodig is. In dit geval gaat het echter om een kleine verkleining en voorkomt de verkleining het downloaden van de iets grotere thumbnail, als de vergroting moet worden weergegeven.)

Als één of meer thumbnails een andere verhouding hebben dan de <div>'s, kun je vervorming voorkomen door breedte en/of hoogte niet op te geven en eigenschappen als object-fit en/of object-position te gebruiken bij de <img>'s. Maar het is het makkelijkste als alle thumbnails, net zoals in het voorbeeld, dezelfde maat hebben. Je kunt de thumbnail eventueel ook tot de juiste grootte aanvullen met een achtergrondkleur of zoiets.

position: absolute;

Een absolute positie isoleert het element van de rest van de pagina. Wat de rest van de pagina betreft, bestaat het element als het ware niet. Dat is hier precies de bedoeling, want nu wordt de in de html op de <img> volgende <a> gewoon over de <img> heen gezet.

Bij hoveren over of aanraken van een <div>, of als door gebruik van de Tab-toets een <a> focus heeft gekregen, moet de thumbnail uit die <div> vergroot worden weergegeven en een onderschrift en border krijgen. Tegelijkertijd moet de bij die thumbnail horende link bovenop die thumbnail worden gezet, zodat bij een tweede aanraking of een klik de link wordt gevolgd. Als de <img> niet absoluut zou worden gepositioneerd, zou die link niet bovenop, maar onder de <img> worden geplaatst. Nu bestaat die hele <img> niet voor de link en wordt deze boven op de <img> gezet.

transition: 0.25s;

Iets hierboven is met width: 100%; height: 100%; een breedte en hoogte aan de thumbnails gegeven. Omdat de breedte in procenten is, worden de thumbnails even groot als de <div>, waar ze in zitten. Feitelijk betekent dat dat de thumbnails van 180 x 161 px iets worden verkleind, want de <div>'s hebben een grootte van 120 x 106 px. Als je nu bij :hover, :focus-within, en dergelijke een andere waarde bij width en height opgeeft, zorgt transition ervoor dat de thumbnails niet in één keer die nieuwe grootte krijgen, maar geleidelijk.

De thumbnails zijn verkleind tot 120 x 106 px. Bij #wrapper div:hover img en #wrapper div:focus-within img wordt dat veranderd naar 180 x 161 px. Die verandering vindt nu niet in één keer plaats, maar geleidelijk aan. De thumbnails lijken te groeien.

Bij transition staat maar één waarde: 0.25s. Als er maar één waarde wordt opgegeven, bepaalt die over hoeveel tijd de verandering wordt uitgesmeerd. Dat is hier vrij kort: 'n kwart seconde. Een eventuele tweede waarde, die hier ontbreekt, geeft een eventueel uitstel aan het begin van de verandering aan.

Het is ook mogelijk om het verloop van de verandering aan te geven met behulp van sleutelwoorden of getallen. Hiermee kun je bijvoorbeeld aangeven dat de verandering aan het eind snel of juist langzaam moet gaan. Bij een verandering die maar 0,25 seconde duurt, is het verschil nauwelijks te zien, dus dat wordt hier niet gebruikt.

transition brengt een geheel eigen risico met zich mee. In de specificatie staat, welke eigenschappen met behulp van transition kunnen veranderen. Je kunt eventueel bij transition opgeven, voor welke eigenschappen het geldt. Als je bijvoorbeeld top en left beide wilt veranderen bij :hover, kun je bijvoorbeeld aangeven dat de geleidelijke verandering met behulp van transition alleen voor top geldt. left verandert dan gewoon in één keer.

Als je niet opgeeft, voor welke eigenschappen transition geldt, geldt het voor álle eigenschappen die bij :hover, :focus-within, en dergelijke worden veranderd. Als daar 'n eigenschap bij zit die op dit moment niet door transition kan worden vertraagd, verandert die gewoon in één keer. Maar als de specificatie of een van de browsermakers de geest krijgt en plotsklaps die eigenschap ook onder transition laat vallen, kan dat tot heel onverwachte resultaten leiden.

Stel dat je een bepaalde eigenschap heel traag wilt veranderen bij :hover en een andere eigenschap flitsend snel. Mogelijk wordt dat flitsend snel dan opeens ook heel traag, als transition in de toekomst die eigenschap ook gaat ondersteunen. Daarom moet je absoluut zeker weten dat ook in de toekomst geen problemen kunnen ontstaan. Bij twijfel: geef aan welke eigenschap(pen) transition mag aansturen.

Bij #wrapper div:hover img en #wrapper div:focus-within img worden width en height van de <img> veranderd van 120 x 106 px naar 180 x 161 px. Die verandering mag onder transition vallen. Maar ook de eigenschappen border, border-radius en transform worden veranderd. Die eigenschappen zijn hier niet opgegeven, maar toch zijn ze aanwezig. Als je een bepaalde eigenschap niet opgeeft, gebruikt de browser die eigenschap met de standaardwaarde.

(Als je in het ontwikkelgereedschap van de browser kijkt bij Berekend, Computed, of hoe het ook heet in de betreffende browser, zie je die eigenschappen en waarden ook daadwerkelijk staan. In Firefox bijvoorbeeld zie je onder andere border-bottom-width 0px staan.)

Ook al heb je niets opgegeven, er is dus wel degelijk onder andere een border-width van 0 px aanwezig. Ook deze valt hierdoor onder transition het veranderen van de breedte van 0 naar 30 px duurt 0,25 seconde. Hetzelfde geldt voor border-radius en transform.

Omdat alle eigenschappen, ook die niet specifiek zijn opgegeven, hier mogen worden vertraagd door transition, is er geen enkel risico voor de toekomst. Als dat niet zo zou zijn, moet je opgeven, voor welke eigenschappen transition geldt.

Je kunt transition beperken tot bepaalde eigenschappen door die eigenschappen te noemen, gevolgd door tijdsduur en eventueel vertraging:

transition: width 0.5s;

Nu geldt transition alleen voor width, ongeacht wat er in de toekomst mogelijk nog zou kunnen veranderen. Maar hier is dat dus niet nodig, omdat bij #wrapper div:hover img en #wrapper div:focus-within img alles geleidelijk mag worden veranderd.

#wrapper a

Alle <a>'s binnen het element met id="wrapper". De achttien links naar de achterliggende pagina's.

width: 0.1px; height: 0.1px;

Dit is een wat eigenaardige grootte voor een link. Dat is vanwege touchscreens en schermlezers.

Met een muis is het heel simpel. Bij hoveren over de <div> wordt de in die <div> zittende thumbnail vergroot en krijgt een onderschrift. De link kan gewoon altijd boven de thumbnail staan, en bij klikken wordt de link dan gevolgd.

Bij een touchscreen is het een ander verhaal. Bij de eerste aanraking van een <div> moet de thumbnail worden vergroot en een onderschrift krijgen, en pas bij een tweede aanraking moet de link worden gevolgd. Bij de tweede aanraking moet de link daarom bovenop de thumbnail staan. Maar bij de eerste aanraking mag dat nog niet zo zijn. Daarom moet de link in eerste instantie op een of andere manier worden verborgen.

Dat verbergen kan heel simpel met display: none; of visibility: hidden;. Maar die methoden vallen af, omdat de link dan niet werkt in schermlezers.

De link in eerste instantie buiten het venster positioneren kan ook niet, want dan werkt de link niet in schermlezers op Android. (Mogelijk wel in de nieuwste versies, maar niet in iets oudere.)

Je zou de <a> in eerste instantie 0 x 0 px groot kunnen maken. Omdat je iets van 0 x 0 px niet kunt aanraken, kan de link dan gewoon boven de thumbnail staan. Maar helaas blijken de links bij een grootte van 0 x 0 px op OS X genegeerd te worden door VoiceOver en de Tab-toets.

Na een korte pauze die werd benut voor het uittrekken van een aantal van de nog aanwezige haren, bleek een grootte van 0,1 x 0,1 px groot te werken. Nu kan de <a> overal na hoveren over of bij de eerste aanraking van de <div> boven de thumbnail worden gezet, schermlezers werken en de Tab-toets doet het ook overal. Een link van 0,1 bij 0,1 px is zo klein, dat deze niet op een aanraking reageert.

Helaas sneuvelden geheel onverwacht kort hierna nog een aantal haren, want als je precies die 0,1 x 0,1 px aanraakt, wordt de link al bij de eerste aanraking gevolgd in UC Browser, Samsung Internet en Dolphin op Android. Omdat aanraken met een vinger gebeurt en dus niet erg precies is, is het vrij precies makkelijk dat ellendige stukje van 0,1 x 0,1 px raken.

Daarom wordt iets hieronder voor deze browsers z-index: -1; opgegeven. Die z-index wordt dan weer verhoogd, als de link bij de tweede aanraking bovenop de thumbnail wordt gezet.

Nu werkt het overal: een eerste aanraking vergroot de thumbnail en zet er een onderschrift onder, een tweede aanraking volgt de link en de nog resterende haren blijven nog even in leven.

overflow: hidden;

In de <a> zit de tekst van de link. Deze wordt ook gebruikt als onderschrift onder de vergrote thumbnail. De tekst lijkt onder de thumbnail te staan, maar staat in feite onder de <a>. De <a> wordt bovenop de thumbnail gezet, maar met een kleine vertraging. Daarom wordt ook de tekst met een kleine vertraging getoond: pas als de <a> op de juiste plaats staat. Anders zou de tekst in eerste instantie niet op de juiste plaats staan.

Het verdwijnen van de <a> gebeurt wel bliksemsnel, want anders zou de link mogelijk nog even werken, als al een andere thumbnail is aangeraakt en dus een andere link moet werken. Maar de tekst onder de thumbnail verdwijnt wel met een kleine vertraging. Daardoor blijft de tekst onder de thumbnail nog even zichtbaar, terwijl de thumbnail niet meer is vergroot. De tekst zweeft als het ware even in de lucht.

De standaardinstelling van overflow is visible als iets te groot is voor het element, toon het dan toch. Mogelijk wordt de lay-out verstoord, maar er verdwijnt in ieder geval geen tekst of zo. Hier is dat onhandig. Met overflow: hidden; wordt alles, wat niet binnen de <a> past, verborgen. Oftewel: zodra de <a> weer 0,1 x 0,1 px is, is de tekst onmiddellijk onzichtbaar.

text-decoration: none;

Standaard wordt tekst in een link onderstreept. Dat is hier lelijk, dus wordt dat weggehaald.

position: absolute;

Absoluut positioneren. Absoluut positioneren heeft hier twee redenen.

* Gelijk hieronder wordt een z-index aan de <a>'s gegeven. Een z-index werkt alleen in bepaalde omstandigheden. Een van die omstandigheden is position met een andere waarde dan static.

* Je zou dan ook position: relative; kunnen gebruiken, wat vaak veel makkelijker werkt dan een absolute positie. Maar een <a> is van zichzelf een inline-element. Daardoor werken bepaalde eigenschappen als breedte en hoogte niet. Door de <a>'s absoluut te positioneren, veranderen ze in 'n soort blok-element en werken deze eigenschappen wel.

z-index: -1;

De <a>'s staan in de html achter de bijbehorende <img>'s. Beide zijn absoluut gepositioneerd. Dat betekent dat de <a>'s boven de <img>'s op het scherm komen te staan. Dat levert in bepaalde browsers problemen op, omdat de <a> nu bij een eerste aanraking kan worden gevolgd. Een negatieve z-index zet de <a>'s onder de bijbehorende <img>. (Een langer verhaal hierover is iets hierboven bij width: 0.1px; height: 0.1px; te lezen.)

Een z-index werkt alleen onder bepaalde omstandigheden. Eén van die omstandigheden is een absolute positie. Die is gelijk hierboven gegeven, dus dat is geregeld.

transition: 0.01s 0s;

Als over de <div> wordt gehoverd of als de thumbnail wordt aangeraakt, wordt de <a> (met een kleine vertraging) boven de thumbnail gezet, zodat bij een volgende aanraking of klik de link wordt gevolgd. Het weer weghalen van de link moet zonder vertraging gebeuren, want anders zouden er korte tijd twee links open staan.

Firefox op touchscreens op Windows blijft echter de thumbnail eindeloos vergroten en verkleinen, als de link gelijk wordt verwijderd. Daarom wordt met behulp van transition dat verwijderen uitgesmeerd over 0,01 seconde. De tweede waarde van 0 seconde geeft aan dat de verwijdering van de link, anders dan het plaatsen, zonder vertraging moet gebeuren.

Het effect van deze regel is volledig onmerkbaar, maar Firefox wordt hierdoor gekalmeerd.

#wrapper a > span

#wrapper: het element met id="wrapper". De <div> waar de hele constructie met thumbnails en links in zit.

a > span: alle <span>'s binnen een <a>. Het teken > geeft aan, dat het alleen <span>'s mogen zijn die een direct kind van de <a> zijn. Onderstaande <span> is een direct kind van de <a>:

<a> <span>Twee kolommen met vaste header.</span> </a>

De middelste <span> hieronder is geen direct kind van de <a>, omdat er een <span> tussen de <a> en de binnenste <span> zit:

<a> <span>Twee kolommen met vaste header en <span lang="en">footer</span> .</span> </a>

In dit voorbeeld is er maar één <span> die een direct kind van de <a> is. Binnen deze <span> zit de tekst van de link, die ook als onderschrift onder de vergrote thumbnail komt te staan. Soms zit binnen deze <span> nog een andere <span> om een woord met een andere taal aan te duiden. Deze selector moet alleen werken voor de buitenste <span> met de volledige tekst van de link, niet voor eventueel daarbinnen zittende geneste <span>'s. De > zorgt daarvoor.

De hele selector in normale mensentaal: doe iets met de <span>'s die een direct kind van een <a> zijn, die weer binnen het element met id="wrapper" 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: 198px;

Breedte.

Iets hieronder wordt links en rechts een border van 1 px breed en een padding van 20 px breed gegeven. De totale breedte van de <span> wordt hiermee 1 + 20 + 198 + 20 + 1 = 240 px.

De vergrote thumbnail is 180 px breed met links en rechts een border van 30 px. Dat is samen, niet geheel toevallig, ook 240 px. De <span> met het onderschrift sluit hierdoor netjes op de thumbnail aan.

min-height: 30px; Onderschrift bedekt niet volledig de border

Minimumhoogte. Deze is even groot als de border aan de onderkant van de vergrote thumbnail.

Normaal genomen wordt een element automatisch precies hoog genoeg om de inhoud ervan weer te kunnen geven. Als bij de bezoeker toevallig een kleinere letter wordt gebruikt, of als de bezoeker de lettergrootte heeft verkleind, kan hierdoor de hoogte van de <span> bij weinig tekst minder dan 30 px worden.

Op de afbeelding is dat het geval. Maar de border onder de thumbnail is nog steeds 30 px hoog. Daardoor steekt de border nu onder de <span> met tekst uit, wat nogal lelijk is. Door de <span> een minimumhoogte van 30 px te geven, dekt de <span> altijd de hele border aan de onderkant af.

font-size: 0.9em;

Iets kleinere letter.

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

-ms-hyphens: auto; -webkit-hyphens: auto; hyphens: auto;

Hier staat in feite drie keer hetzelfde: hyphens: auto;. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.

De onderschriften onder de thumbnails zijn vrij smal. Daarom wordt hier automatisch afbreken aangezet. Meestal is dat niet zo'n goed idee, maar hier kan het bij iets langere woorden veel lege ruimte voorkomen. Niet alle browsers ondersteunen dit, en de bezoeker moet ook de bij de taal horende afbreekregels hebben geïnstalleerd. Maar waar het werkt, is dat meegenomen.

border: black solid 1px;

Zwart randje.

border-radius: 0 0 5px 5px;

Rechtsonder en linksonder cirkelvormige hoek van 5 px breed en hoog.

padding: 5px 20px;

Omdat voor onder en links geen waarden zijn opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 5px 20px 5px 20px in de volgorde boven – rechts – onder – links.

Boven en onder een kleine afstand tussen tekst in en buitenkant van de <span>.

Links en rechts een veel grotere afstand. In browservensters smaller dan 400 px kan een deel van de border rondom de vergrote thumbnail en van de tekst in deze <span> links of rechts buiten het venster komen te staan.

Dat die border deels wegvalt maakt niet zoveel uit. Maar om de hele tekst te kunnen zien, moet je gaan scrollen, waarbij je ook nog per ongeluk de link zou kunnen volgen.

Door deze brede padding is de tekst ook in smalle browservensters volledig te zien. Voor vensters minimaal 400 px breed wordt de brede padding later weer verwijderd.

position: absolute;

Absoluut positioneren, zodat de <span> op de juiste plaats kan worden neergezet.

Een absoluut gepositioneerd element wordt neergezet ten opzichte van de eerste voorouder, die een zogenaamd 'containing block' vormt. Zo'n containing blockwordt door bepaalde eigenschappen gevormd, waaronder position met een andere waarde dan static. Elk van deze <span>'s heeft als ouder een <a>, die bij #wrapper a absoluut is gepositioneerd. De <span>'s worden dus gepositioneerd ten opzichte van de <a>, waar ze in zitten.

Een <span> is van zichzelf een inline-element. Daardoor werken bepaalde eigenschappen als hoogte en breedte niet. Door de <span> absoluut te positioneren, verandert deze in een soort blok-element, waardoor dit soort eigenschappen wel werken.

top: 161px;

161 px vanaf de bovenkant neerzetten.

Zoals gelijk hierboven beschreven worden de <span>'s, en daarmee de erin zittende tekst, gepositioneerd ten opzichte van de <a>, waar ze in zitten. Als een <div> met een thumbnail voor de eerste keer is aangeraakt, als erover wordt gehoverd of als de <a> in de <div> focus heeft gekregen, worden die <a>'s bij #wrapper div:hover a, #wrapper a:focus 161 px hoog gemaakt. Even hoog als de bij de <a> horende thumbnail.

Omdat de <img> bij #wrapper img en de <a> bij #wrapper a beide absoluut zijn gepositioneerd, staan ze op dezelfde hoogte binnen hun gemeenschappelijke ouder-<div>. Hierdoor staan de onderkant van de <a> en de onderkant van de <img> op gelijke hoogte. Als de <span> met de tekst op 161 px vanaf de bovenkant van de <a> wordt neergezet, staat deze dus ook precies onder de thumbnail.

Voor het oog lijkt het onderschrift onder de thumbnail te staan, in werkelijkheid staat het onder de <a>.

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

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

Onderschrift staat te ver naar rechts

Deze <span>'s met het onderschrift worden geplaatst ten opzichte van de <a>, waar ze in zitten. Die <a> is echter in eerste instantie miniem klein en wordt met enige vertraging even groot gemaakt als de bijbehorende thumbnail en bovenop die thumbnail neergezet.

Als de <span> met tekst te snel zichtbaar wordt, staat deze hierdoor nog niet op de goede plaats, want de <a> zelf staat nog niet goed. Op de afbeelding is dat te zien: het onderschrift staat te ver naar links. Na 'n halve seconde wordt het onderschrift alsnog goed gezet, maar we waren 'n site aan het maken en geen demonstratie van gedresseerde springende vlooien.

Daarom worden de <span>'s links buiten het scherm neergezet, zodat ze onzichtbaar zijn. Pas na een kleine vertraging, als de <a> op de juiste plaats staat, worden ze zichtbaar. Grappig bijverschijnsel: de thumbnails, en ook de bijbehorende border, groeien aan alle kanten. Pas als de thumbnail niet meer groeit, wordt in één keer de <span> met het onderschrift neergezet.

(Verbergen met display: hidden; of display: none; is hier geen optie, want dan negeren schermlezers de tekst. Tekst die buiten het browservenster staat, wordt wel gewoon voorgelezen.)

transition: 0s 0.55s;

Iets hierboven zijn de <span>'s met transform: translateX(-20000px); links buiten het scherm neergezet. Als je nu bij :hover, :focus, en dergelijke een andere waarde bij translateX() opgeeft, zorgt transition ervoor dat die nieuwe waarde niet gelijk, maar geleidelijk aan of na enige vertraging geldt. In dit geval gaat het alleen om de vertraging.

De <span>'s zijn links buiten het scherm geparkeerd. Bij #wrapper div:hover a > span, #wrapper a:focus > span worden ze met transform: translateX(‑30px); binnen het scherm gezet. Die verandering vindt nu niet gelijk plaats, maar na een kleine vertraging.

Bij transition staan twee waarden: 0s en 0.55s. Als er twee waarden staan, geldt de eerste waarde voor de duur van de verandering. In dit geval moet die verandering in één keer plaatsvinden: gedurende nul seconde. (Als je hier bijvoorbeeld 10s zou opgeven, zie je de <span> inderdaad van linksaf het scherm binnen schuiven. Na enige tijd, want ze staan een heel eind buiten het scherm.)

De tweede waarde geeft de vertraging aan: pas na 0,55 seconde. De <span> wordt gepositioneerd ten opzichte van de <a>, waar de <span> in zit. In principe staat die <a> na een vertraging van 0,5 seconde op de juiste plaats met de juiste grootte. In de praktijk blijkt echter, dat dit soms 'n heel klein beetje langer duurt. Hierdoor kan de <span> als het ware nog even wiebelen bij het neerzetten. Door de <span> een iets grotere vertraging te geven dan de <a>, wordt dit wiebelen voorkomen.

transition brengt een geheel eigen risico met zich mee. In de specificatie staat, welke eigenschappen met behulp van transition kunnen veranderen. Je kunt eventueel bij transition opgeven, voor welke eigenschappen het geldt. Als je bijvoorbeeld top en left beide wilt veranderen bij :hover, kun je bijvoorbeeld aangeven dat de geleidelijke verandering met behulp van transition alleen voor top geldt. left verandert dan gewoon in één keer.

Als je niet opgeeft, voor welke eigenschappen transition geldt, geldt het voor álle eigenschappen die bij :hover, :focus, en dergelijke worden veranderd. Als daar 'n eigenschap bij zit die op dit moment niet door transition kan worden vertraagd, verandert die gewoon in één keer. Maar als de specificatie of een van de browsermakers de geest krijgt en plotsklaps die eigenschap ook onder transition laat vallen, kan dat tot heel onverwachte resultaten leiden.

Stel dat je een bepaalde eigenschap heel traag wilt veranderen bij :hover en een andere eigenschap flitsend snel. Mogelijk wordt dat flitsend snel dan opeens ook heel traag, als transition in de toekomst die eigenschap ook gaat ondersteunen. Daarom moet je absoluut zeker weten dat ook in de toekomst geen problemen kunnen ontstaan. Bij twijfel: geef aan welke eigenschap(pen) transition mag aansturen.

Bij #wrapper div:hover a > span, #wrapper a:focus > span wordt alleen transform: translateX() veranderd van -20000px naar -30px. Omdat dat het enige is dat verandert, speelt dat risico hier niet. Als dat niet zo zou zijn, moet je opgeven, voor welke eigenschappen transition geldt.

Je kunt transition beperken tot bepaalde eigenschappen door die eigenschappen te noemen, gevolgd door tijdsduur en eventueel vertraging:

transition: width 0.5s;

Nu geldt transition alleen voor width, ongeacht wat er in de toekomst mogelijk nog zou kunnen veranderen. Maar hier is dat dus niet nodig.

(O jee, ik heb weer 'n beetje gejokt. Eigenlijk doet zich dit verschijnsel ook hier voor. Als het browservensters minstens 400 px breed is,worden bij #wrapper a > span breedte en padding aangepast. Ook die aanpassing gebeurt pas na 0,55 seconde. Als je het venster smaller dan 400 px maakt en dan langzaam breder, zie je bij 400 px breedte die vertraging bij het aanpassen van de breedte en de padding. Maar dat is geen enkel probleem hier. Dit zal vrijwel nooit gebeuren en als het toch gebeurt, bijvoorbeeld door het draaien van een mobieltje, moet je het weten om het te kunnen zien. Je kunt dit voorkomen, maar dat is in dit geval schieten met een mug op een olifant. Of zoiets.)

#wrapper div:hover

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

#wrapper div {width: 120px; height: 106px; float: left; outline: black solid 1px; position: relative;}

Alle <div>'s in een element met id="wrapper", maar alleen als over die <div> wordt gehoverd (of als die wordt aangeraakt). Dit zijn de achttien <div>'s met thumbnails en links.

z-index: 10; Vergrote thumbnail staat niet bovenaan

Normaal genomen worden elementen in de volgorde van de html op het scherm gezet: latere elementen in de html komen boven eerdere elementen te staan. Elke thumbnail zit in een eigen <div> (met de bijbehorende <a>). Als de thumbnail wordt vergroot, komt die onder latere <div>'s te staan.

Op de afbeelding is dit te zien. De thumbnail in de zevende <div> is vergroot. Deze staat boven de eerste en tweede <div>, maar de achtste, dertiende en veertiende <div> staan boven de thumbnail.

(Omdat voor de afbeelding ook de z-index bij de <a> even is weggehaald, valt ook het grootste deel van het onderschrift weg.)

Door bij hoveren of aanraken van een <div> de z-index te verhogen, komt deze boven latere elementen te staan.

Een z-index werkt alleen in bepaalde omstandigheden. Eén van die omstandigheden is een relatieve positie. Bij #wrapper div zijn de <div>'s relatief gepositioneerd, dus dat is geregeld.

#wrapper div:focus-within

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

#wrapper div {width: 120px; height: 106px; float: left; outline: black solid 1px; position: relative;}

#wrapper div:hover {z-index: 10;}

Alle <div>'s in een element met id="wrapper", maar alleen als die <div> of een nakomeling van die <div> focus heeft.

De css bij deze regel is precies hetzelfde als die bij de regel #wrapper div:hover gelijk hierboven, dus je zou denken dat als selector dan gewoon de gecombineerde selector #wrapper div:hover, #wrapper div:focus-within {} gebruikt kan worden. Maar als een browser één (of meer) van de selectors niet kent, wordt de hele regel met de bijbehorende css genegeerd.

:focus-within is een van de nieuwere pseudo-classes. Lang niet alle browsers ondersteunen deze pseudo-class. Om te voorkomen dat deze browsers de css bij deze selector negeren, staan :hover en :focus-within daarom op twee aparte regels. En wordt de bijbehorende css twee keer herhaald.

Als over de <div> wordt gehoverd, wordt bij #wrapper div:hover de z-index verhoogd, zodat de hele thumbnail te zien is. Gebruikers van de Tab-toets hebben hier echter niets aan.

:focus-within werkt alleen als het element of een nakomeling van het element focus heeft. In dit geval als de <div> of één van de erin zittende elementen <img>, <a> of <span> focus heeft. Bij gebruik van de Tab-toets kan een <a> standaard focus krijgen. Omdat de <a> binnen een <div> zit, geldt dan voor die <div> de pseudo-class :focus-within, want een element binnen de <div> heeft focus.

z-index: 10;

Hogere z-index zodat de hele thumbnail plus onderschrift zijn te zien. Een uitgebreider verhaal staat iets hierboven bij #wrapper div:hover.

#wrapper div:hover img

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

#wrapper img {width: 100%; height: 100%; position: absolute; transition: 0.25s;}

Doe iets met alle <img>'s binnen een <div> die weer binnen het element met id="wrapper" zit, maar alleen als over die <div> wordt gehoverd (of als deze wordt aangeraakt).

width: 180px; height: 161px;

Bij #wrapper img zijn de thumbnails verkleind. Nu wordt deze thumbnails vergroot naar z'n ware grootte.

border: rgba(0, 0, 0, 0.7) solid 30px;

Aan alle kanten een border met een breedte van 30 px. De kleur wordt met behulp van de rgba()-notatie opgegeven.

Vaak wordt voor 'n kleur de hexadecimale notatie gebruikt, iets als color: #33ab01;. Daarbij worden niet alleen cijfers, maar ook letters gebruikt. 0 tot en met 9 werken precies hetzelfde als altijd, maar na de 9 komen nog A, B, C, D, E en F.

Als je telt, is 't dus: 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12, enzovoort. Daarbij is A gelijk aan het tientallige 10, B aan 11, enzovoort. Op deze manier kun je met twee cijfers en/of letters 256 mogelijkheden aangeven: van 00 tot en met FF.

De eerste drie getallen bij rgba() geven de kleur aan. Deze lopen van 0 tot en met 255, dus ook hiermee kun je 256 mogelijkheden aangeven. En omdat er drie getallen zijn levert dat 256 x 256 x 256 = 16.777.216 mogelijke kleuren op, net iets meer dan het aantal kleurpotloden in de gemiddelde kleurdoos van 'n kind.

De notatie bij rgba() geeft dus precies evenveel mogelijkheden als de hexadecimale.

Het eerste getal staat voor rood, het tweede voor groen en het derde voor blauw (feitelijk de Engelse namen, maar de eerste letter is toevallig in het Nederlands hetzelfde). Uit deze drie kleuren zijn alle kleuren op een monitor opgebouwd.

255 wil zeggen volledig aanwezig, 0 wil zeggen helemaal ontbrekend.

255, 255, 255 levert wit op, 0 , 0 , 0 zwart.

In plaats van getallen mag je ook percentages gebruiken, bijvoorbeeld: rgba(10%, 20%, 100%, 0.3).

Omdat in dit voorbeeld drie keer 0 is opgegeven, levert dit een zwarte kleur op.

Het vierde getal staat voor het alfa-kanaal. Hiermee wordt de doorzichtigheid aangegeven. Dit getal loopt van 0 naar 1. Volledig doorzichtig is 0, volledig ondoorzichtig is 1.

Het getal voor het alfa-kanaal wordt als decimale breuk aangegeven, dus bijvoorbeeld 0.5 wil zeggen halfdoorzichtig. Let erop dat je 'n punt gebruikt, de Amerikaanse manier om breuken aan te geven. Als je 'n komma gebruikt, denkt de browser dat er twee verschillende getallen staan.

In dit voorbeeld is deze achtergrondkleur enigszins doorzichtig: 0.7. Hierdoor zie je de andere thumbnails nog enigszins door de border heen. Een brede border onderscheidt de vergrote thumbnail van de rest, zodat deze duidelijker zichtbaar is. Met een smalle border is dat minder het geval. Maar een brede border oogt wat onvriendelijk, als een soort isoleercel. Door hem doorzichtig te maken, oogt de border wat vriendelijker.

border-radius: 20px;

Aan alle kanten een cirkelvormige hoek van 20 px breed en 20 px hoog.

-webkit-transform: translate(-60px, -56px); transform: translate(-60px, -56px);

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

Thumbnail staat op verkeerde plaats

De thumbnails 60 px naar links en 56 px naar boven verplaatsen. Zonder deze correctie worden de thumbnails gewoon linksboven in hun ouder-<div> neergezet. Op de afbeelding is dat het geval: de vergrote thumbnail staat in de linkerbovenhoek van zijn ouder-<div>.

Bij #wrapper img zijn de thumbnails met width: 100%; even breed gemaakt als de <div>, waar ze in zitten: 120 px. Iets hierboven is de thumbnail 180 px breed gemaakt. Dat is een verschil van 60 px. Als je het midden van de thumbnail op dezelfde plaats wilt houden – in het midden van z'n ouder-<div> –, moet de thumbnail de helft hiervan naar links worden gezet: -30 px. Maar de thumbnail krijgt links en rechts ook nog een border van 30 px. Om het midden van de thumbnail op dezelfde plaats te houden, moet de thumbnail daarom in totaal 60 px naar links worden gezet.

Voor de hoogte geldt hetzelfde, die wordt veranderd van 106 naar 161 px plus twee keer een border van 30 px.

Met transition: 0.25s; is bij #wrapper img opgegeven dat de verandering van de breedte geleidelijk aan gedurende een kwart seconde moet plaatsvinden. Maar ook de verplaatsing naar links en naar boven duurt een kwart seconde. Hierdoor lijkt de thumbnail vanuit het midden alle kanten uit te groeien. Ook de groei van de breedte van de border en het rond worden van de hoeken (border-radius) duurt 'n kwart seconde. (Een uitgebreider verhaal hierover is te vinden bij #wrapper img onder het kopje transition: 0.25s;.)

#wrapper div:focus-within img

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

#wrapper img {width: 100%; height: 100%; position: absolute; transition: 0.25s;}

#wrapper div:hover img {width: 180px; height: 161px; border: rgba(0, 0, 0, 0.7) solid 30px; border-radius: 20px; -webkit-transform: translate(-60px, -56px); transform: translate(-60px, -56px);}

Doe iets met alle <img>'s binnen een <div> die weer binnen het element met id="wrapper" zit, maar alleen als die <div> of een nakomeling van die <div> focus heeft.

De css bij deze regel is precies hetzelfde als die bij de regel #wrapper div:hover img gelijk hierboven, dus je zou denken dat als selector dan gewoon de gecombineerde selector #wrapper div:hover, #wrapper div:focus-within {} gebruikt kan worden. Maar als een browser één (of meer) van de selectors niet kent, wordt de hele regel met de bijbehorende css genegeerd.

:focus-within is een van de nieuwere pseudo-classes. Lang niet alle browsers ondersteunen deze pseudo-class. Om te voorkomen dat deze browsers de css bij deze selector negeren, staan :hover en :focus-within daarom op twee aparte regels. En wordt de bijbehorende css twee keer herhaald.

:focus-within werkt alleen als het element of een nakomeling van het element focus heeft. In dit geval als de <div> of één van de erin zittende elementen <img>, <a> of <span> focus heeft.

Als over de <div> wordt gehoverd, of als deze wordt aangeraakt, wordt bij #wrapper div:hover img de erin zittende thumbnail vergroot, op de juiste plaats gezet en voorzien van een brede border. Gebruikers van de Tab-toets hebben hier niets aan.

Bij gebruik van de Tab-toets kan een <a> standaard focus krijgen. Omdat de <a> binnen een <div> zit, geldt dan voor die <div> de pseudo-class :focus-within, want een element binnen de <div> heeft focus. En dus werkt deze selector, zodra de <a> focus heeft gekregen.

width: 180px; height: 161px; border: rgba(0, 0, 0, 0.7) solid 30px; border-radius: 20px; -webkit-transform: translate⁠(⁠‑⁠60px, -56px); transform: translate(-60px, ‑56px);

Deze css is precies hetzelfde als die iets hierboven bij #wrapper div:hover img. De beschrijving is daar te vinden.

#wrapper div:hover a, #wrapper a:focus

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

#wrapper a {width: 0.1px; height: 0.1px; overflow: hidden; text-decoration: none; position: absolute; z-index: -1; transition: 0.01s 0s;}

De eerste selector, voor de komma: doe iets met de <a>'s binnen een <div> die weer binnen het element met id="wrapper" zit, maar alleen als over de <div> wordt gehoverd (of als deze wordt aangeraakt).

De tweede selector, na de komma: doe iets met de <a>'s in het element met id = "wrapper", maar alleen als de <a> focus heeft.

Deze <a>'s zijn de achttien links naar de achterliggende pagina's, één voor elke thumbnail. Bij #wrapper a is gezorgd dat deze links bij hoveren over of aanraken van een thumbnail niet werken. Bij een klik of een tweede aanraking moeten ze wel werken.

width: 180px; height: 161px;

De <a>'s moeten de volledige thumbnail bedekken en worden dus even groot gemaakt als de thumbnails.

overflow: visible;

In de <a> zit tekst, die als onderschrift onder de thumbnail komt te staan. Daarmee komt die tekst ook onder de <a> te staan en daarmee erbuiten. Bij #wrapper a is overflow: hidden; opgegeven: verberg wat niet binnen de <a> past. De tekst zou hierdoor niet worden weergegeven. Door deze regel wordt de tekst wel zichtbaar, ook al past deze niet binnen de <a>.

z-index: 10;

Bij #wrapper a hebben de <a>'s een z-index van -1 gekregen: zet ze helemaal onderaan neer. Dat is nu niet handig, want de <a>'s moeten juist boven de <img>'s met de thumbnail komen te staan.

(Eigenlijk is een waarde van auto (de standaardwaarde) of eventueel 1 al voldoende. Maar ooit, jaren geleden, heb ik zo'n vijfhonderd z-indexen aangebracht, keurig op volgorde. En toen moest er helemaal aan het begin 'n nieuwe tussen. Na deze uiterst traumatische ervaring laat ik dwangmatig altijd ruimte over bij een z-index, voor het geval er later nog eentje tussen moet.)

Een z-index werkt alleen onder bepaalde omstandigheden. Eén van die omstandigheden is een absolute positie. Die hebben de <a>'s bij #wrapper a gekregen, dus dat is geregeld.

-webkit-transform: translate(-30px, -26px); transform: translate(-30px, -26px); Link staat op verkeerde plaats

Hier staat in feite twee keer hetzelfde: transform: translate(-30px, ‑26px);. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.

De <a> moet de vergrote thumbnail afdekken, zodat bij een tweede aanraking of een klik de link wordt gevolgd. Standaard wordt de <a> echter in de linkerbovenhoek van z'n ouder-<div> geplaatst. Terwijl de thumbnail bij #wrapper div:hover img en #wrapper div:focus-within img een eind naar links en naar boven is verplaatst.

Op de afbeelding is de thumbnail doorzichtig gemaakt, zodat de <div>'s met hun border nog te zien zijn. De thumbnail met z'n border staat midden boven z'n ouder-<div>.

De <a> is op de afbeelding doorzichtig rood gemaakt. Deze staat inderdaad netjes in de linkerbovenhoek van z'n ouder-<div>, zoals een welopgevoede <a> betaamt. Maar Thierry Baudet is ook welopgevoed en die staat ook niet goed, dus aan welopgevoed heb je soms niet zoveel.

Om de <a> goed boven de thumbnail te krijgen, wordt deze 30 px naar links en 26 px naar boven verplaatst.

transition-delay: 0.5s;

Bij #wrapper a is onder andere transition: 0.01s 0s; opgegeven. transition is een zogenaamde 'shorthand' voor een aantal samenhangende eigenschappen. In dit geval zijn er dat maar twee, maar een shorthand kan soms heel veel eigenschappen combineren.

Je zou deze shorthand ook zo kunnen schrijven: transition-duration: 0.01s; transition-delay: 0s;. De verandering moet worden uitgesmeerd over 0,01 seconde en zonder vertraging beginnen.

Omdat hier alleen transition-delay wordt aangepast, blijft het eerder opgegeven transition-duration: 0.01s; gewoon gelden. Maar die hele tijdsduur maakt hier niets uit, omdat die absurd kort is: 0,01 seconde. (De reden daarvan is een probleem in Firefox, waarover meer is te vinden bij #wrapper a onder het kopje transition: 0.01s 0s;.)

De <a> moet, na een eerste aanraking van of hoveren over de thumbnail, de hele thumbnail bedekken. Een tweede aanraking of een klik volgt dan de link. De <a> moet echter met enige vertraging boven de thumbnail worden gezet, omdat anders sommige browsers op touchscreens de link gelijk bij de eerste aanraking van de thumbnail al volgen. Een vertraging van 'n halve seconde blijkt goed te werken. Nauwelijks merkbaar, maar het voorkomt in alle gevallen het al bij de eerste aanraking volgen van de link.

#wrapper div:hover a > span, #wrapper a:focus > span

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

#wrapper a > span {background: white; color: black; width: 198px; min-height: 30px; font-size: 0.9em; -ms-hyphens: auto; -webkit-hyphens: auto; hyphens: auto; border: black solid 1px; border-radius: 0 0 5px 5px; padding: 5px 20px; position: absolute; top: 161px; -webkit-transform: translateX(-20000px); transform: translateX(-20000px); transition: 0s 0.5s;}

Dit zijn twee selectors, gescheiden door een komma.

Eerst de eerste selector #wrapper div:hover a > span:

#wrapper: het element met id="wrapper". De <div> waar het alle thumbnails en links in zitten.

div:hover: <div>'s, maar alleen als daarover wordt gehoverd (of als de <div> wordt aangeraakt). In elke <div> zit één thumbnail met bijbehorende link.

a > span: alle <span>'s binnen een <a>. Het teken > geeft aan, dat het alleen <span>'s mogen zijn die een direct kind van de <a> zijn. Onderstaande <span> is een direct kind van de <a>:

<a> <span>Twee kolommen met vaste header.</span> </a>

De middelste <span> hieronder is geen direct kind van de <a>, omdat er een <span> tussen de <a> en de binnenste <span> zit:

<a> <span>Twee kolommen met vaste header en <span lang="en">footer</span> .</span> </a>

In dit voorbeeld is er maar één <span> die een direct kind van de <a> is. Binnen deze <span> zit de tekst van de link, die ook als onderschrift onder de vergrote thumbnail komt te staan. Soms zit binnen deze <span> nog een andere <span> om een woord met een andere taal aan te duiden. Deze selector moet alleen werken voor de buitenste <span> met de volledige tekst van de link, niet voor eventueel daarbinnen zittende geneste <span>'s. De > zorgt daarvoor.

De hele selector in normale mensentaal: doe iets met de <span>'s die een direct kind van een <a> zijn, die weer binnen een <div> zit, die ten slotte binnen het element met id="wrapper" zit. Maar alleen als over de <div> wordt gehoverd (of als de <div> wordt aangeraakt).

De tweede selector #wrapper a:focus > span:

Doe iets met een <span> die binnen een <a> zit die weer binnen het element met id="wrapper" zit, maar alleen als de <a> focus heeft. Omdat tussen a:focus en span het teken > staat, geldt deze selector alleen <span>'s die een direct kind van de <a> zijn. Een uitgebreidere uitleg over het teken > staat gelijk hierboven bij de eerste selector.

-webkit-transform: translateX(-30px); transform: translateX(‑30px);

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

De <span>'s staan binnen een <a>, die bij #wrapper div:hover a, #wrapper a:focus even breed is gemaakt als de bijbehorende thumbnail. Links en rechts van de thumbnail staat nog een border van 30 px breed.

De <span> met het onderschrift is even breed als de thumbnail plus de twee borders. Om de <span> op de juiste plaats te krijgen, moet deze daarom 30 px naar links worden verplaatst.

css voor vensters minimaal 400 px breed

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

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 400 px breed zijn. In deze bredere vensters past het onderschrift onder de thumbnails altijd binnen het venster, waardoor de brede padding links en rechts niet meer nodig is.

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

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

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

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

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

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

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

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

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

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

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 anderhalve schermpixel (feitelijk bijna drie, 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.

#wrapper a > span

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

#wrapper a > span {background: white; color: black; width: 198px; min-height: 30px; font-size: 0.9em; -ms-hyphens: auto; -webkit-hyphens: auto; hyphens: auto; border: black solid 1px; border-radius: 0 0 5px 5px; padding: 5px 20px; position: absolute; top: 161px; -webkit-transform: translateX(-20000px); transform: translateX(-20000px); transition: 0s 0.5s;}

#wrapper div:hover a > span, #wrapper a:focus > span {-webkit-transform: translateX(-30px); transform: translateX(-30px);}

<span>'s die een direct kind van een <a> zijn, die zelf weer in het element met id="wrapper" zit. In deze <span>'s zit de tekst van de link. Deze tekst wordt ook als onderschrift bij een vergrote thumbnail gebruikt.

Een volledige beschrijving van deze selector staat bij #wrapper a > span.

width: 228px; padding: 5px;

Bij #wrapper a > span hebben deze <span>'s een breedte van 198 px gekregen, met links en rechts een padding van 20 px. Daardoor is in heel smalle browservensters het onderschrift toch volledig te lezen.

In bredere browservensters is die grote padding niet meer nodig, dus die wordt hier vervangen door een padding van 5 px aan alle kanten. Daardoor wordt de <span> link en rechts 15 px smaller. Om de totale breedte van de <span> hetzelfde te houden, zodat deze nog goed onder de thumbnail past, wordt de breedte daarom met 30 px verhoogd naar 228 px.

JavaScript

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

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

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

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

Dit script bestaat uit twee delen.

Het JavaScript voor iOS bestaat uit één simpele regel. Zonder deze regel is een vergrote thumbnail alleen weer te verkleinen, als een andere thumbnail wordt vergroot. Door deze regel JavaScript wordt de thumbnail ook weer verkleind, als het scherm op een willekeurige plaats wordt aangeraakt.

Het JavaScript om :focus-within te simuleren is iets langer. Sommige mensen gebruiken niet de muis of aanraken om naar een link, tekstveld, en dergelijke te gaan, maar de Tab-toets. Bijvoorbeeld omdat ze moeite hebben een muis te gebruiken, maar soms is het gewoon ook veel sneller dan een muis. Als een element met de Tab-toets wordt bezocht, heeft dat element focus.

In dit voorbeeld kunnen de thumbnails ook met behulp van de Tab-toets worden vergroot en van een onderschrift worden voorzien. Hiervoor wordt in een aantal selectors gebruik gemaakt van de relatief nieuwe pseudo-class :focus-within. Voor browsers die het relatief nieuwe :focus-within niet ondersteunen, wordt dat in dit script geïmiteerd.

Als dit script op meerdere pagina's wordt gebruikt, kan het ook als een extern script worden gebruikt: <script src="pad-naar-script/script.js"></script>

In dat geval moet <script> helemaal onderaan de pagina worden gezet, gelijk boven </body>. Het script zoekt namelijk elementen in de pagina op, en als die nog niet zijn gemaakt door de browser, gaat het mis. Bovendien stopt de opbouw van de pagina, zodra de browser een script ontmoet, omdat het script eerst wordt uitgevoerd. Het zou immers kunnen dat het script (heel) belangrijk is voor de weergave. Dat is hier niet het geval. Door het script onderaan de pagina te zetten, voorkom je ook die in dit geval overbodige vertraging.

<script></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.

JavaScript voor iOS

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

document.getElementsByTagName("body"): het eerste stukje.

getElementsByTagName is een zogenaamde 'functie'. Een functie is een stukje in de browser ingebakken code, waarmee je iets kunt doen. Deze functie is te vinden in het object document, vandaar dat document ervoor staat.

Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.

JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.

Met de methode getElementsByTagName() uit document kan JavaScript alle elementen van 'n bepaalde soort opzoeken. De tags waarnaar wordt gezocht, staat tussen haakjes:

getElementsByTagName("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 items. Zo'n item kun je aanspreken door het volgnummer te gebruiken. En omdat computers dol zijn op '0', is het volgnummer van het eerste item '0', en geen '1'.

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

document.getElementsByTagName("body")[0] 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.

Deze regel JavaScript zorgt ervoor dat op iOS het hele element <body> gevoelig wordt voor een aanraking. Zonder deze regel kan een thumbnail alleen weer worden verkleind, als een andere thumbnail wordt vergroot. Met deze regel kan een thumbnail ook weer worden verkleind, door het scherm op een willekeurige plaats aan te raken.

JavaScript om :focus-within te simuleren

(function () {

function: het sleutelwoord waarmee het begin van een functie wordt aangegeven. Een functie is een stukje bij elkaar horende code. (Het haakje helemaal aan het begin wordt iets verderop beschreven.)

(): achter een functie moeten twee haakjes staan. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie, maar bij deze functie gebeurt dat niet.

{: geeft het begin van de code binnen de functie aan. Aan het eind van de functie, dat is in dit geval helemaal onderaan in de laatste regel van het script, staat een bijbehorende }.

In die laatste regel staat in dit geval nog meer dan alleen de } die het einde van de code aangeeft: }) ();

}: dit is de eerder genoemde afsluitende }, waarmee het einde van de code in de functie wordt aangegeven.

): dit afsluitende haakje is de tegenhanger van het haakje dat voor de functie staat. Samen zorgen ze ervoor dat de hele functie, met alles erop en eraan, tussen haakjes staat. De reden van deze haakjes wordt iets hieronder besproken.

(): dit is weer gewoon een taalregel van JavaScript. In dit geval moeten er achter de }) nog twee haakjes staan. Een computer is gewoon niet zo slim, anders weet de ziel niet wat er moet gebeuren.

;: met de puntkomma wordt in JavaScript een regel afgesloten. Het is te vergelijken met een gewone punt in een tekst.

We hebben hier een script, waarin alle code binnen een functie is geplaatst. Alle code staat tussen { en }, zodat de computer het begin en einde van de functie kan herkennen.

Een functie is een stukje bij elkaar horende code dat je, zo vaak als je wilt, kunt uitvoeren. Als je de tafel van twaalf op het scherm wilt zetten, hoef je niet twaalf vermenigvuldigingen in JavaScript te schrijven, maar schrijf je 'n functie voor één vermenigvuldiging, die je vervolgens tien keer (op steeds iets andere wijze) uitvoert.

Een functie heeft echter één probleem: de code in de functie wordt pas uitgevoerd, als de functie wordt aangeroepen. Dat aanroepen kan op allerlei manieren gebeuren, bijvoorbeeld als de gebruiker 'n toets indrukt, als de pagina is geladen, als het 13:13 is op vrijdag de dertiende, noem maar op. Maar zonder te worden aangeroepen doet een functie helemaal niets.

Binnen deze functie wordt gekeken, of de browser de css-pseudo-class :focus-within ondersteunt. Maar deze functie doet dus wat, als die wordt aangeroepen. En dat aanroepen moet vanuit JavaScript gebeuren. Het heeft weinig nut als je bezoekers spreekkoren aanheffen: er gebeurt gewoon niets. Een vicieuze cirkel.

Om te zorgen dat de buitenste functie, die waar alle code in zit, toch vanzelf wordt uitgevoerd, zet je er een ( voor. En helemaal aan het eind, achter de afsluitende }, zet je de tegenhanger ). Nu wordt de functie automatisch uitgevoerd, zonder dat deze hoeft te worden aangeroepen. En wordt de code binnen de functie uitgevoerd.

(Je kunt de code ook in een niet alles omvattende functie zetten. Dan wordt de code gelijk uitgevoerd. Maar dat brengt belangrijke risico's met zich mee. In dit script worden namen voor variabelen gebruikt als 'links' en 'len'. Als nou een ander JavaScript toevallig dezelfde namen zou gebruiken, gaat het gruwelijk mis. Door het hele script in een functie te stoppen, voorkom je dat. Als je hier meer over wilt weten, kun je op internet zoeken naar 'name conflict' of 'name clash'.

De bovenste regel van dit script staat buiten deze functie, die wordt dus automatisch uitgevoerd. Het hierboven genoemde risico voor een conflict bestaat daar niet, omdat in die regel geen variabelen worden gebruikt.)

"use strict";

Deze regel zorgt ervoor dat bepaalde slordigheden in de code, die makkelijk tot grote problemen kunnen leiden, niet meer mogen. Een validator (die controleert op fouten in de code) is nu strenger en keurt meer dingen af.

Een klein aantal oudere browsers ondersteunt dit niet, maar die hebben er verder geen last van, omdat ze de regel gewoon negeren.

i;

i: deze variabele wordt op een aantal plaatsen als teller gebruikt. Aan het begin van een berekening wordt er 'n getal in gestopt. Het is gebruikelijk om dit soort tellers de naam 'i' (van 'index') te geven. Dat soort gewoontes maakt het makkelijker code van anderen te lezen. Hier wordt de variabele alleen aangemaakt, er wordt pas iets in gestopt, als er geteld moet worden.

Over wat een variabele is, is meer te vinden bij var links = document.querySelectorAll("#wrapper a"),.

;: de regel waarin variabelen worden aangemaakt, eindigt hier. Aan het eind van de eerdere regels, waarin een variabele werd aangemaakt, stond steeds een komma: er moest nog een variabele worden aangemaakt. De puntkomma geeft het definitie einde van de regel aan, er hoeven geen verder variabelen te worden aangemaakt.

Alle variabelen die de functie verderop nodig heeft, zijn hiermee gemaakt:

links bevat alle <a>'s uit div#wrapper, in de vorm van objecten.

len bevat het aantal <a>'s in links.

i bevat nog niets, maar kan als teller worden gebruikt.

Nu deze gegevens zijn gevonden en opgeslagen, kunnen ze gebruikt gaan worden om :focus-within te simuleren in browsers die dat niet ondersteunen. Daarvoor zorgt de rest van deze functie.

try {

Binnen een try-blok staat code, die mogelijk een fout kan opleveren. Er wordt geprobeerd ('try') de code uit te voeren. Als dat lukt, wordt gewoon de rest van de code uitgevoerd. Maar als een fout wordt gegenereerd, wordt de code na } catch (error) { uitgevoerd.

Het begin van het bij try horende blok code wordt aangegeven met een {, het eind met een }. In dit geval bestaat het hele blok maar uit één regel: document.querySelector(":focus-within");.

Een 'fout' moet je niet al te letterlijk nemen. In dit geval wordt gekeken, of de browser de css-pseudo-class :focus-within ondersteunt. Als dat niet zo is, wordt een fout gegenereerd.

document.querySelector(":focus-within");

Deze regel is onderdeel van een try-blok.

Het middelste stukje querySelector is een zogenaamde 'functie'. Een functie is een stukje in de browser ingebakken code, waarmee je iets kunt doen. Deze functie is te vinden in het object document, vandaar dat document ervoor staat.

Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.

JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.

Met de methode querySelector() uit document kan JavaScript onder andere een bepaalde selector opzoeken. De selector waarnaar wordt gezocht, staat tussen haakjes:

querySelector(":focus-within")

Als :focus-within niet wordt ondersteund door de browser, wordt een fout gegenereerd. In dat geval wordt die fout ('error') iets hieronder gevangen ('catch') en wordt de code achter } catch (error) { uitgevoerd.

Als geen fout wordt gegenereerd, als :focus-within door de browser wordt ondersteund, wordt de code achter } catch error { niet uitgevoerd. Er wordt dan doorgegaan met de eerste regel na het catch-blok. Omdat die regel er hier niet is, sterft het script hier een mooie, vredige dood: het stopt er gewoon mee. En dat is precies de bedoeling, want het script is alleen bedoeld voor browsers die :focus-within niet ondersteunen.

} catch (error) {

De in het catch-blok zittende code wordt alleen uitgevoerd, als door het bijbehorende try-blok een fout is gegenereerd (als de browser de css-pseudo-class :focus-within niet ondersteunt).

}: dit is de afsluitende accolade van de code van het try-blok. De openings-accolade staat bij try {.

catch (error): catch is gewoon het sleutelwoord dat aangeeft dat hier de fout wordt afgehandeld. Tussen de haakjes wordt een zogenaamd fout-object doorgegeven, waarvan de naam 'error' is. Je mag het ook 'wilhelmina' noemen in plaats van 'error', maar 'error' is min of meer een standaardnaam. Zo houd je je code 'n beetje leesbaar. Niet alleen voor jezelf, maar ook voor anderen.

In error zit een hele serie informatie over de fout, maar die wordt hier verder niet gebruikt.

{: deze accolade geeft aan dat hier de code begint die moet worden uitgevoerd, als zich een fout heeft voorgedaan. Aan het eind van deze code staat weer een afsluitende }.

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

Dit deel van het script wordt alleen uitgevoerd, als het try-blok een fout heeft gegenereerd (als de browser de css-pseudo-class :focus-within niet ondersteunt).

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

Hier eerst het deel dat ervoor zorgt dat alle <a>'s in div#wrapper worden behandeld.

(: met dit haakje opent het deel dat ervoor zorgt, dat alle (in dit voorbeeld achttien) <a>'s aan de beurt komen. Aan het eind van de regel staat de bijbehorende ), waardoor het script weet dat dit het einde van dit deel van de code is.

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

De variabele i is al eerder aangemaakt bij i, en kan daarom hier nu gewoon worden gebruikt.

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

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

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

Elke keer als een <a> is afgehandeld, 1 optellen bij 'i'. Omdat programmeurs liederlijk lui zijn, wordt 'er 1 bij optellen' afgekort tot ++.

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

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

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

(...)

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

i < len;: het middelste deel.

i bevat een getal. Als er nog geen enkele <a> is verwerkt, is dat getal 0, want dat is hierboven opgegeven.

Het teken < betekent: kleiner dan.

In len is iets hoger bij len = links.length, het aantal <a's in div#wrapper opgeslagen. In het voorbeeld is dat 18. Eigenlijk staat hier dus: i < 18;

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

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

Als niet meer aan deze voorwaarde wordt voldaan, als teller i niet meer kleiner is dan de 18 in len, stop dan met het uitvoeren van de code die tussen de {} staat. En omdat 18 even groot is als het aantal <a>'s in div#wrapper dat moet worden bekeken, geeft dit een mogelijkheid om elke <a> één keer te verwerken. En er, als ze allemaal verwerkt zijn, mee te stoppen.

): dit haakje hoort bij de ( gelijk achter for. Tussen deze twee haakjes staat de code, die ervoor zorgt dat elke <a> uit div#wrapper aan de beurt komt.

{: het laatste teken op de regel. Hiermee geef je aan dat hierna de code volgt die uitgevoerd moet worden. Tot nu toe is alleen gezorgd dat met elk item uit links, met elke <a> in div#wrapper, íéts moet gebeuren, maar nog niet wát. Dat wát volgt na deze {. Na de code die moet worden uitgevoerd staat nog een afsluitende }. Hiermee geef je aan dat het uitvoerende deel van de code hier stopt.

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

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

Aan het begin heeft i de waarde 0. Na de eerste ronde heeft i de waarde 1. Na de tweede ronde heeft i de waarde 2. Na de derde ronde heeft i de waarde 3. Na de 18e ronde heeft i de waarde 18. Waarmee i niet meer kleiner is dan de 18 in len, het aantal <a>'s.

Omdat niet meer aan de voorwaarde i < len wordt voldaan, wordt gestopt met het uitvoeren van de code tussen de {}. En dat komt goed uit, want elke <a> uit div#wrapper is precies één keer aan de beurt gekomen. Niet meer, niet minder. Bij allemaal is de tussen de {} staande code één keer toegepast.

(Wat mogelijk wat verwarrend is: het script begint te tellen met 0. De eerste <a> heeft dus volgnummer 0, en de 18e <a> heeft volgnummer 17. Ook al stopt de for-lus bij 17, er worden dus toch 18 <a>'s bekeken.)

De code tussen de haakjes in gewone taal: zet teller i op 0 als de for de eerste keer wordt uitgevoerd. Herhaal de for zolang teller i lager is dan de 18 in len. Verhoog teller i elke keer als de for wordt uitgevoerd met 1.

e.target.previousElementSibling.setAttribute("style", "width: 180px; height: 161px; border: rgba(0, 0, 0, 0.7) solid 30px; border-radius: 20px; -webkit-transform: translate(-60px, -56px); transform: translate(-60px, -56px);");

Als in de html de <a> niet gelijk op de bijbehorende <img> volgt, moet je deze regel aanpassen.

Dit deel van het script wordt alleen uitgevoerd, als het try-blok een fout heeft gegenereerd (als de browser de css-pseudo-class :focus-within niet ondersteunt).

Deze regel zit binnen een for-lus en wordt voor elke <a> binnen div#wrapper één keer uitgevoerd.

Deze regel is onderdeel van de anonieme functie die begint bij links[i].addEventListener("focus", function (e) {

e: het bij links[i].addEventListener("focus", function (e) { aan de code in de functie doorgegeven object, waarin onder andere allerlei informatie zit over de <a> die focus heeft.

target: dit is een onderdeel van het hierboven genoemde object e. In target zit, in de vorm van een object, informatie over de <a> die focus heeft. Ook dat is weer heel veel informatie: het soort element, eventuele tekst erin, nakomelingen, wat de ouder is, noem maar op.

previousElementSibling: het vorige element in de html. In het hierboven genoemde target zit, in de vorm van een object, de <a>. Omdat previousElementSibling achter target staat, gaat het om het element vóóŕ het element dat in target zit. Dat is altijd de <img> met de thumbnail die bij de <a> hoort, want dat is een van de Voorwaarden waaraan de html moet voldoen.

Ook deze <img> is weer beschikbaar in de vorm van een object, waardoor veel informatie over de <img> beschikbaar is. En allerlei methoden uit het object gebruikt kunnen worden.

setAttribute(): dit is zo'n methode. Eigenlijk is dit een gewone functie, maar omdat het om een functie uit een object gaat, werkt die soms net iets anders dan een gewone functie. Daarom wordt een functie in een object een 'methode' genoemd.

Met setAttribute() kun je een attribuut aan een element in de html toevoegen. Dat kan van alles zijn: tabindex, een WAI-ARIA-code, noem maar op. Tussen de haakjes komen de naam en de waarde van het attribuut te staan.

("style", "width: 180px; height: 161px; border: rgba(0, 0, 0, 0.7) solid 30px; border-radius: 20px; -webkit-transform: translate(-60px, -56px); transform: translate(-60px, ‑56px);"): voor de komma staat tussen aanhalingstekens de naam van het attribuut dat wordt toegevoegd, achter de komma staat tussen aanhalingstekens de waarde van het attribuut.

In dit geval levert dat style="..." op, met op de plaats van de puntjes de css die hier gelijk boven staat. Als je de aan de pagina toegevoegde css wilt bekijken moet je niet in de gewone code, maar in de Gegenereerde code kijken.

De hele regel in normale mensentaal: maak de in de html voor de <a> zittende <img> (de thumbnail) groter, zet er een border met ronde hoeken om en plaats de thumbnail in het midden van z'n ouder-<div>. Met andere woorden: deze regel doet precies hetzelfde als de selector bij #wrapper div:focus-within img, maar dan voor browsers die :focus-within niet ondersteunen.

Bij links[i].addEventListener("focus", function (e) { is geregeld dat deze regel alleen wordt uitgevoerd, als een <a> focus krijgt. Omdat een <a> focus kan krijgen door het indrukken van de Tab-toets, wordt de thumbnail nu ook vergroot voor gebruikers van de Tab-toets.

e.target.parentNode.setAttribute("style", "z-index: 10;");

Als in de html de <a> geen direct kind van de <div> met de <img> en de <a> is, moet je deze regel aanpassen.

Dit deel van het script wordt alleen uitgevoerd, als het try-blok een fout heeft gegenereerd (als de browser de css-pseudo-class :focus-within niet ondersteunt).

Deze regel zit binnen een for-lus en wordt voor elke <a> binnen div#wrapper één keer uitgevoerd.

Deze regel is onderdeel van de anonieme functie die begint bij links[i].addEventListener("focus", function (e) {

Deze regel is ongeveer hetzelfde als die iets hierboven bij e.target.previousElementSibling.setAttribute("style", "width: 180px, (...), transform: translate(-60px, -56px);");. Er zijn twee verschillen.

* In plaats van previousElementSibling (vorige element in de html) staat hier parentNode: de ouder van de <a> die wordt verwerkt. Dat is de <div> waar de <a> en de bijbehorende <img> samen in zitten.

* Er wordt hier maar één eigenschap aan de pagina toegevoegd: z-index: 10;. Als je de aan de pagina toegevoegde css wilt bekijken moet je niet in de gewone code, maar in de Gegenereerde code kijken.

De hele regel in normale mensentaal: geef aan de ouder van de <a> (de <div>) een z-index van 10. Met andere woorden: deze regel doet precies hetzelfde als de selector bij #wrapper div:focus-within, maar dan voor browsers die :focus-within niet ondersteunen.

Bij links[i].addEventListener("focus", function (e) { is geregeld dat deze regel alleen wordt uitgevoerd, als een <a> focus krijgt. Omdat een <a> focus kan krijgen door het indrukken van de Tab-toets, wordt de thumbnail volledig zichtbaar voor gebruikers van de Tab-toets.

e.target.previousElementSibling.removeAttribute("style");

Als in de html de <a> niet gelijk op de bijbehorende <img> volgt, moet je deze regel aanpassen.

Dit deel van het script wordt alleen uitgevoerd, als het try-blok een fout heeft gegenereerd (als de browser de css-pseudo-class :focus-within niet ondersteunt).

Deze regel zit binnen een for-lus en wordt voor elke <a> binnen div#wrapper één keer uitgevoerd.

Deze regel is onderdeel van de anonieme functie die begint bij links[i].addEventListener("blur", function (e) {

Als een <a> focus krijgt, wordt bij de <img> die bij die <a> hoort bij e.target.previousElementSibling.setAttribute("style", "width: 180px, (...), transform: translate(-60px, -56px);"); allerlei css aan de <img> toegevoegd. Die css zorgt voor het vergroten en juist neerzetten van de thumbnail in de <img>, en voor de border rondom de <img>. Die css verdwijnt niet vanzelf, die moet weer worden verwijderd, als de <a> de focus verliest.

Als je dat niet zou doen en met de Tab-toets alle <a>'s zou aflopen, zouden uiteindelijk alle thumbnails vergroot zijn.

Deze regel is de tegenhanger van de regel die de css toevoegt. De beschrijving staat bij die eerdere regel. Het enige verschil: hier wordt niet setAttribute gebruikt, maar removeAttribute: verwijder een attribuut. Het te verwijderen attribuut staat tussen aanhalingstekens: 'style'. Dat is het attribuut met de eerder toegevoegde css. Als je het attribuut 'style' verwijdert, verdwijnt gelijk de toegevoegde css.

e.target.parentNode.removeAttribute("style");

Als in de html de <a> geen direct kind van de <div> met de <img> en de <a> is, moet je deze regel aanpassen.

Dit deel van het script wordt alleen uitgevoerd, als het try-blok een fout heeft gegenereerd (als de browser de css-pseudo-class :focus-within niet ondersteunt).

Deze regel zit binnen een for-lus en wordt voor elke <a> binnen div#wrapper één keer uitgevoerd.

Deze regel is onderdeel van de anonieme functie die begint bij links[i].addEventListener("blur", function (e) {

Als een <a> focus krijgt, wordt bij de ouder<div> van die <a> bij e.target.parentNode.setAttribute("style", "z-index: 10;"); de z-index verhoogd naar 10. Die z-index zorgt ervoor dat thumbnail en onderschrift over de andere thumbnails komen te staan. Die css verdwijnt niet vanzelf, die moet weer worden verwijderd, als de <a> de focus verliest.

Als je dat niet zou doen en met de Tab-toets alle <a>'s zou aflopen, zouden uiteindelijk alle <div>'s een z-index van 10 hebben en staat de vergrote thumbnail met onderschrift niet meer boven de andere thumbnails.

Deze regel is de tegenhanger van de regel die de css toevoegt. De beschrijving staat bij die eerdere regel. Het enige verschil: hier wordt niet setAttribute gebruikt, maar removeAttribute: verwijder een attribuut. Het te verwijderen attribuut staat tussen aanhalingstekens: 'style'. Dat is het attribuut met de eerder toegevoegde css. Als je het attribuut 'style' verwijdert, verdwijnt gelijk de toegevoegde css.