Skip links en inhoudsopgave

Afhankelijk van het geactiveerde plaatje veranderen één tot vier plaatjes tijdelijk - uitleg

Laatst aangepast: .

Vier thumbnails naast elkaar

Korte omschrijving

Afhankelijk van welke afbeelding je aanraakt of -klikt, naar welke afbeelding je tabt of over welke afbeelding je hovert, veranderen één tot vier afbeeldingen tijdelijk.

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.

Hier is in dit voorbeeld één uitzondering op: de volgorde van de Tab-toets. Als de Tab-toets wordt gebruikt om de afbeeldingen te veranderen, gaat die in het voorbeeld van links naar rechts, zoals gebruikelijk is. Op de site gaat de Tab-toet echter in omgekeerde volgorde: van rechts naar links. Dit illustreert gelijk, welk problemen wat betreft toegankelijkheid dit voorbeeld kan opleveren, en waarom dit in de regel beter niet gebruikt kan worden. Meer daarover is te vinden bij Gebruikers Tab-toets.

Als je dit lastig vindt, kun je bovenaan de pagina de hele handel 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 onderstippeld blauw. 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.

Achterliggend idee

In eerste instantie zijn vier gewone afbeeldingen zichtbaar.

Als de eerste afbeelding wordt aangeraakt of -geklikt, als naar de eerste afbeelding wordt getabt of als over de eerste afbeelding wordt gehoverd, wordt de eerste afbeelding vervangen.

Als hetzelfde gebeurt bij de tweede afbeelding, worden de eerste én de tweede afbeelding vervangen.

Als hetzelfde gebeurt bij de derde afbeelding, worden de eerste, de tweede én de derde afbeelding vervangen.

En als hetzelfde gebeurt bij de vierde afbeelding, worden alle vier de afbeeldingen vervangen.

Eerdere versies moesten ook werken in Internet Explorer 6. Daarom waren in die versies de vier originele afbeeldingen gewone <img>'s, die in een <a> zaten. De vervangende afbeeldingen waren achtergrond-afbeeldingen. In Internet Explorer 6 werkte hoveren alleen boven een <a>, vandaar. Omdat deze sadistische ellendepukkel niet meer ondersteund hoeft te worden, zijn alle afbeeldingen nu gewone afbeeldingen. De originele en de bijbehorende vervangende afbeelding zitten steeds samen in dezelfde <span>.

Voor de plaatsing van de afbeeldingen wordt flexbox gebruikt, omdat dit veel simpeler en geschikter is dan de eerdere constructies met float.

Deze constructie levert wel een aantal problemen op. Als je over de vierde afbeelding hovert, of deze aanraakt of - klikt, moeten de eerste drie afbeeldingen worden vervangen. Maar er bestaat geen selector, waarmee je iets kunt veranderen in eerdere html. Dat is voor aanraken, klikken en de Tab-toets nog wel op te lossen, maar niet voor hoveren.

Bij aanraken, klikken en de Tab-toets kun je bij het element waar de <span>'s in zitten de pseudo-class :focus-within gebruiken. Je kunt dan alle vervangende afbeeldingen zichtbaar maken, en de afbeeldingen uit de <span>'s die na de <span> met de focus komen weer verbergen. Of zoiets. Dan werkt het van voor naar achter, en dat gaat prima met css.

Voor hoveren kan dit niet, want er bestaat niet zoiets als :hover-within.

Daarom is in de html de volgorde van de <span>'s - en daarmee van de daarin zittende afbeeldingen - omgedraaid. Op het scherm wordt die volgorde nogmaals omgedraaid, waardoor de <span>'s met de afbeeldingen weer in de juiste volgorde staan.

De vierde afbeelding op het scherm is in de html de eerste afbeelding, en de eerste afbeelding op het scherm is in de html de laatste afbeelding. Nu kan gewoon gebruik worden gemaakt van de 'general sibling combinator' ~: doe iets met het element dat op een ander element volgt.

Dit levert wel een aantal problemen op voor gebruikers van de Tab-toets en voor gebruikers van een Schermlezer.

De Tab-toets volgt altijd de volgorde van de html, ongeacht de volgorde op het scherm. Omdat de weergave op het scherm andersom is als de volgorde in de html, begint de Tab-toets met de laatste <span> op het scherm, waarbij gelijk alle vier de vervangende afbeeldingen worden getoond. Bij het nogmaals indrukken van de Tab-toets wordt de derde <span> bezocht en worden de eerste drie vervangende afbeeldingen getoond. Precies omgekeerd aan wat eigenlijk de bedoeling is. In het voorbeeld is dit met een tabindex opgelost, maar meestal zal dat niet kunnen. Meer hierover is te vinden bij Gebruikers Tab-toets.

Ook een schermlezer volgt altijd de volgorde in de html, ongeacht de volgorde op het scherm. Bovendien krijgt een schermlezer de vervangende afbeeldingen helemaal niet te zien. Daarom wordt bovenaan het voorbeeld aan schermlezers de mogelijkheid gegeven alle afbeeldingen te tonen, waarbij de volgorde op het scherm in één moeite door hetzelfde wordt gemaakt als die in de html. Meer hierover is te vinden bij Schermlezers.

Voor dit soort constructies kan eigenlijk beter gebruik worden gemaakt van JavaScript. Dan kan de volgorde in de html hetzelfde blijven als die op het scherm. Met JavaScript kun je dan vaststellen over welke afbeelding wordt gehoverd. (Voor aanraken en klikken en voor de Tab-toets zou dat ook met alleen css kunnen door gebruik te maken van de pseudo-class :focus-within.)

Bij vier afbeeldingen is dit nog niet zo'n probleem, maar bij meer afbeeldingen zal het al snel heel erg onoverzichtelijk worden als de volgorde omgekeerd is aan wat mensen verwachten.

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 Edge, 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 en Edge gebruiken Blink.)

Internet Explorer: -ms-, naar de maker: Microsoft.

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 Firefox herkent -moz-appearance. Zodra Firefox appearance gaat herkennen, zal dit moz-appearance overrulen, omdat het er later in staat. Dat ze er beide in staan, is dus geen enkel probleem.

In dit voorbeeld wordt appearance gebruikt.

appearance

Op dit moment moet je nog het volgende schrijven:

{-moz-appearance: ...; -webkit-appearance: ...; appearance: ...;}

In de toekomst kun je volstaan met:

{appearance: ...;}

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 niet meer gebruikt. Nieuwe, experimentele css-eigenschappen zitten inmiddels 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.

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

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

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

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

tabindex="-1"

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

In dit voorbeeld wordt tabindex="-1" voor twee andere dingen gebruikt. De vervangende afbeeldingen worden getoond door een <span> met een originele afbeelding aan te raken. (Of op andere manieren, maar die zijn hier niet van belang.) Daardoor krijgt die <span> focus en worden één of meer vervangende afbeeldingen getoond. Door het scherm ergens buiten die <span> aan te raken, verliest de <span> weer de focus en verdwijn of verdwijnen de vervangende afbeelding of afbeeldingen weer.

Behalve op iOS en iPadOS. Daar verliest de <span> pas weer de focus, als een ander element de focus krijgt. Buiten de <span>'s zijn er echter in dit voorbeeld geen elementen die de focus kunnen krijgen. Dat betekent dat er altijd minimaal één vervangende afbeelding zichtbaar is op iOS en iPadOS, als er eenmaal eentje is getoond. Want je kunt een vervangende afbeelding alleen weer verbergen, door een ander element de focus te geven. En in dit voorbeeld is dat dus altijd een <span>, waardoor dan altijd in ieder geval de bij die <span> horende vervangende afbeelding weer wordt getoond.

Om dit op te lossen heeft <main> een tabindex gekregen:

<main tabindex="-1">

Nu kan <main> ook de focus krijgen. Als dat gebeurt, verliest de <span> de focus en verdwijnt of verdwijnen de vervangende afbeelding of afbeeldingen weer. Met behulp van css wordt ervoor gezorgd dat <main> altijd minstens even hoog is als het venster van de browser. Hierdoor kunnen vervangende afbeeldingen altijd weer worden verborgen, ongeacht waar je het venster aanraakt.

Je zou ook tabindex="0" kunnen gebruiken, maar dan wordt <main> ook bezocht, als de Tab-toets wordt ingedrukt. Waardoor gebruikers van de Tab-toets pas bij een tweede keer indrukken van de Tab-toets de eerste vervangende afbeelding zien verschijnen. Door '-1' te gebruiken, wordt <main> genegeerd door de Tab-toets.

Voor schermlezers is een input#schermlezer aangebracht, waarmee alle afbeeldingen gelijktijdig kunnen worden getoond. Ook deze <input> zou door de Tab-toets worden bezocht, wat ook bij deze <input> nutteloos en verwarrend is. Daarom wordt ook deze voorzien van een negatieve tabindex:

<input id="schermlezer" type="checkbox" tabindex="-1">

tabindex="..."

Op de plaats van de puntjes moet een positief getal worden ingevuld: het volgnummer. Een element met een positieve tabindex wordt altijd bezocht bij gebruik van de Tab-toets, ook als dit element normaal genomen zou worden genegeerd. Elementen met een tabindex met een positief volgnummer worden altijd als eerste bezocht, voor elementen als een link of tekstveld zonder tabindex, en ook voor elementen met tabindex="0".

Hierbij wordt de volgorde van de volgnummers aangehouden: van laag naar hoog.

In dit voorbeeld hebben de vier <span>'s met de afbeeldingen een volgnummer:

<span tabindex="4"> (...) </span>

<span tabindex="3"> (...) </span>

<span tabindex="2"> (...) </span>

<span tabindex="1"> (...) </span>

Bij de weergave op het scherm is de volgorde van de <span>'s (en daarmee van de erin zittende afbeeldingen) precies andersom als de volgorde in de html: de laatste <span> in de html staat op het scherm vooraan, de eerste <span> in de html staat achteraan op het scherm.

Maar de Tab-toets volgt standaard de volgorde in de html. Daardoor zou de laatste <span> op het scherm als eerste worden bezocht. Door met behulp van tabindex de volgorde om te keren, wordt de laatste <span> in de html nu als eerste bezocht, en de eerste <span> in de html als laatste. Hierdoor werkt de Tab-toets op het scherm zoals gebruikelijk: van links naar rechts en van boven naar onder.

Dit lijkt een leuke oplossing, maar dat is niet zo. In het voorbeeld werkt dit prima, omdat alleen de <span>'s door de Tab-toets worden bezocht. Maar op vrijwel elke pagina zullen meer elementen aanwezig zijn, die door de Tab-toets worden bezocht. Daarom werkt dit bijvoorbeeld op de site niet goed, zoals iets hieronder bij tabindex="0" wordt beschreven.

Daarom is op de site het positieve volgnummer bij tabindex vervangen door tabindex="0". Nu wordt op de site de gebruikelijke volgorde van de Tab-toets aangehouden. Dat betekent echter ook, dat op de site de <span>'s van achter naar voren worden bezocht door de Tab-toets. Dat is voor vier afbeeldingen misschien nog niet zo'n groot probleem, maar bij meer afbeeldingen zal het al snel onwerkbaar worden.

In de meeste gevallen is deze constructie daarom niet bruikbaar en is iets dat werkt met behulp van JavaScript, waarbij de volgorde op het scherm hetzelfde kan zijn als die in de html, beter.

tabindex="0"

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

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

(In de praktijk blijkt trouwens dat alle browsers de volgorde van de html aanhouden bij tabindex="0", nadat eerst alle tabindexen met een positief nummer zijn bezocht.)

In het voorbeeld uit de download hebben de vier <span>'s een tabindex met een positief volgnummer, zoals hierboven bij tabindex="..." is beschreven. In het voorbeeld werkt dat prima, omdat er verder geen enkele link of zoiets aanwezig is.

Op de site werkt dit niet goed, want daar is onder andere een menu aanwezig. Als de <span>'s een tabindex met een positief volgnummer krijgen, worden eerst de <span>'s bezocht, en pas daarna alle andere links en dergelijke. Hoogst verwarrend.

Daarom zijn op de site de vier tabindex-attributen met positieve volgnummers vervangen door tabindex="0". Nu wordt de volgorde van de html aangehouden. Maar dat betekent ook dat op de site, bij gebruik van de Tab-toets, de laatste <span> als eerste wordt bezocht, en de eerste <span> als laatste. Bij vier afbeeldingen is het mogelijk niet zo'n probleem, als de afbeeldingen van rechts naar links worden bezocht, maar bij meer afbeeldingen zal het al snel chaotisch worden.

In de meeste gevallen is deze constructie daarom niet bruikbaar en is iets dat werkt met behulp van JavaScript, waarbij de volgorde op het scherm hetzelfde kan zijn als die in de html, beter.

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 is er een verschil tussen hoveren en klikken, maar op een touchscreen is dat verschil er niet: je raakt een touchscreen aan of niet. Dat levert vooral soms problemen op, als bij een element 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 is er een verschil tussen hoveren en klikken, maar op een touchscreen is dat verschil er niet: je raakt een touchscreen aan of niet. Dat levert vooral soms problemen op, als bij een element :hover én klikken worden gebruikt, zoals bij een link die bij hoveren erover verkleurt. Omdat deze combinatie niet wordt gebruikt in dit voorbeeld, spelen deze problemen niet. Een aanraking op een touchscreen werkt in dit geval hetzelfde als hoveren met een muis.

Omdat hoveren op een touchscreen als een aanraking wordt verwerkt, krijgt de <span> die wordt aangeraakt focus. Dat levert op iOS en iPadOS problemen op, die gelijk hieronder bij :focus worden besproken.:hover én klikken worden gebruikt, zoals bij een link die bij hoveren erover verkleurt. Omdat deze combinatie niet wordt gebruikt in dit voorbeeld, spelen deze problemen niet. Een aanraking op een touchscreen werkt in dit geval hetzelfde als hoveren met een muis.

Omdat hoveren op een touchscreen als een aanraking wordt verwerkt, krijgt de <span> die wordt aangeraakt focus. Dat levert op iOS en iPadOS problemen op, die gelijk hieronder bij :focus worden besproken.

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

Normaal genomen wordt een <span> door de Tab-toets genegeerd, maar door het toevoegen van een tabindex kunnen de vier <span>'s met de afbeeldingen toch door de Tab-toets worden bezocht en focus krijgen.

Door diezelfde tabindex kan een <span>, als erop wordt geklikt, de focus krijgen. Hierdoor blijft of blijven de vervangende afbeelding of afbeeldingen na klikken zichtbaar, ook als de muis weer van de <span> wordt afgehaald.

Op een touchscreen is de focus eigenlijk niet van belang, want bij hoveren over een <span> wordt of worden de vervangende afbeelding of afbeeldingen al getoond. En op een touchscreen wordt hoveren op dezelfde manier afgehandeld als een aanraking. Maar omdat de <span>'s een tabindex hebben, krijgen de <span>'s ook bij een aanraking de focus. Als het scherm ergens buiten de <span>'s wordt aangeraakt, verliest de <span> de focus weer en verdwijnen de vervangende afbeeldingen.

Behalve op iOS en iPadOS. Daar verliest een element pas de focus, als een ander element de focus krijgt. En in het voorbeeld zijn zulke elementen er niet: alleen de vier <span>'s kunnen de focus krijgen. Op de site zijn zulke elementen er wel, maar daar heb je weinig aan. Bijvoorbeeld de links in het menu kunnen ook focus krijgen, waardoor de vervangende afbeeldingen weer sluiten. Maar dan ga je ook gelijk naar een andere pagina, dus dat is een wat ruige manier om vervangende afbeeldingen weer te verbergen.

Daarom heeft speciaal voor iOS het element <main> ook een tabindex gekregen:

<main tabindex="-1">

Nu kan ook <main> de focus krijgen, waardoor de vervangende afbeeldingen sluiten. Een uitgebreider verhaal hierover staat bij tabindex="-1".

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

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 13 juli 2020.

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 ppi):
Firefox, Google Chrome, Internet Explorer 11 en Edge, in grotere en kleinere browservensters.

OS X 10.14.6 ('Mojave') (1680 x 1050 px, resolution: 96 ppi, device-pixel-ratio: 1):
Firefox, Safari, Google Chrome en Microsoft Edge, in grotere en kleinere browservensters.

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

Laptops

Windows 8.1 (1366 x 768 px, resolution: 135 ppi):
Bureaublad-versie: Firefox, Google Chrome, Internet Explorer 11 en Edge, in grotere en kleinere browservensters.
Startscherm-versie: Internet Explorer 11.

Windows 10 (1600 x 900 px, resolution: 106 ppi):
Firefox, Google Chrome, Internet Explorer 11 en Edge, in grotere en kleinere browservensters.

Tablets

iPad met iOS 12.4.7 (2048 x 1536 px, device-pixel-ratio: 2:
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).

iPad met iPadOS 13.5 (2160 x 1620 px, 264 ppi):
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).

Android 4.4.2 ('Kitkat') (1280 x 800 px, resolution: 149 ppi):
Firefox en Chrome (alle portret en landschap).

Android 4.4.2 ('Kitkat') (2560 x 1600 px, resolution: 299 ppi):
Firefox en Chrome (alle portret en landschap).

Android 6.0 ('Marshmallow') (1920 x 1200 px, resolution: 224 ppi):
Samsung Internet, Firefox en Chrome (alle portret en landschap).

Android 8.1.0 ('Oreo') (1920 x 1200 px, resolution: 218 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).

Android 10 (2000 x 1200 px, resolution: 225 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).

Smartphones

Windows 10 Mobile (1280 x 720 px, resolution: 315 ppi):
Edge.

iPhone met iOS 10.3.1 (1334 x 750 px, 326 ppi) (gesimuleerd in Xcode):
Safari (portret en landschap).

iPhone met iOS 12.4 (1334 x 750 px, 326 ppi) (gesimuleerd in Xcode):
Safari (portret en landschap).

iPhone met iOS 13.5 (1334 x 750 px, 326 ppi):
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).

Android 7.0 ('Nougat') (1280 x 720 px, resolution: 294 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).

Android 9.0 ('Pie') (1920 x 1080 px, resolution: 424 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle 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.

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, 8.1.0 en 9.0

VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS 12.4.7, 13.5, iPadOS 13.5 en OS X 10.14.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 html-validator, de css met de css-validator van w3c. 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 geen problemen aanwezig zijn, staat in een smal groen kadertje 'Geen problemen'. Bij een onderwerp over toegankelijkheid zijn er soms geen problemen, maar alleen aanpassingen. Ook in dat geval staat bovenaan in een smal groen kadertje 'Geen problemen'. Daaronder staan dan de aanpassingen.

Als in een onderdeel één of meer problemen worden besproken, staat van elk probleem in een breed rood kadertje een korte samenvatting daarvan.

Als bij het probleem een oplossing wordt gegeven, staat de samenvatting in een rode stippellijn.

Als bij het probleem geen oplossing is gevonden, staat de samenvatting in een rode ononderbroken lijn.

Zonder JavaScript

Geen problemen.

Omdat JavaScript niet wordt gebruikt, heeft het aan- of uitstaan van JavaScript geen enkel effect.

Zonder css

Geen problemen.

Omdat de vervangende afbeeldingen worden verborgen met behulp van css, zijn zonder css de originele én de vervangende afbeeldingen allemaal zichtbaar. Ook is de voor schermlezers bedoelde tekst zichtbaar.

De opmaak is natuurlijk volledig verdwenen, maar er verdwijnt geen informatie.

Zonder afbeeldingen

Geen problemen

Eh, tja, je ziet natuurlijk geen afbeeldingen. Dus je hebt niets aan dit voorbeeld. Maar als je ervoor kiest om geen afbeeldingen te zien, dan kun je het moeilijk een probleem noemen, als je geen afbeeldingen ziet.

(Mensen die hier anders over denken verwijs ik graag naar een filosofisch café, waar ze gezellig urenlang met geestverwanten kunnen filosoferen, of dit nu wel of geen probleem is.)

Wat je wel ziet: de alt-tekst van de originele afbeeldingen. En in sommige browsers staat de alt-tekst van de vervangende afbeeldingen daar doorheen. Omdat het wat onwaarschijnlijk lijkt dat mensen die geen afbeeldingen willen zien wel gezellig 'n avond lang alt-teksten gaan lezen, is dit verder niet per browser uitgezocht.

Gebruikers Tab-toets

Probleem: zonder correctie gaat de Tab-toets in omgekeerde volgorde de <span>'s af.

De Tab-toets volgt altijd de volgorde van de elementen in de html, ongeacht de volgorde op het scherm. Dit levert grote problemen op.

Als over de eerste <span> wordt gehoverd, moet de eerste afbeelding veranderen. Als over de tweede <span> wordt gehoverd, moeten de eerste twee afbeeldingen veranderen. Als over de derde <span> wordt gehoverd, moeten de eerste drie afbeeldingen veranderen. En als over de vierde <span> wordt gehoverd, moeten alle vier de afbeeldingen veranderen.

Er bestaat echter geen selector die 'van achter naar voren' werkt. Je kunt, als je over de vierde <span> hovert, nooit met alleen css iets doen met de eerdere <span>'s.

Daarom is de volgorde van de <span>'s in de html omgekeerd: de vierde <span> staat als eerste in de html, de eerste als vierde. Met behulp van css wordt op het scherm de volgorde van de <span>'s nogmaals omgedraaid: op het scherm staat de vierde <span> uit de html vooraan, en de eerste <span> uit de html staat achteraan.

Daardoor is ook de volgorde van de in de <span>'s zittende afbeeldingen op het scherm andersom als de volgorde in de html.

Omdat de selector kijkt naar de volgorde in de html, lijkt het nu alsof een latere <span> op het scherm iets met een eerdere <span> kan doen. In werkelijkheid werkt het dus gewoon net zoals altijd, alleen is de zichtbare volgorde op het scherm omgedraaid. Nu werkt hoveren ook.

Helaas volgt de Tab-toets altijd de volgorde van de html, ongeacht de volgorde op het scherm. De Tab-toets begint hierdoor bij de vierde <span> op het scherm, want die is de eerste <span> in de html. Daarna volgt de derde <span> op het scherm, dan de tweede en als laatste de eerste.

Hoogst verwarrend. Bij vier afbeeldingen, zoals in dit voorbeeld, is het misschien nog te overzien. Maar bij iets meer afbeeldingen wordt het al snel een enorme puzzel, als de Tab-toets van achter naar voren blijkt te werken.

Daarom is met behulp van een tabindex de volgorde van de Tab-toets aangepast:

<span tabindex="4"> (...) </span> <span tabindex="3"> (...) </span> <span tabindex="2"> (...) </span> <span tabindex="1"> (...) </span>

De Tab-toets volgt de volgorde van het volgnummer bij tabindex, dus nu gaat de Tab-toets eerst naar de laatste <span>, dan naar de derde, naar de tweede, en als laatste naar de eerste <span>. Precies de volgorde zoals de <span>'s op het scherm staan. Waarmee het probleem ogenschijnlijk op geniale wijze is opgelost.

Ogenschijnlijk. En genieën veroorzaken vaak meer problemen dan ze oplossen. Zoals kernwapens. Maar nu dwaal ik mogelijk 'n tikkeltje af.

In het voorbeeld werkt deze oplossing prima. Maar op de site gaat het gigantisch mis in datzelfde voorbeeld. En het zal op vrijwel elke pagina gigantisch mis gaan.

Een tabindex met een positief nummer wordt door de Tab-toets eerder bezocht dan elementen zonder tabindex of met tabindex="0". Op de site staat bovenaan de pagina een menu. Daarin zitten links zonder tabindex. Deze worden nu, bij gebruik van de Tab-toets, pas bezocht nadat de <span>'s uit het voorbeeld zijn bezocht. Heel verwarrend.

Dit probleem zal op vrijwel elke pagina spelen, omdat vrijwel overal meer elementen als links of tekstvelden aanwezig zullen zijn, die bij gebruik van de Tab-toets worden bezocht.

Op de site is dit opgelost door bij de <span>'s de tabindex in elke <span> het volgnummer '0' te geven. Nu worden de <span>'s gewoon in de volgorde van de html bezocht, net als alle andere elementen op de site. (Op de site worden geen volgnummers bij de tabindex gebruikt, en dan wordt gewoon de volgorde uit de html gevolgd.)

Maar op de site worden de afbeeldingen nu in omgekeerde volgorde bezocht door de Tab-toets: van rechts naar links. Bovendien gebeurt het tonen van de vervangende afbeeldingen nu ook ietwat eigenaardig. Als de Tab-toets voor de eerste keer wordt ingedrukt, wordt de laatste <span> als eerste bezocht. Daardoor worden alle vier de vervangende afbeeldingen getoond. Als de Tab-toets nogmaals wordt ingedrukt, wordt de derde <span> bezocht, en worden de eerste drie vervangende afbeeldingen getoond, enzovoort. Precies omgekeerd van wat de bedoeling is.

Dit is zonder JavaScript niet op te lossen. Klikken, aanraken en de Tab-toets zijn met behulp van alleen css werkend te krijgen. Je zou bijvoorbeeld met behulp van div#wrapper:focus-within alle vervangende afbeeldingen kunnen tonen, en dan in de <span>'s volgend op de <span> met focus de vervangende afbeeldingen weer kunnen verbergen.

Hoveren is onmogelijk op te lossen met alleen css. Daarom is deze constructie eigenlijk niet goed bruikbaar. Beter kun je met JavaScript kijken over welke <span> precies wordt gehoverd, en vervolgens de vervangende afbeeldingen uit de <span>'s daarvoor ook tonen. De volgorde op het scherm kan dan hetzelfde blijven al de volgorde in de html, waardoor de Tab-toets gewoon van link naar rechts blijft werken.

Tekstbrowsers

Geen problemen.

Lynx en WebbIE tonen beide de tekst voor de schermlezer en de alt-teksten bij de alle acht afbeeldingen, de originele en de vervangende.

Schermlezers

Probleem: deze constructie werkt niet in schermlezers.

Allereerst: waarom zou je afbeeldingen willen tonen in een schermlezer? Simpel: omdat lang niet iedereen die een schermlezer gebruikt helemaal blind is.

Schermlezers lezen weliswaar netjes de alt-tekst van elke afbeelding voor, maar de vervangende afbeeldingen worden niet getoond.

In principe zou je dit kunnen oplossen met behulp van WAI-ARIA-codes (codes speciaal voor schermlezers) en JavaScript, maar dat werkt eigenlijk niet echt betrouwbaar. Om te beginnen is het ongelooflijk ingewikkeld. Maar het grootste probleem: elke schermlezer doet het weer net iets anders. Bovendien heeft niet elke gebruiker de laatste versie, want sommige schermlezers zijn wanstaltig duur. En dan is er ook nog 'n vrijwel onbeperkt aantal combinaties mogelijk. Als iets werkt in Windows 10 met Edge en NVDA, is er geen enkele garantie dat het ook werkt in Firefox met NVDA op datzelfde systeem.

Daarom is voor een andere constructie gekozen. In div#voor-schermlezers staat een tekst, die speciaal voor schermlezers is bedoeld. Deze tekst staat links buiten het scherm, zodat de opmaak van de pagina niet wordt verstoord. Deze tekst wijst op de mogelijkheid een aankruisvakje input#schermlezer aan te vinken, waardoor alle acht de afbeeldingen gelijktijdig worden getoond.

Dit aanvinken van een aankruisvakje werkt wel probleemloos in alle geteste schermlezers. Het hoort zelfs te werken als het aankruisvakje buiten het scherm staat, maar in Android ouder dan versie 8.1 kan het aankruisvakje dan toch niet worden aangevinkt. Omdat deze Android-versies nog veel worden gebruikt, wordt het aankruisvakje daarom binnen het venster van de browser gezet. Door het aankruisvakje heel klein te maken, is het feitelijk onmogelijk het per ongeluk aan te raken of aan te klikken. Tijdens het testen is dit in ieder geval niet gelukt.

Dit geeft gelijk de mogelijkheid een ander probleem op te lossen. Net als de Tab-toets volgt een schermlezer altijd de volgorde van de html, ongeacht de volgorde op het scherm. En op het scherm is de volgorde van de <span>'s omgekeerd als de volgorde in de html: de eerste <span> uit de html wordt als laatste op het scherm getoond, en de vierde <span> uit de html is op het scherm de eerste. Daardoor worden ook de afbeeldingen in omgekeerde volgorde op het scherm gezet.

Een schermlezer leest de alt-teksten dus van achter naar voren: eerst de vierde alt-tekst, dan de derde, enzovoort. Of eigenlijk: eerst de alt-tekst bij de vierde originele afbeelding, dan de alt-tekst bij de vierde vervangende afbeelding, dan de alt-tekst bij de derde originele afbeelding, de alt-tekst bij de derde vervangende afbeelding, enzovoort.

Als daarvoor wordt gekozen, worden de vervangende afbeeldingen ook getoond. Omdat de opmaak dan toch al verandert, wordt gelijktijdig de volgorde van de <span>'s met de afbeeldingen op het scherm hetzelfde gemaakt als de volgorde in de html. Dat geeft een snelle wisseling van afbeeldingen, maar dat valt niet echt op, omdat die wisseling er toch al is door het zichtbaar maken van de vervangende afbeeldingen.

Zoomen en andere lettergrootte

Geen problemen.

Alle browsers

Probleem: de originele afbeeldingen kunnen niet worden gekopieerd.

Zolang de css aanstaat, is het onmogelijk de originele afbeeldingen te kopiëren. Zodra je met de muis boven een <span> met originele afbeelding komt, of zodra je zo'n <span> aanraakt of -klikt of er met de Tab-toets naartoe gaat, verdwijnt de originele afbeelding immers. Alleen als je css uitzet, kun je de originele afbeeldingen kopiëren.

De vervangende afbeeldingen kunnen wel probleemloos worden gekopieerd.

(Dit is trouwens absoluut geen kopieerbeveiliging, want als bijvoorbeeld css uitzet, zijn de originele afbeeldingen gewoon te kopiëren. En er zijn nog tig andere simpele manieren.)

Wijzigingen

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

:

Nieuw opgenomen.

25 maart 2009:

Tekst aangepast voor de nieuw verschenen Internet Explorer 8. De code hoefde niet te worden veranderd.

2 december 2009:

1 november 2011:

Afbeeldingen begrijpelijke namen gegeven. Voor dit voorbeeld is dat eigenlijk niet van belang, maar normaal genomen wel. Zoekmachine, schermlezers, enzovoort begrijpen 'vuurtoren.jpg' toch iets beter dan '04a.jpg'.

13 juli 2020:

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

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

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

042-css-dl:

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

042-pics:

Acht afbeeldingen: vier originele en vier vervangende.

De afbeeldingen zijn afkomstig van pixabay.com/nl. De licentie is te vinden op pixabay.com/nl/service/license-summary en komt er ongeveer op neer dat je alles met de afbeeldingen mag doen, behalve verkopen en gebruiken voor illegale doeleinden.

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 onderstippeld blauw. 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 de afbeeldingen, als ze niet meer naast elkaar passen, onder elkaar gezet.

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.

<main tabindex="-1">

Als op iOS en iPadOS een <span> met een afbeelding wordt aangeraakt, worden één of meer vervangende afbeeldingen getoond. Weer verbergen van die vervangende afbeeldingen kan alleen door het aanraken van een ander element dat reageert op :hover of dat de focus kan krijgen. In dit voorbeeld zijn dat echter alleen de <span>'s, waardoor altijd minstens één vervangende afbeelding zichtbaar blijft.

Door <main> een tabindex te geven, reageert <main> ook op een aanraking. Waardoor de vervangende afbeeldingen weer worden verborgen, als <main> ergens wordt aangeraakt. Bij html, main en body wordt met height: 100%; gezorgd dat <main> altijd even hoog is als het venster van de browser. Hierdoor maakt het niet uit, waar je het scherm aanraakt: de vervangende afbeeldingen worden altijd gesloten.

<div id="voor-schermlezers">

De tekst binnen deze <div> wordt bij #voor-schermlezers links buiten het scherm geplaatst, waardoor deze onzichtbaar is. Voor schermlezers maakt dat niets uit: de tekst wordt gewoon voorgelezen.

<input id="schermlezer" type="checkbox" tabindex="-1">

Deze <input> is alleen van belang voor schermlezers. Bij #schermlezer wordt hij vrijwel onzichtbaar gemaakt. Helemaal onzichtbaar maken kan niet, want dan werkt de <input> niet in Android ouder dan versie 8.1. Om dezelfde reden kan deze <input> ook niet buiten het browservenster worden geplaatst. Maar omdat de <input> vrijwel onzichtbaar is, is het eigenlijk onmogelijk deze per ongeluk aan te raken of te -klikken. (Tijdens het testen lukte dat niet.) Ook wordt de lay-out niet verstoord door deze <input>

Als deze <input> wordt aangevinkt, worden de vervangende afbeeldingen allemaal zichtbaar gemaakt, waardoor deze ook in schermlezers zijn te zien. Bovendien wordt de volgorde van de afbeeldingen op het scherm gelijk aan de volgorde van de afbeeldingen in de html, zodat ze van links naar rechts worden voorgelezen. Dit gebeurt met de css bij #schermlezer:checked ~ span en verder.

Als mensen de Tab-toets gebruiken om links, <input>'s, en dergelijke af te lopen, zou ook deze <input> worden bezocht. Dat heeft echter voor deze gebruikers geen enkel nut. Om de Tab-toets deze <input> te laten negeren, is het attribuut tabindex=-"1" toegevoegd.

<label id="label-voor-schermlezer" for="schermlezer">Toon alle afbeeldingen</label>

De <label> die bij de <input id="schermlezer"> gelijk hierboven hoort. Deze <label> is niet zichtbaar, omdat hij boven het venster van de browser staat. Dat maakt voor schermlezers echter niets uit: de tekst erin wordt gewoon voorgelezen. Maar omdat de <label> niet zichtbaar is, verstoort deze de lay-out niet.

Als de bijbehorende <input> is aangevinkt, wordt de <label> bij #schermlezer:checked + #label-voor-schermlezer zichtbaar gemaakt, samen met de bijbehorende input#schermlezer. Op die manier is het duidelijk, hoe je de weergave weer naar standaard kunt terugzetten. Zonder dat zichtbaar maken zou dat alleen duidelijk zijn voor gebruikers van een schermlezer.

<span tabindex="4">

<span tabindex="3"> <span tabindex="2"> <span tabindex="1">

De vier <span>'s met de afbeeldingen.

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. Dit is een belangrijk hulpmiddel voor mensen die om een of andere reden de muis niet kunnen of willen gebruiken.

Een <span> wordt normaal genomen genegeerd door de Tab-toets, maar door het toevoegen van een tabindex kunnen de <span>'s bij gebruik van de Tab-toets toch focus krijgen, waardoor ook voor gebruikers van de Tab-toets de vervangende afbeeldingen zichtbaar kunnen worden.

De Tab-toets volgt altijd de volgorde van de elementen in de html, ongeacht de volgorde op het scherm. Omdat de <span>'s met de afbeeldingen op het scherm in omgekeerde volgorde worden getoond, heeft de eerste <span> in de html het hoogste volgnummer, en de laatste <span> in de html heeft het laagste volgnummer. De Tab-toets volgt de volgnummers bij de tabindex, dus nu wordt door de Tab-toets de laatste <span> in de html als eerste bezocht, en de eerste <span> in de html als laatste. Omdat de <span>'s op het scherm in omgekeerde volgorde worden getoond, volgt de Tab-toets op het scherm nu toch de volgorde van de <span>'s op het scherm: van links naar rechts.

Het gebruik van een tabindex met een positief volgnummer kan grote problemen opleveren, wat betreft toegankelijkheid. Ook is het meestal niet bruikbaar. Zo zijn op de site de volgnummers alle vier vervangen door '0', omdat anders de volgorde van de Tab-toets op de site niet meer klopte.

Over deze problemen is meer te vinden bij tabindex="..." en tabindex="0".

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

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

html, main

Alle <html>'s en <main>'s.

<html> is het buitenste element, daar is er altijd maar één van. Van <main> is er ook maar één: de belangrijkste inhoud van de pagina staat erin. Hier is dat de hele pagina.

Normaal genomen zul je bij <html> een id gebruiken, omdat de css anders voor álle pagina's geldt, want elke pagina heeft nou eenmaal <html>. Dat werkt precies hetzelfde als een id bij andere tags:

<html id="ik-ben-een-id">

In de css komt dan te staan:

#ik-ben-een-id {...} of html#ik-ben-een-id {...}

Op de site bijvoorbeeld is dit opgelost door het gebruik van:

<html lang="nl" id="h-042"> height: 100%;

Een hoogte in procenten is normaal genomen ten opzichte van de ouder van het element.

<html> is het buitenste element, daarom wordt dit normaal genomen even hoog als het venster van de browser.

De ouder van <main> is <body>, die gelijk hieronder met height: 100%; even hoog wordt gemaakt als z'n ouder <html>. <main> wordt hierdoor ook even hoog als <html>, en omdat <html> even hoog is als het browservenster, is <main> dat ook.

Deze hoogte is nodig om op iOS en iPadOS de vervangende afbeeldingen weer te kunnen verbergen, zoals uitgebreider wordt beschreven bij tabindex="-1".

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.

Sommige eigenschappen, zoals font-family en margin, die hieronder bij <body> worden gebruikt, zullen geen probleem zijn, als ze op alle pagina's van een site worden gebruikt. Maar bij een eigenschap als height: 100%; kan het wel een probleem zijn, als die op elke pagina wordt gebruikt. Als alleen body als selector wordt gebruikt, geldt die selector voor élke pagina.

Normaal genomen zul je daarom, als je een ietwat bijzondere eigenschap bij <body> gebruikt, <body> met een id gebruiken, omdat de css anders voor álle pagina's geldt, want elke pagina heeft nou eenmaal <body>. Dat werkt precies hetzelfde als een id bij andere tags:

<body id="ik-ben-een-id">

In de css komt dan te staan:

#ik-ben-een-id {...} of body#ik-ben-een-id {...}

Op de site bijvoorbeeld is dit opgelost door het gebruik van:

<body id="b-042"> 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: 100%;

Een hoogte in procenten is normaal genomen ten opzichte van de ouder van het element. De ouder van <body> is <html>, die bij html, main even hoog is gemaakt als het venster van de browser. Hierdoor wordt ook <body> even hoog als het venster.

Deze hoogte is nodig om op iOS en iPadOS de vervangende afbeeldingen weer te kunnen verbergen, zoals uitgebreider wordt beschreven bij tabindex="-1".

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.

font-size: 110%;

Iets groter dan standaard. 't Zal de leeftijd zijn, maar ik vind de standaardgrootte wat te klein.

Als eenheid wordt de relatieve eenheid % 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.

margin: 0;

Slim om te doen vanwege verschillen tussen browsers.

#wrapper

Het element met id="wrapper". Binnen deze <div> staat het hele voorbeeld.

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 div#voor-schermlezers, input#schermlezer, label#label-voor-schermlezer, en de vier <span>'s met de afbeeldingen. Alleen die vier <span>'s zijn hier echte flex items, want de andere directe kinderen worden later absoluut gepositioneerd. En dan zijn het geen echte flex items meer.

flex-wrap: wrap;

Gelijk hierboven is div#wrapper met display: flex; veranderd in een zogenaamde 'flex container'. Daarmee zijn de directe kinderen van div#wrapper veranderd in 'flex items'. Die directe kinderen zijn de vier <span>'s met de afbeeldingen. (De andere directe kinderen worden later absoluut gepositioneerd en zijn daardoor geen echte flex items meer.)

Zonder flex-wrap worden de afbeeldingen samengeperst

Flex items worden standaard naast elkaar weergegeven, ook als het blok-elementen zoals een <div> zijn. Bovendien worden ze, tenzij dat wordt aangepast, verkleind tot ze allemaal in de flex container passen. Op de afbeelding is dat te zien: alle vier de afbeeldingen zijn zichtbaar, terwijl het browservenster maar 320 px breed is. Met als resultaat vier zwaar mishandelde afbeeldingen.

Met deze regel worden de <span>'s niet verkleind, maar onder elkaar gezet, als ze niet naast elkaar in het browservenster passen.

justify-content: space-around;

Met justify-content worden de afbeeldingen gelijkmatig verspreid

Verdeel eventueel overblijvende ruimte gelijk tussen de flex items (de vier <span>'s met afbeeldingen).

Op bovenstaande afbeeldingen heeft div#wrapper, de flex container, even een zwarte border gekregen, waardoor de grootte ervan is te zien. Op de bovenste afbeelding is voldoende ruimte om de vier <span>'s naast elkaar te zetten. Er blijft zelfs ruimte over: div#wrapper is breder dan de vier <span>'s. De overblijvende ruimte wordt tussen de <span>'s verdeeld, waarbij de lege ruimte tussen de <span>'s twee keer zo breed is als de lege ruimte links en rechts van de buitenste <span>'s.

Op de onderste afbeelding passen de vier <span>'s niet naast elkaar. De ruimte tussen de <span>'s in de bovenste regel is weer twee keer zo breed als de ruimte links en rechts van de buitenste <span>'s. De <span> op de onderste regel komt automatisch in het midden te staan: de overblijvende ruimte wordt hier gelijkelijk tussen links en rechts verdeeld.

Waar je nog niet zo lang geleden soms de meest ingewikkelde dingen moest uithalen om iets te centreren, volstaan nu deze paar regels. Die bovendien geen bijwerkingen hebben op het gebied van toegankelijkheid en dergelijke.

max-width: 1000px;

Maximum breedte. Voorkomen dat div#wrapper in brede browservensters té breed wordt.

line-height: 0;

Geen regelhoogte. De regelhoogte wordt geërfd door de nakomelingen van div#wrapper, waaronder de <span>'s.

In elke <span> zitten twee afbeeldingen met een breedte van 200 px: de originele en de vervangende afbeelding. De <span>'s zelf krijgen bij #wrapper > span een breedte van 200 px. Omdat er geen twee afbeeldingen naast elkaar in de <span> passen, wordt de vervangende tweede afbeelding op een nieuwe regel gezet, onder de originele eerste afbeelding (en vervolgens daaronder verborgen, maar dat komt later).

Tussen twee afbeeldingen zit een kleine horizontale kier

In een aantal opzichten gedraagt een <img> zich net zoals gewone tekst. Bij gewone tekst zijn sommige letters wat hoger of lager dan andere. Zo steekt bijvoorbeeld de 'g' iets onder de meest andere letters uit. Om te voorkomen dat de 'g' te dicht op de regel eronder komt te staan, wordt onder de tekst een kleine marge aangehouden, waarin de uitlopers van letters zoals de 'g' kunnen staan.

Omdat een <img> zich wat betreft de regelhoogte net als gewone tekst gedraagt, staat deze marge ook onder de afbeelding. De vervangende afbeelding staat dan ook niet tegen de originele afbeelding aan, maar iets daaronder, zoals op de afbeelding is te zien.

De vervangende afbeelding staat iets te laag

Bij img + img wordt de vervangende afbeelding weer z'n eigen hoogte terug omhoog gezet, waardoor hij verdwijnt onder de originele afbeelding. Maar niet helemaal, want hij moet eigenlijk z'n eigen hoogte plus de marge aan de onderkant van de tekst omhoog worden gezet. Op de afbeelding links is dit te zien: aan de onderkant is nog een klein stukje van de vervangende afbeelding te zien.

Door de regelhoogte gewoon op 0 te zetten, verdwijnt de marge aan de onderkant en komen beide afbeeldingen precies over elkaar heen te staan.

margin: 0 auto;

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

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

<main> is een blok-element en wordt daarom normaal genomen automatisch even breed als z'n ouder <body>. Ook <body> is een blok-element en wordt daarom normaal genomen ook weer even breed als z'n ouder <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser. Uiteindelijk staat div#wrapper hierdoor altijd horizontaal gecentreerd binnen het venster.

#voor-schermlezers

Het element met id="voor-schermlezers". Een <div> met tekst speciaal voor schermlezers.

position: absolute;

Om de <div> op de juiste plaats neer te kunnen zetten.

Er wordt gepositioneerd ten opzichte van het 'containing block'. Dat is de eerste voorouder die zelf een bepaalde eigenschap heeft, zoals een andere positie dan statisch. Als die er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.

left: -20000px;

Links buiten het scherm parkeren. Schermlezers lezen de tekst gewoon voor, maar deze verstoort nu niet de lay-out van de pagina.

#schermlezer

Het element met id="schermlezer". Een aankruisvakje waarmee schermlezers alle afbeeldingen gelijktijdig zichtbaar kunnen maken.

-moz-appearance: none; -webkit-appearance: none; appearance: none; width: 1px; height: 1px;

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

input#schermlezer is bedoeld voor schermlezers. De <input> zou in schermlezers ook moeten kunnen worden aan- en uitgevinkt, als deze buiten het scherm staat. Maar in TalkBack op Android werkt dat pas in versie 8.1. In oudere versies, die nog volop in gebruik zijn, werkt een <input> niet, als deze buiten het browservenster staat. Bovendien mag er geen ander element boven de <input> staan.

Dat levert een probleem op, want nu staat er een aankruisvakje op het scherm, dat alleen nut heeft voor schermlezers. En dat de lay-out tamelijk opzichtig verstoort. Daarom wordt de standaardlay-out van het aankruisvakje met appearance: none; verwijderd. Dit geeft de mogelijkheid het uiterlijk van het aankruisvakje aan te passen.

Maar nu werkt de <input> nog steeds niet in oudere versies van TalkBack, omdat deze geen oppervlakte meer heeft. Daarom worden een breedte en hoogte van 1 px aan de <input> gegeven. Dat is de minimale grootte, waarop de <input> overal werkt.

De <input> is zo klein, dat het feitelijk onmogelijk is deze per ongeluk aan te raken of aan te klikken. Tijdens het testen lukte het nergens, om de <input> met klikken of aanraken aan- of uit te vinken.

Een <input> is een inline-element, en daardoor kun je er geen breedte en hoogte aan geven. Maar gelijk hieronder wordt het absoluut gepositioneerd, en dan verandert het in een soort blok-element, waardoor je er wel breedte en hoogte aan kunt geven.

position: absolute;

Om de <input> op de juiste plaats neer te kunnen zetten.

Er wordt gepositioneerd ten opzichte van het 'containing block'. Dat is de eerste voorouder die zelf een bepaalde eigenschap heeft, zoals een andere positie dan statisch. Als die er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.

top: 10px; right: 10px;

10 px vanaf de bovenkant en vanaf rechts neerzetten.

z-index: 30;

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. Hierdoor zou, bij bepaalde breedtes van het browservenster, de <input> verdwijnen onder een afbeelding. En dus niet meer werken in oudere versies van TalkBack, zoals iets hierboven bij appearance wordt beschreven.

Met een hogere z-index staat de <input> altijd bovenaan. Deze z-index is tamelijk hoog, maar ook de afbeeldingen krijgen later een z-index. Daarom moet de z-index van de <input> vrij hoog zijn.

Een z-index werkt alleen in bepaalde omstandigheden. Eén van die omstandigheden is een absolute positie. Die is iets hierboven aan de <input> gegeven, dus dat is geregeld.

#label-voor-schermlezer

Het element met id="label-voor-schermlezer". De bij input#schermlezer horende <label>.

position: absolute;

Om de <label> op de juiste plaats neer te kunnen zetten.

Er wordt gepositioneerd ten opzichte van het 'containing block'. Dat is de eerste voorouder die zelf een bepaalde eigenschap heeft, zoals een andere positie dan statisch. Als die er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.

top: -40px;

Boven het venster van de browser zetten, zodat de lay-out van de pagina niet wordt verstoord. Voor schermlezers maakt dat niets uit: de tekst wordt gewoon voorgelezen, ook al zie je de tekst in de <label> niet.

right: 0;

Helemaal rechts neerzetten.

#wrapper > span

#wrapper: het element met id="wrapper". De <div> waar het hele voorbeeld in zit.

>: de elementen achter dit teken moeten een direct kind van het element voor dit teken zijn. De hierachter staande <span>'s moeten een direct kind van div#wrapper zijn. Onderstaande <span> is een direct kind van div#wrapper:

<div id="wrapper"> <span></span> </div>

De <span> hieronder is geen direct kind van div#wrapper, omdat er een <p> tussen div#wrapper en de <span> zit:

<div id="wrapper"> <p> <span></span> </p> </div>

span: alle <span>'s.

De hele selector in normale mensentaal: doe iets met de <span>'s die een direct kind van div#wrapper zijn.

Dat de <span>'s een direct kind van div#wrapper moeten zijn, is belangrijk. Er kunnen meer <span>'s in div#wrapper zitten, bijvoorbeeld om een verandering van taal aan te geven. In het voorbeeld is dat niet het geval, maar ook dan is dit belangrijk. Als je later een <span> toevoegt, zoek je je ongans waar die vreemde verschijnselen opeens vandaan komen.

Een <span> is van zichzelf een inline-element, waardoor eigenschappen als breedte en hoogte niet zijn te gebruiken. Maar div#wrapper, de ouder van de <span>'s, is bij #wrapper met display: flex; veranderd in een flex container. Hierdoor zijn de <span>'s veranderd in flex items, waardoor dit soort eigenschappen nu wel is te gebruiken.

width: 200px;

Binnen elke <span> staan twee afbeeldingen met een breedte van 200 px. Als de <span> geen breedte krijgt, komen deze naast elkaar te staan. Door een breedte op te geven komt de vervangende afbeelding onder de originele afbeelding te staan.

height: 133px; overflow: hidden;

De <span>'s 133 px hoog maken, even hoog als de erin zittende afbeeldingen.

Bij img + img worden de vervangende afbeeldingen met position: relative; en top: -100%; onder de originele afbeeldingen gezet. Maar een relatieve positie verplaatst het element niet écht. Op het scherm staat het wel ergens anders, maar de originele ruimte wordt nog steeds ingenomen. (Dat is anders dan bij een negatieve marge aan de bovenkant: die verplaatst het element écht.)

Op Blink gebaseerde browsers (onder andere Google Chrome en Edge) reageren op hoveren, klikken of aanraken alsof de vervangende afbeelding nog op de originele plaats staat. Tot 133 px onder de originele afbeelding, de plaats waar de vervangende afbeelding stond voordat deze naar boven werd geplaatst, blijft het scherm reageren op hoveren, klikken of aanraken.

Door een hoogte aan de <span> te geven en met overflow: hidden; gewoon te verbergen wat te hoog is, wordt dit gecorrigeerd. Nu reageren ook op Blink gebaseerde browsers alleen op hoveren, klikken of aanraken boven de originele afbeelding.

padding: 10px;

Bij een bepaalde breedte van het browservenster komen de <span>'s, en daarmee de erin zittende afbeeldingen, volledig tegen elkaar aan te staan. Door de <span>'s wat padding te geven aan alle kanten, komen de afbeeldingen niet volledig tegen elkaar aan te staan. Bovendien geeft dit aan de bovenkant wat afstand tot de bovenkant van het browservenster.

#wrapper > span:first-of-type

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

#wrapper > span {width: 200px; height: 133px; overflow: hidden; padding: 10px;}

#wrapper: het element met id="wrapper". De <div> waar het hele voorbeeld in zit.

>: de elementen achter dit teken moeten een direct kind van het element voor dit teken zijn. De hierachter staande <span>'s moeten een direct kind van div#wrapper zijn. Onderstaande <span> is een direct kind van div#wrapper:

<div id="wrapper"> <span></span> </div>

De <span> hieronder is geen direct kind van div#wrapper, omdat er een <p> tussen div#wrapper en de <span> zit:

<div id="wrapper"> <p> <span></span> </p> </div>

span: alle <span>'s.

:first-of-type: het element met een bepaald volgnummer. In dit geval wordt geen volgnummer gebruikt, maar een speciaal voor het eerste element bedoelde selector: :first-of-type. Voor alle latere elementen gebruik je 'n soortgelijke selector, maar dan met een volgnummer: :nth-of-type(). Tussen de haakjes komt het volgnummer. :nth-of-type(1) is precies hetzelfde als :first-of-type, maar de laatste is wat mensvriendelijker.

Omdat voor :first-of-type (of voor latere elementen :nth-of-type()) een span staat, worden alleen <span>'s geteld. Als binnen div#wrapper 327 <p>'s zitten, tellen die niet mee. Hadden ze maar 'n <span> moeten zijn.

De hele selector in normale mensentaal: de eerste <span> die een direct kind is van div#wrapper.

order: 4;

Bij #wrapper is div#wrapper met display: flex; veranderd in een flex container. Hierdoor zijn de directe kinderen van div#wrapper veranderd in flex items. Die directe kinderen zijn de vier <span>'s met de afbeeldingen. (De andere directe kinderen worden elders absoluut gepositioneerd en zijn daardoor geen echte flex items meer.)

De vier <span>'s zitten in een bepaalde volgorde in de html. Met behulp van de bij flexbox horende eigenschap order kan die volgorde op het scherm worden aangepast. Er zijn vier <span>'s. Door de eerste <span> uit de html (span:first-of-type) volgnummer 4 te geven, wordt deze als vierde op het scherm gezet: helemaal rechts.

Hier gelijk onder krijgt de tweede <span> uit de html (span:nth-of-type(2)) het volgnummer 3, waardoor deze als een na laatste op het scherm wordt gezet.

span:nth-of-type(3), de derde <span> uit de html krijgt als volgnummer 1, en span:nth-of-type(4) krijgt als volgnummer 1, waardoor deze op het scherm vooraan komt te staan.

De volgorde in de html kan niet hetzelfde zijn als die op het scherm, omdat bij hoveren over een bepaalde <span> de vervangende afbeeldingen in eerdere <span>'s ook getoond moeten worden. En er bestaat geen css-selector die 'achteruit' kan werken. Omdat selectors echter altijd naar de volgorde in de html kijken, kun je dat toch ogenschijnlijk voor elkaar krijgen door de volgorde in de html om te draaien. En die dan bij weergave op het scherm nogmaals om te draaien.

Deze constructie heeft grote gevolgen voor de toegankelijkheid voor gebruikers van de Tab-toets en voor gebruikers van een schermlezer. Daarom kan deze constructie eigenlijk beter niet worden gebruikt. Over de problemen wat betreft toegankelijkheid is meer te lezen bij Gebruikers Tab-toets en Schermlezers.

#wrapper > span:nth-of-type(2) {order: 3;}

#wrapper > span:nth-of-type(3) {order: 2;} #wrapper > span:nth-of-type(4) {order: 1;}

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 > span {width: 200px; height: 133px; overflow: hidden; padding: 10px;}

Dit zijn de tweede, derde en vierde <span> met afbeeldingen. De beschrijving van selector en css staat gelijk hierboven bij #wrapper > span:first-of-type. De enige twee verschillen: het gaat hier niet om de eerste, maar om de tweede, derde en vierde <span>, en het volgnummer achter order is anders.

img

Alle <img>'s. De vier originele en de vier vervangende afbeeldingen.

position: relative;

Er zijn twee redenen om de afbeeldingen relatief te positioneren.

Het tonen en verbergen van de vervangende afbeeldingen gebeurt met behulp van een z-index. Een z-index werkt alleen in bepaalde omstandigheden, zoals een relatieve positie.

De vervangende afbeeldingen worden onder originele afbeeldingen gezet door ze gelijk hieronder met top: 100%; naar boven te verplaatsen. Dit kan ook op andere manieren, maar omdat ze toch al een relatieve positie hebben, kan die worden gebruikt voor de verplaatsing.

z-index: 20;

Normaal genomen worden elementen in de volgorde van de html op het scherm gezet. Omdat de vervangende afbeeldingen in de html na de originele afbeeldingen komen, zouden deze boven de originele afbeeldingen komen te staan.

Alle afbeeldingen krijgen hier een z-index van 20. De vervangende afbeeldingen krijgen gelijk hieronder een z-index van 10 en komen daardoor onder de originele afbeeldingen te staan, ook al staan ze later in de html.

(En door later bij span:hover img + img, span:hover ~ span img + img, span:focus img + img, span:focus ~ span img + img simpelweg de z-index te verhogen, komen de vervangende afbeeldingen boven de originele afbeeldingen te staan.)

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

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

img {position: relative; z-index: 20;}

img: alle <img>'s.

+: het element achter de + moet in de html direct volgen op het element voor de +. In dit geval gaat het om een <img> die gelijk op een andere <img> volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder dezelfde <span>.

img: alle <img>'s.

De hele selector in normale mensentaal: een <img> die direct op een andere <img> volgt. Dit zijn de <img>'s met de vervangende afbeeldingen.

top: -100%;

Hier iets boven bij img zijn alle <img>'s relatief gepositioneerd. Een relatieve verplaatsing in procenten is ten opzichte van het element zelf. Omdat het hier om een negatief percentage gaat, is de verplaatsing naar boven.

De vervangende afbeelding wordt z'n eigen hoogte (100%) naar boven verplaatst. Hierdoor komt hij op precies dezelfde plaats te staan als de originele afbeelding.

z-index: 10;

Hier gelijk boven zijn de vervangende afbeeldingen met top: -100%; op dezelfde plaats als de originele afbeeldingen gezet. Omdat ze in de html na de originele afbeeldingen komen, zouden de originele afbeeldingen worden afgedekt door de vervangende afbeeldingen.

Hier iets boven bij img hebben alle <img>'s een z-index van 20 gekregen. Door de z-index van de vervangende afbeeldingen hier te verlagen naar 10, komen deze onder de originele afbeeldingen te staan.

Een z-index werkt alleen in bepaalde omstandigheden. Eén van die omstandigheden is een relatieve positie. Die is iets hierboven bij img gegeven, dus dat is geregeld.

span:hover img + img, span:hover ~ span img + img, span:focus img + img, span:focus ~ span img + 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.

img {position: relative; z-index: 20;}

img + img {top: -100%; z-index: 10;}

Dit zijn vier verschillende selectors, gescheiden door een komma.

De eerste selector, span:hover img + img:

span: alle <span>'s.

:hover: maar alleen als erover wordt gehoverd.

img: alle <img>'s.

+: het element achter de + moet in de html direct volgen op het element voor de +. In dit geval gaat het om een <img> die gelijk op een andere <img> volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder dezelfde <span>.

img: alle <img>'s.

De hele eerste selector in normale mensentaal: doe iets met de afbeelding die op een afbeelding in een <span> volgt, maar alleen als over die <span> wordt gehoverd. Die afbeelding is de vervangende afbeelding.

De tweede selector, span:hover ~ span img + img:

span: alle <span>'s.

:hover: maar alleen als erover wordt gehoverd.

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

De enige voorwaarde is verder dat het voor en het na de ~ staande element dezelfde ouder hebben. Dat is hier het geval: de <span> voor de ~ en de <span> na de ~ hebben beide als ouder div#wrapper.

span: alle <span>'s die op de <span> voor de ~ volgen.

img: alle <img>'s.

+: het element achter de + moet in de html direct volgen op het element voor de +. In dit geval gaat het om een <img> die gelijk op een andere <img> volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder dezelfde <span>.

img: alle <img>'s.

De hele tweede selector in normale mensentaal: doe iets met de afbeelding die op een afbeelding in een <span> volgt, maar alleen in de <span>'s die volgen op de <span>, waarover wordt gehoverd. Die afbeelding is de vervangende afbeelding.

De derde selector, span:focus img + img:

span: alle <span>'s.

:focus: maar alleen als de <span> focus heeft. Dat kan door er met de Tab-toets naartoe te gaan, door de <span> aan te raken of door erop te klikken. (Normaal genomen kan een <span> geen focus krijgen, maar door het toevoegen van een tabindex kan dat hier wel.)

img: alle <img>'s.

+: het element achter de + moet in de html direct volgen op het element voor de +. In dit geval gaat het om een <img> die gelijk op een andere <img> volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder dezelfde <span>.

img: alle <img>'s.

De hele derde selector in normale mensentaal: doe iets met de afbeelding die op een afbeelding in een <span> volgt, maar alleen als die <span> de focus heeft. Die afbeelding is de vervangende afbeelding.

De vierde selector: span:focus ~ span img + img:

span: alle <span>'s.

:focus: maar alleen als de <span> focus heeft. Dat kan door er met de Tab-toets naartoe te gaan, door de <span> aan te raken of door erop te klikken. (Normaal genomen kan een <span> geen focus krijgen, maar door het toevoegen van een tabindex kan dat hier wel.)

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

De enige voorwaarde is verder dat het voor en het na de ~ staande element dezelfde ouder hebben. Dat is hier het geval: de <span> voor de ~ en de <span> na de ~ hebben beide als ouder div#wrapper.

span: alle <span>'s die op de <span> voor de ~ volgen.

img: alle <img>'s.

+: het element achter de + moet in de html direct volgen op het element voor de +. In dit geval gaat het om een <img> die gelijk op een andere <img> volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder dezelfde <span>.

img: alle <img>'s.

De hele tweede selector in normale mensentaal: doe iets met de afbeelding die op een afbeelding in een <span> volgt, maar alleen in de <span>'s die volgen op de <span> die de focus heeft. Die afbeelding is de vervangende afbeelding.

Alle vier de selectors samen in normale mensentaal: doe iets met de vervangende afbeelding in de <span> waarover wordt gehoverd of die de focus heeft, en met de vervangende afbeelding(en) in de <span>('s) die na die <span> komen.

Het lijkt op het scherm alsof bij hoveren, aanraken, en dergelijke van een <span> dit invloed heeft op de eerdere <span>'s. Dat is niet zo, want dat is onmogelijk met alleen css. In werkelijkheid is de laatste <span> op het scherm in de html de eerste <span>, en de eerste <span> op het scherm is in de html de laatste <span>. Op het scherm is de volgorde bij wrapper > span:first-of-type en daaronder met behulp van order aangepast.

Dit heeft wel nadelige gevolgen voor de toegankelijkheid voor gebruikers van de Tab-toets en gebruikers van schermlezers. Hierover is meer te vinden bij Gebruikers Tab-toets en Schermlezers.

z-index: 30;

Bij img + img hebben de vervangende afbeeldingen een z-index van 10 gekregen. Dat is lager dan de z-index van 20 van de originele afbeeldingen. Daardoor staan ze onder de originele afbeeldingen.

Door de z-index van de vervangende afbeeldingen simpelweg te verhogen, komen ze boven de originele afbeeldingen te staan en worden zichtbaar. En dekken de originele afbeelding af, die daardoor onzichtbaar wordt.

Een z-index werkt alleen in bepaalde omstandigheden, zoals een relatieve positie. Die hebben ze bij img gekregen, dus dat is geregeld.

#schermlezer:checked ~ 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 > span {width: 200px; height: 133px; overflow: hidden; padding: 10px;}

#wrapper > span:first-of-type {order: 4;}

#wrapper > span:nth-of-type(2) {order: 3;}

#wrapper > span:nth-of-type(3) {order: 2;}

#wrapper > span:nth-of-type(4) {order: 1;}

#schermlezer: het element met id="schermlezer". Dit is een <input type="checkbox">

:checked: maar alleen als dit aankruisvakje is aangevinkt.

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

De enige voorwaarde is verder dat het voor en het na de ~ staande element dezelfde ouder hebben. Dat is hier het geval: input#schermlezer voor de ~ en span na de ~ hebben beide als ouder div#wrapper.

span: alle <span>'s.

De hele selector in normale mensentaal: doe iets met de <span>'s die in de html na input#schermlezer komen, maar alleen als dit is aangevinkt. Door dit aankruisvakje aan te vinken, wordt het voorbeeld aangepast voor een schermlezer.

height: auto;

Eerder zijn bij #wrapper > span de <span>'s precies hoog genoeg gemaakt om er één afbeelding in te kunnen zetten. Nu worden de originele en vervangende afbeelding beide getoond. Door de hoogte weer de standaardinstelling auto te geven, worden de <span>'s precies hoog genoeg om de inhoud ervan - beide afbeeldingen - weer te geven.

order: 0;

Eerder is de volgorde van de weergave van de <span>'s op het scherm aangepast. En daarmee ook de volgorde van de daarin zittende afbeeldingen. Schermlezers volgen altijd de volgorde van de html, ongeacht de volgorde op het scherm. Omdat de pagina toch al ingrijpend verandert (de vervangende afbeeldingen worden ook getoond), kan gelijktijdig de volgorde op het scherm hetzelfde worden gemaakt als de volgorde in de html.

margin-top: 1.3rem;

Boven de <span>'s met de afbeeldingen komt een balkje met tekst en een aankruisvakje te staan, waarmee de aanpassingen voor de schermlezer weer ongedaan kunnen worden gemaakt. Een marge aan de bovenkant maakt daar ruimte voor.

Als eenheid wordt de relatieve eenheid rem gebruikt, omdat bij gebruik van een absolute eenheid zoals px de hoogte van de marge niet mee verandert met de lettergrootte. Zoomen kan wel altijd, ongeacht welke eenheid wordt gebruikt.

De rem is ongeveer hetzelfde als de bekendere eenheid em, maar is gebaseerd op de lettergrootte van <html>. Hierdoor is de rem, anders dan de em, overal op de pagina even groot. Ook als de bezoeker de lettergrootte heeft veranderd.

#schermlezer:checked

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

#schermlezer {-moz-appearance: none; -webkit-appearance: none; appearance: none; width: 1px; height: 1px; position: absolute; top: 10px; right: 10px; z-index: 30;}

#schermlezer: het element met id="schermlezer". Dit is een <input type="checkbox">

:checked: maar alleen als dit aankruisvakje is aangevinkt.

-moz-appearance: checkbox; -webkit-appearance: checkbox; appearance: auto;

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

De eerste twee waarden checkbox zijn verouderd, maar worden in verschillende browsers nog gebruikt. Als deze eigenschap in de officiële specificatie gaat komen, wordt de waarde auto gebruikt.

Bij #schermlezer zijn de aankruisvakjes vrijwel onzichtbaar gemaakt, onder andere door met appearance: none; de standaardlay-out van het aankruisvakje te verwijderen. Hier wordt die standaardlay-out weer teruggezet. Zou dat niet gebeuren, dan is volstrekt onduidelijk, hoe het aankruisvakje eventueel weer kan worden uitgevinkt.

width: 10px; height: 10px;

Bij #schermlezer is het aankruisvakje met width: 1px; en height: 1px; zo klein mogelijk gemaakt. Hier wordt het weer vergroot tot een werkbaar formaat.

border: black solid 1px;

Zwart randje.

position: fixed;

Vastzetten ten opzichte van het venster van de browser. Ook als de bezoeker de pagina gaat scrollen, blijft de <input> op dezelfde plaats op het scherm staan.

top: 5px;

5 px vanaf de bovenkant neerzetten.

#schermlezer:checked + #label-voor-schermlezer

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

#label-voor-schermlezer {position: absolute; top: -40px; right: 0;}

#schermlezer: het element met id="schermlezer". Dit is een <input type="checkbox">

:checked: maar alleen als dit aankruisvakje is aangevinkt.

+: het element achter de + moet in de html direct volgen op het element voor de +. In dit geval gaat het om label#label-voor-schermlezer die gelijk op input:schermlezer volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder dezelfde div#wrapper.

background: white;

Witte achtergrond.

color: black;

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

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

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

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

line-height: 1.2em; Zonder regelhogte is de label moeilijk te lezen

Bij #wrapper is met line-height: 0; een regelhoogte van 0 px opgegeven. Die regelhoogte wordt geërfd door de nakomelingen van div#wrapper, waaronder deze <label>. Tekst zonder regelhoogte is niet zo heel erg handig, want daardoor valt de iets hierboven opgegeven witte achtergrond grotendeels weg, zoals op de afbeelding is te zien. (Dat je toch nog iets van die achtergrond ziet, komt door de iets hieronder opgegeven padding van 3 px aan boven- en onderkant.)

Daarom wordt die regelhoogte hier weer teruggezet naar wat ongeveer de standaard-regelhoogte is: 1,2 em.

Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij een vaste eenheid als px de regelhoogte niet mee verandert met de lettergrootte. Zoomen kan altijd, ongeacht de eenheid die je gebruikt.

text-align: right;

Tekst rechts uitlijnen.

border: black solid 1px;

Zwart randje.

padding: 3px 60px 3px 3px;

Boven, onder en links een padding van 3 px.

Rechts een grotere padding van 60 px. Aan de rechterkant staat ook het aankruisvakje. Door de tekst 60 px naar links te zetten, komt de tekst naast het aankruisvakje te staan, en niet daar doorheen.

position: fixed;

Vastzetten ten opzichte van het venster van de browser. Ook als de bezoeker de pagina gaat scrollen, blijft de <input> op dezelfde plaats op het scherm staan.

top: 0;

Bovenaan het browservenster neerzetten.

left: 0;

Helemaal links neerzetten.

Een fixed element wordt normaal genomen niet breder dan nodig is om de inhoud ervan weer te kunnen geven. Hier is dat alleen de tekst 'Toon alle afbeeldingen', waardoor er een enorme afstand tussen de tekst en het bijbehorende aankruisvakje zou ontstaan.

Eerder is echter bij #label-voor-schermlezer al right: 0; opgegeven. Nu loopt de <label> van helemaal links naar helemaal rechts, over de volle breedte van het venster van de browser, ongeacht hoe breed dit venster is.

#schermlezer:checked ~ span img + 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.

img {position: relative; z-index: 20;}

img + img {top: -100%; z-index: 10;}

#schermlezer: het element met id="schermlezer". Dit is een <input type="checkbox">

:checked: maar alleen als dit aankruisvakje is aangevinkt.

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

De enige voorwaarde is verder dat het voor en het na de ~ staande element dezelfde ouder hebben. Dat is hier het geval: input#schermlezer voor de ~ en span na de ~ hebben beide als ouder div#wrapper.

img: alle <img>'s.

+: het element achter de + moet in de html direct volgen op het element voor de +. In dit geval gaat het om een <img> die gelijk op een andere <img> volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder dezelfde <span>.

img: alle <img>'s.

De hele selector in normale mensentaal: doe iets met de afbeelding die op een andere afbeelding in een <span> volgt, maar alleen als input#schermlezer is aangevinkt. Die afbeelding is de vervangende afbeelding.

margin-top: 20px;

Marge van 20 px tussen de originele afbeelding en de eronder staande vervangende afbeelding. Hier gelijk onder wordt de vervangende afbeelding zichtbaar gemaakt, en zonder marge zou deze tegen de originele afbeelding aan komen te staan.

position: static;

Eerder is bij img een relatieve positie aan alle <img>'s gegeven. Daar is bij img + img gebruik van gemaakt door met top: -100%; de vervangende afbeelding te onder de originele afbeelding te plaatsen.

Door de relatieve positie te veranderen in de standaard statische positie, werkt deze verplaatsing niet meer en wordt de vervangende afbeelding gewoon zichtbaar.