Menu met links met toelichting en indicatie van huidige, bezochte en onbezochte pagina's - uitleg
Laatst aangepast: .
Korte omschrijving
Menu met acht links. In een smal browservenster moet het menu eerst worden geopend. Bij gebruik van muis of toetsenbord verschijnt een klein venstertje met informatie. De link kan gewoon worden gevolgd. Op een aanraakscherm verschijnt bij de eerste eerste aanraking een venstertje met informatie, bij de tweede aanraking wordt de link gevolgd.
BELANGRIJK
Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.
Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.
Als je dit lastig vindt, 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 min of meer 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
- Aantal knoppen, grootte en vorm, kleuren, enzovoort kunnen natuurlijk worden aangepast.
- Op een aanraakscherm wordt bij een eerste aanraking alleen het venstertje met informatie geopend. Pas bij een tweede aanraking wordt de link gevolgd. Je kunt je daarom afvragen, of dit wel zo'n handige constructie is. Maar goed, dit voorbeeld bestond al en het was gewoon leuk om het te moderniseren.
- Op een laptop met een aanraakscherm zal een aanraking in de regel hetzelfde werken als een klik met een muis: de link wordt gelijk gevolgd en het venstertje met informatie wordt niet of alleen in een flits getoond. Het tonen van het venstertje met behulp van :hover werkt niet. Daarom is deze constructie niet geschikt, als in het venstertje met informatie belangrijke informatie staat.
- Als je 'n link hebt bezocht, verandert het lijntje onder de link. Om de oorspronkelijke kleuren van een onbezochte link weer terug te krijgen, moet je de geschiedenis van je browser verwijderen. Of, als de browser die mogelijkheid biedt, alleen de bij de links horende pagina's verwijderen uit de geschiedenis.
- Voor het geval dat vragen oproept: een aantal id's eindigt op '-vb'. Dat vreemde uiteinde staat voor 'voorbeeld' en is er alleen maar, omdat anders op de site zelf een aantal id's voor het menu van de site dezelfde naam zou hebben als een aantal id's in het voorbeeld.
- JavaScript wordt alleen gebruikt om de toegankelijkheid te verbeteren. Ook zonder JavaScript werkt dit voorbeeld, maar het is dan veel onhandiger voor bijvoorbeeld schermlezers.
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 (KDE neon). 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 browservensters minimaal 760 px breed staat een horizontale balk met acht knoppen. In smallere vensters zijn de knoppen verborgen en moet je ze eerst zichtbaar maken. In die smallere vensters staan de knoppen niet naast elkaar, maar onder elkaar.
De werking is in smallere en bredere browservensters precies hetzelfde. Alleen staan in smallere vensters de venstertjes met informatie naast de knoppen en in bredere vensters eronder.
De knoppen zijn blauw met witte tekst, maar als erover wordt gehoverd of als ze de focus hebben, worden ze wit met zwarte tekst. Vooral in smallere browservensters is dat nodig om te laten zien, bij welke knop het venstertje met informatie hoort. De knop voor de huidige pagina heeft een afwijkende kleur.
In het verleden konden websites aan de hand van gewijzigde eigenschappen bij bezochte links zien, welke sites iemand had bezocht. Om deze schending van de privacy te voorkomen, kunnen nog slechts enkele eigenschappen van bezochte links met behulp van css worden aangepast. Eén van die eigenschappen is border-color.
In elke link staat een <span> die even breed is als de link. Die <span> heeft aan de onderkant een border. Als een link nog niet is bezocht, is de border rood. Zodra een link is bezocht, is de border groen.
Tot zover is het allemaal nog niet al te ingewikkeld. Het tonen en verbergen van de venstertjes met informatie is echter 'n stuk lastiger, omdat dat op verschillende manieren kan gebeuren. De eerste fase is voor al die manieren hetzelfde.
Bij openen van de pagina reageren de <a>'s met de links nergens op door het gebruik van pointer-events: none;. Hierdoor wordt een aanraking, hoveren, en dergelijke doorgegeven aan de ouder van de <a>: de <li> waar de <a> in zit. Omdat de <a>'s eigenlijk (nog) geen echte link zijn, is de tekst in de <a>'s niet onderstreept.
Bij de link die bij de huidige pagina hoort gebeurt er verder niets: deze krijgt alleen een rode streep door de tekst, als over de link wordt gehoverd of als deze de focus heeft. De werking van de andere zeven links hangt af van de gebruikte bedieningsmethode.
Als met een muis over een knop wordt gehoverd, wordt bij die knop een venstertje met informatie geopend. Gelijktijdig wordt bij de in de <li> zittende <a> pointer-events: none; veranderd in pointer-events: auto;. Hierdoor gaat de <a> werken als een gewone link: bij klikken erop wordt de link gevolgd. De tekst in de <a> wordt onderstreept, zoals min of meer gebruikelijk is bij een link. Omdat de link nu werkt als een gewone link, wordt nu bij klikken op de link de link gevolgd.
Bij hoveren over een knop gaat de verandering van een niet-werkende link in een werkende link zo snel, dat het onmogelijk is om op de link te klikken, voordat deze werkt. De bezoeker merkt dus helemaal niets van de niet-werkende link: alles lijkt gewoon normaal te werken.
Voor gebruikers van de Tab-toets werkt het, zoals het altijd werkt: pointer-events heeft geen invloed op de werking van het toetsenbord. Met behulp van de Tab-toets wordt van link naar link gesprongen, en bij indrukken van Enter wordt de link gevolgd. Zodra een link de focus heeft, wordt de tekst in de link onderstreept en wordt het bij de link horende venstertje met informatie getoond.
In browservensters minimaal 760 px breed zijn de acht knoppen met links altijd zichtbaar. Het kan knap irritant zijn, als op elke pagina acht keer de Tab-toets moet worden ingedrukt, voordat de eigenlijke inhoud van de pagina wordt bereikt. Daarom is bovenaan de pagina een skip-link aangebracht, waarmee de acht knoppen in een keer kunnen worden gepasseerd.
Op een aanraakscherm werkt bovenstaande allemaal niet. Hoveren wordt daar hetzelfde behandeld als een aanraking. Zodra je een knop aanraakt, gebeurt er bij die knop hetzelfde als iets hierboven bij Als met een muis over een knop wordt gehoverd wordt beschreven: de link gaat gelijk werken. Dat betekent op een aanraakscherm dat de link gelijk bij de eerste aanraking zou worden gevolgd, waarbij – afhankelijk van besturingssysteem en browser – soms in een flits het venstertje met informatie nog heel even is te zien.
Door aan elke <li> een tabindex="-1" te geven, kan de <li> door deze aan te raken de focus krijgen. Omdat de <a> in de <li> met behulp van pointer-events: none; niet op een aanraking reageert, wordt de link niet gevolgd, maar krijgt de <li> de focus. Hierdoor wordt het bij de link horende venstertje met informatie getoond en wordt de tekst in de link onderstreept.
Zodra de <li> de focus heeft, wordt bij de <a> pointer-events: none; veranderd in pointer-events: auto;. Hierdoor wordt bij een tweede aanraking van de knop de link gevolgd.
Schermlezers volgen gelijk de link. Met behulp van WAI-ARIA wordt geregeld dat de informatie uit het venstertje gelijk na de tekst in de link wordt voorgelezen, afhankelijk van de schermlezer al dan niet na een kleine vertraging.
Dan is er nog een hele reeks css om te voorkomen dat meldingen te breed worden, soepel tonen en verbergen, en dergelijke, maar deze zijn voornamelijk voor het uiterlijk van belang.
Semantische elementen en WAI-ARIA
Deze twee onderwerpen zijn samengevoegd, omdat ze veel met elkaar te maken hebben.
Semantische elementen
De meeste elementen die in html worden gebruikt, hebben een semantische betekenis. Dat wil zeggen dat je aan de gebruikte tag al (enigszins) kunt zien, wat voor soort inhoud er in het element staat. In een <h1> staat een belangrijke kop. In een <h2> staat een iets minder belangrijke kop. In een <p> staat een alinea. In een <table> staat een tabel (en geen lay-out, als het goed is!). Enzovoort.
Door het op de goede manier gebruiken van semantische elementen, kunnen zoekmachines, schermlezers, enzovoort de structuur van een pagina begrijpen. De spider van een zoekmachine is redelijk te vergelijken met een blinde. Het is dus ook in je eigen belang om semantische elementen zo goed mogelijk te gebruiken. Een site die toegankelijk is voor mensen met een handicap, is in de regel ook goed te verwerken door een zoekmachine en maakt dus een grotere kans gevonden en bezocht te worden.
Als het goed is, wordt het uiterlijk van de pagina bepaald met behulp van css. Het uiterlijk staat hierdoor (vrijwel) los van de semantische inhoud van de pagina. Met behulp van css kun je een <h1> heel klein weergeven en een <h6> heel groot, terwijl schermlezers, zoekmachines, en dergelijke nog steeds weten dat de <h1> een belangrijke kop is.
Slechts enkele elementen, zoals <div> en <span>, hebben geen semantische betekenis. Daardoor zijn deze elementen uitstekend geschikt om met behulp van css het uiterlijk van de pagina aan te passen: de semantische betekenis verandert niet, maar het uiterlijk wel. Voor een schermlezer of zoekmachine verandert er (vrijwel) niets, voor de gemiddelde bezoeker krijgt het door de css een heel ander uiterlijk.
(De derde laag, naast html voor de inhoud en css voor het uiterlijk, is JavaScript. Die zorgt voor de interactie tussen site en bezoeker. De min of meer strikte scheiding tussen css en html aan de ene kant en JavaScript aan de andere kant is met de komst van css3 en html5 veel vager geworden. Je kunt nu bijvoorbeeld ook met css dingen langzaam verplaatsen en met html deels de invoer in formulieren controleren.)
Html5 heeft een aantal nieuwe elementen, die speciaal zijn bedoeld om de opbouw van een pagina aan te geven. Deze elementen gedragen zich als een gewone <div>, maar dan een <div> met een semantische betekenis. Hierdoor kunnen schermlezers, zoekmachines, en dergelijke beter zien, hoe de pagina is samengesteld. De meeste schermlezers kunnen dit soort elementen ook gebruiken om snel door de pagina te navigeren. In dit voorbeeld worden hiervan alleen <nav>, <main> en <section> gebruikt.
<nav>
<nav> gedraagt zich als een gewone <div>, maar dan een <div> met een semantische betekenis: navigatie. Hierdoor kunnen schermlezers, zoekmachines, en dergelijke gelijk zien dat hierin links zijn ondergebracht.
Om wat voor soort links het gaat, is echter niet duidelijk. Daarom is gelijk onder <nav> een <h2> aangebracht met de tekst 'Menu voorbeeld'. Deze <h2> is onzichtbaar buiten het scherm geplaatst, maar wordt gewoon voorgelezen door schermlezers. Hierdoor is ook voor schermlezers gelijk aan het begin van de <nav> duidelijk, wat voor soort links in de <nav> zitten.
Zeker als er meerdere <nav>'s aanwezig zijn, zoals in het voorbeeld op de site het geval is, is zo'n <h> aan het begin van de <nav> heel belangrijk.
<main>
Hierbinnen staat de belangrijkste inhoud van de pagina (in dit voorbeeld is dat de tekst onder de knoppen. Eigenlijk is dat hier niet helemaal juist, omdat het hier juist om de knoppen en niet om die tekst gaat. Maar normaal genomen zal dat niet zo zijn.)
<section>
Min of meer samenhangend deel van een pagina, deel van een tekst, en dergelijke.
In dit voorbeeld is de tekst onder de knoppen onderverdeeld in een aantal <section>'s. Gelijk onder elke <section> staat een <h>, zodat schermlezers makkelijk van <section> naar <section> kunnen springen.
WAI-ARIA-codes
WAI-ARIA wordt vaak ingekort tot ARIA. Voluit betekent het Web Accessibility Initiative - Accessible Rich Internet Applications.
Er worden in dit voorbeeld zeven WAI-ARIA-codes gebruikt: aria-labelledby, aria-controls, aria-expanded, aria-current, aria-describedby, role="tooltip" en aria-hidden.
aria-labelledby
Gelijk onder de <nav> met de links staat een <h2> met 'Menu voorbeeld'. Veel gebruikers van schermlezers 'springen' van kopregel naar kopregel, zodat ze snel de inhoud van de pagina kunnen scannen.
Door in de <nav> met aria-labelledby een verwijzing naar de id van de <h2> aan te brengen, worden <nav> en <h2> aan elkaar gekoppeld:
<nav id="menu-vb" aria-labelledby="h2-vb">
<h2 id="h2-vb">Menu voorbeeld</h2>
Nu is voor schermlezers duidelijk om wat voor soort links het binnen de <nav> gaat. Zeker als er meerdere <nav>'s aanwezig zijn, zoals bijvoorbeeld op de site het geval is, is dit heel belangrijk.
(Je zou de <nav> ook voor schermlezers herkenbaar kunnen maken met <nav aria-label="Menu voorbeeld">, maar dan missen gebruikers van een schermlezer die van <h> naar <h> springen de hele <nav>.)
aria-controls
Met behulp van een aankruisvakje kan in browservensters smaller dan 760 px het menu worden verborgen of getoond. Met behulp van aria-controls wordt het aankruisvakje gekoppeld aan het bijbehorende menu in ul#menu-ul-vb:
<input id="toon-menu-vb" type="checkbox" aria-controls="menu-ul-vb" aria-expanded="false">
<ul id="menu-ul-vb">
Op dit moment wordt aria-controls door bijna geen enkele schermlezer ondersteund, maar mogelijk verandert dat in de toekomst en wordt dan bijvoorbeeld gezegd, waar het aankruisvakje voor dient.
aria-expanded
In browservensters smaller dan 760 px kan het menu worden getoond en verborgen door het aan- of uitvinken van een aankruisvakje. Op het scherm is dat duidelijk te zien, maar voor schermlezers is onduidelijk, of het menu wel of niet wordt getoond.
Met behulp van aria-expanded kan aan een schermlezer worden doorgegeven, of het menu wordt getoond of niet. De schermlezer zal dit dan melden. (Hoe dat precies wordt gemeld, verschilt per schermlezer.)
aria-expanded="false" geeft aan dat het menu is verborgen, aria-expanded="true" geeft aan dat het menu wordt getoond. Bij openen van de pagina wordt het menu niet getoond en ziet dat er zo uit:
<input id="toon-menu-vb" type="checkbox" aria-controls="menu-ul-vb" aria-expanded="false">
Het veranderen van false in true en omgekeerd gebeurt met behulp van JavaScript. Ook zonder JavaScript werkt alles, alleen zal de schermlezer dan altijd melden dat het menu niet wordt getoond, omdat de waarde bij aria-expanded altijd false blijft.
aria-current
Alle acht knoppen met links worden op elke pagina herhaald. Maar op elke pagina is één knop eigenlijk overbodig, omdat die bij de pagina zelf hoort. Je zou die knop kunnen weglaten, maar dat wordt 'n rommeltje. Op de ene pagina linkt de vierde knop dan naar pagina drie, op een andere pagina linkt de vierde knop naar pagina twee.
Daarom worden steeds alle acht knoppen getoond. De knop die bij de huidige pagina hoort heeft een ander uiterlijk, waardoor gelijk duidelijk is dat die knop 'n apart geval is.
Schermlezers hebben aan dat andere uiterlijk niets. Daarom wordt bij de knop die bij de huidige pagina hoort aria-current="page" toegevoegd:
<a href="#" aria-current="page">Home<span></span></a>
Een schermlezer zal nu iets zeggen als 'Home, huidige pagina' als deze link wordt voorgelezen.
aria-describedby
aria-describedby verwijst naar de id van een element, waarin een uitgebreidere beschrijving of iets soortgelijks staat. In dit voorbeeld verwijst het van een <a> naar de bijbehorende <span> met extra informatie (behalve bij de link die bij de huidige pagina hoort):
<a href="012-files-dl/menu-012-1-dl.html" aria-describedby="tt-1">Pagina 1<span></span></a><span id="tt-1" role="tooltip" aria-hidden="true">Ruimte voor informatie over de inhoud van pagina 1</span>
Door deze koppeling leest een schermlezer de tekst in de <a> voor, gelijk gevolgd door de tekst in de <span>. Afhankelijk van de schermlezer kan er een kleine pauze zijn tussen voorlezen van de <a> en de <span>
role="tooltip"
Met een role wordt aangegeven, wat voor soort rol dit element speelt. Een algemeen aanvaarde Nederlandse vertaling voor 'tooltip' is er niet, maar het gaat hier om het venstertje met extra informatie:
<span id="tt-1" role="tooltip" aria-hidden="true">Ruimte voor informatie over de inhoud van pagina 1</span>
Als een schermlezer dit ondersteunt, kan deze iets toevoegen als 'Beschrijving' aan het begin van de tekst.
aria-hidden
Met behulp van aria-hidden="true" kan een deel van de code worden verborgen voor schermlezers en dergelijke, zodat dit niet wordt voorgelezen. Op de normale weergave op het scherm heeft dit verder geen enkele invloed.
De extra informatie zit in een <span> met role="tooltip", waardoor deze met behulp van aria-describedby in de <a> gelijk na de tekst in de link worden voorgelezen. Je zou denken dat een schermlezer dan begrijpt dat dat voldoende is, maar schermlezers blijken de tekst in de <span> nogmaals voor te lezen. Door aan de <span> aria-hidden="true" toe te voegen, wordt dat voorkomen:
<span id="tt-1" role="tooltip" aria-hidden="true">Ruimte voor informatie over de inhoud van pagina 1</span>
Toetsenbordnavigatie en tabindex
Op een desktopcomputer gebruiken de meeste mensen een muis om over een pagina te navigeren, links te volgen, en dergelijke. Soms gebruiken mensen hier echter een toetsenbord voor, omdat ze geen muis kunnen of willen gebruiken. Navigeren, links volgen, en dergelijke gebeurt dan met behulp van de Tab-toets, Enter, Spatiebalk, pijltjestoetsen, en dergelijke. (Overigens wordt ook bij aanraakschermen soms een toetsenbord en/of muis gebruikt.)
Als je alleen simpele html zou gebruiken, werkt deze toetsenbordnavigatie fantastisch. Maar soms kan een bepaalde constructie in de html of in de css de werking ervan verstoren. Bij het maken van een website moet je er vooral op letten dat alles bereikbaar is met de Tab-toets. Voor andere toetsen zijn dan meestal geen aanpassingen nodig.
Links, invoervelden in formulieren, en dergelijke kunnen met behulp van de Tab-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. Daarna worden elementen die automatisch al de focus kunnen krijgen (zoals een link en een knop) en elementen met een tabindex="0" afgewerkt in de volgorde, waarin ze in de html staan.
tabindex="-1"
Een negatieve waarde van -1 zorgt ervoor dat een element, dat normaal genomen door het gebruik van de Tab-toets de focus kan krijgen, volledig wordt genegeerd door de Tab-toets. Zelfs een link met een negatieve tabindex wordt volledig genegeerd.
Ook kan aan een element met een negatieve tabindex dat normaal genomen geen focus kan krijgen, toch de focus worden gegeven met behulp van JavaScript, een klik of een aanraking. Waarbij gebruikers van de Tab-toets daar geen last van hebben, omdat tabindex="-1" wordt genegeerd door de Tab-toets.
In dit voorbeeld wordt tabindex="-1" op drie plaatsen gebruikt.
<html lang="nl" tabindex="-1">
Op Android en Windows kan het venstertje met informatie weer worden gesloten door ergens buiten het menu het scherm aan te raken (op Windows uiteraard alleen als het apparaat een aanraakscherm heeft).
Op iOS en iPadOS is dat niet het geval. Door aan <html> een negatieve tabindex te geven, kan ook op iOS en iPadOS het venstertje worden gesloten door ergens buiten het menu het scherm aan te raken.
(Zoals iets hieronder beschreven heeft ook <main> een tabindex="-1", waardoor het venstertje ook gesloten wordt door ergens buiten het menu <main> aan te raken. Maar dan moet je het scherm binnen <main> aanraken, en <main> bestrijkt mogelijk niet het hele scherm, waardoor dit mogelijk niet overal op het scherm werkt.)
<li tabindex="-1">
Een <li> kan normaal genomen niet de focus krijgen. Maar dat is hier wel nodig, omdat op aanraakschermen een aantal dingen wordt geregeld met behulp van li:focus-within. Als op een aanraakscherm de <li> nu wordt aangeraakt, kan deze toch de focus krijgen.
(Met een muis speelt dit niet, die worden dingen geregeld met li:hover, en dat werkt gewoon standaard bij een <li>.)
<main id="inhoud" tabindex="-1">
Als in een browservenster smaller dan 760 px Escape wordt ingedrukt, terwijl geen van de knoppen de focus heeft, wordt het menu gesloten en de focus op <main> gezet. Daardoor kan het menu snel worden gesloten en kan met scrollen en dergelijke gelijk worden verder gegaan met de tekst en dergelijke onder de knoppen. Dit wordt geregeld met behulp van JavaScript. Maar om <main> de focus te kunnen geven, is het attribuut tabindex="-1" nodig.
tabindex="0"
Als je tabindex="0" gebruikt, kan een element focus krijgen met behulp van de Tab-toets, door een aanraking of door een klik. Ook als dat element normaal genomen geen focus kan krijgen.
tabindex="0" wordt in dit voorbeeld niet gebruikt.
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".
In dit voorbeeld wordt een tabindex met een positief getal niet gebruikt.
Muis, toetsenbord, touchpad en aanraakscherm
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 aanraakschermen 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 aanraakschermen 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 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 dat 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.
Op een aanraakscherm wordt hoveren vaak hetzelfde afgehandeld als een aanraking.
Bij gebruik van een muis is er een verschil tussen hoveren en klikken, maar op een aanraakscherm is dat verschil er niet: je raakt een aanraakscherm 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.
Op een laptop met een aanraakscherm zal een aanraking in de regel hetzelfde werken als een klik met een muis: de link wordt gelijk gevolgd en het venstertje met informatie wordt niet of alleen in een flits getoond. Het tonen van het venstertje met behulp van :hover werkt daardoor niet, als op een laptop met een aanraakscherm de link wordt aangeraakt. Daarom is deze constructie niet geschikt, als in het venstertje met informatie belangrijke informatie staat. (Bij gebruik van een muis werkt het wel, omdat dan hoveren en klikken twee verschillende handelingen zijn.)
In browservensters smaller dan 760 px is er weinig ruimte. Daarom is het menu daar verborgen, tot een aankruisvakje wordt aangevinkt. Omdat :hover daar niet wordt gebruikt, levert dit geen problemen op.
Anders is het bij het menu zelf, want daar wordt :hover wel gebruikt. Bij gebruik van een muis wordt bij hoveren over een <li> het venstertje met informatie geopend, en bij een klik op de in de <li> zittende <a> wordt de link gevolgd.
Als het venstertje met informatie wordt geopend door hoveren over de link, wordt op een aanraakscherm ook gelijk de link gevolgd, want die wordt ook aangeraakt. Afhankelijk van besturingssysteem en browser zie je soms in een flits even het venstertje, maar soms zie je het helemaal niet.
Daarom wordt op een aanraakscherm de link met behulp van pointer-events: none; ongevoelig gemaakt voor een aanraking. Omdat de <li>, waar de link in zit, een tabindex="-1" heeft gekregen, is deze op een aanraakscherm juist gevoelig gemaakt voor een aanraking: de <li> kan de focus krijgen.
Hierdoor kan bij de eerste aanraking het venstertje met informatie worden geopend. Gelijktijdig wordt bij de in de <li> zittende link pointer-events: none; veranderd in pointer-events: auto;. Hierdoor zal bij een tweede aanraking de link worden gevolgd.
Op apparaten waar een muis (of een touchpad) de belangrijkste aanwijzer is, mag hoveren gewoon werken. Bij hoveren over de <li> opent het venstertje met informatie en bij klikken op de link wordt de link gevolgd. Omdat je altijd over de <li> hovert als je op de link wilt klikken, werkt dit prima. Met behulp van een @media-regel wordt het hoveren beperkt tot apparaten, waarbij de belangrijkste aanwijzer een muis of een touchpad is.
: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. (Dit geldt uiteraard niet voor aanraakschermen.)
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 Toetsenbordnavigatie en tabindex.)
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.
Bij gebruik van de muis of een aanraakscherm is het kadertje niet nodig, want je mag toch hopen dat iemand weet, waar iemand iets heeft heeft aangeraakt of -geklikt. Als je dat niet meer weet, valt te vrezen dat een kadertje ook geen redding meer biedt.
In het verleden was dat vaak een probleem, omdat dat kadertje nou niet bepaald erg mooi is. En dus eigenlijk alleen bij gebruik van de Tab-toets nodig is. Dit is opgelost met de pseudo-class :focus-within: de focus wordt alleen nog aangegeven, als een toetsenbord wordt gebruikt. Bij een klik of een aanraking zie je het kadertje niet meer.
Inmiddels is :focus-within in alle iets nieuwere browsers de standaard, dus eigenlijk hoef je :focus en/of :focus-within alleen nog te gebruiken, als je bijvoorbeeld het uiterlijk van het kadertje wilt aanpassen.
Voor de Tab-toets zijn hier geen aanpassingen nodig: die gaat gewoon van <a> naar <a>, waarbij bij de <p> met de focus het venstertje met informatie wordt getoond. Ook wordt de achtergrond van de <a> wit en de tekst wordt onderstreept zwart.
Op een aanraakscherm doen zich hier echter wel problemen voor. Als de <a> wordt aangeraakt, wordt de link gelijk gevolgd. Het venstertje met informatie wordt, afhankelijk van browser en besturingssysteem, helemaal niet of heel kort in een flits getoond.
Daarom wordt aan de <li>'s een tabindex="-1" gegeven. Nu kunnen de <li>'s bij aanraking de focus krijgen, waardoor het venstertje met informatie wordt getoond. De achtergrond van de <a> in de <li> wordt wit en de tekst in de <a> onderstreept zwart.
De <a>'s in de links zijn met behulp van pointer-events="none" ongevoelig voor een aanraking gemaakt. Als de <li> de focus krijgt, wordt dit veranderd in pointer-events="auto". Bij de tweede aanraking wordt de link hierdoor gewoon gevolgd.
In browservensters smaller dan 760 px kan de bezoeker het menu tonen of verbergen. Dat verbergen kan ook door het venster ergens buiten het menu aan te raken. In dat geval wordt de focus op <main> gezet, waarin de eigenlijke tekst van de pagina zit. Dit zorgt ervoor dat het geopende menu makkelijk gesloten kan worden, als het een deel van de pagina bedekt.
<main> krijgt de focus met behulp van JavaScript. Omdat <main> normaal genomen geen focus kan krijgen, heeft <main> een tabindex="-1" gekregen.
: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 aanraakschermen is het element actief, als het wordt aangeraakt.
:active wordt niet gebruikt in dit voorbeeld.
Gegenereerde code
Het onderstaande geldt alleen voor desktopbrowsers. In browsers op mobiele systemen is het vaak ook mogelijk gegenereerde code te bekijken, maar dat is veel ingewikkelder. Bovendien verandert de manier, waarop dat kan, nogal snel.
Als je html schrijft, kan dat (hopelijk) in de browser worden weergegeven. Vanuit de browser kun je die html bekijken, precies zoals je de code hebt ingevoerd. Alsof je het in een editor ziet. In Firefox bijvoorbeeld kan dat door in het menu te kiezen voor Extra → Browserhulpmiddelen → Paginabron. (Of door de veel snellere sneltoets Ctrl+U.) Elke browser heeft dit soort mogelijkheden.
Wat je dan te zien krijgt, is exact de code, zoals jij die hebt ingetypt. Inclusief alle fouten, hoofd- en kleine letters, noem maar op. Als je zo slordig bent om een <p> niet af te sluiten, zit er niet plotsklaps een afsluitende </p> in de code. Als er css wordt gebruikt, html wordt ingevoegd via JavaScript, noem maar op, zie je daar niets van, want dat heb jij niet ingetypt.
Daar heb je dus eigenlijk vrij weinig aan, want die code kende je al. Die heb je zelf fluitend of met bloed, zweet en tranen zitten intypen.
Wat de browser daadwerkelijk gebruikt, is iets totaal anders: de gegenereerde code. En die is veel interessanter, want die code blijkt (fors) af te wijken, van wat jij heb ingetypt. De browser gebruikt een tijdelijke kopie van de door jou geschreven code, die zo is aangepast dat er voor de browser mee is te werken.
Elke browser heeft inmiddels mogelijkheden om de gegenereerde code te bekijken. In Firefox bijvoorbeeld in het menu Extra → Browserhulpmiddelen → Webontwikkelaarshulpmiddelen. In Google Chrome in het menu onder Meer hulpprogramma's → Hulpprogramma's voor ontwikkelaars. In Edge open je dit door op F12 te drukken, en het kan vast ook via het menu.
Houdt er wel rekening mee dat elke browser de door jou ingetypte code iets zal aanpassen. In Firefox bijvoorbeeld wordt een <P> veranderd in een <p>. Als er 'n </p> mist, is die opeens wel aanwezig in de gegenereerde code. Wat elke browser precies aanpast, zal iets verschillen en kan ook nog veranderen. Oudere versies van Internet Explorer bijvoorbeeld veranderden een <p> juist in een <P>, nieuwere versies deden dat niet meer.
Als je met behulp van JavaScript elementen invoegt of verwijdert in de HTML (zoals in dit voorbeeld gebeurt), zie je dat alleen in deze gegenereerde code.
De code aanpassen aan je eigen ontwerp
- Als je dit voorbeeld gaat aanpassen voor je eigen site, houd het dan in eerste instantie zo eenvoudig mogelijk. Ga vooral geen details invullen.
-
Gebruik geen FrontPage, Publisher of Word (alle drie van Microsoft). Publisher en Word zijn niet bedoeld om websites mee te maken. FrontPage is zwaar verouderd en wordt al jaren niet meer onderhouden door Microsoft.
Ook OpenOffice en LibreOffice leveren een uiterst beroerd soort html af. Tekstverwerkers met al hun toeters en bellen zijn gewoon niet geschikt om websites mee te bouwen.
Je kunt beter een goed (gratis) programma gebruiken. Links naar dat soort programma's vind je op de pagina met links onder Gereedschap → wysiwyg-editor en Gereedschap → Editors en IDE's.
Maar het allerbeste is om gewoon zelf html, css, enzovoort te leren, omdat zelfs het allerbeste programma het nog steeds zwaar verliest van 'n op de juiste manier met de hand gemaakte pagina.
-
Als je in een desktopbrowser met behulp van zoomen het beeld vergroot, heeft dit hetzelfde effect, als wanneer de pagina in een kleiner browservenster wordt getoond. Je kunt hiermee dus kleinere apparaten zoals een tablet of een smartphone simuleren. Maar het blijft natuurlijk wel een simulatie: het is nooit hetzelfde als testen op een écht apparaat. Zo kun je bijvoorbeeld aanrakingen alleen echt testen op een echt aanraakscherm.
Inmiddels hebben veel browsers in de ontwikkelgereedschappen mogelijkheden voor het simuleren van weergave op een kleiner scherm ingebouwd. Ook dit blijft een simulatie, maar geeft vaak wel een beter beeld dan zoomen.
-
Als je 'n site maakt in Firefox, Opera, Safari, Google Chrome, Vivaldi of Edge, is er 'n hele grote kans dat die in alle browsers werkt. Hier wordt de voorkeur gegeven aan Firefox, omdat het een van de weinige browsers is, die niet bij een bedrijf hoort dat vooral op je centen of je data uit is.
Google Chrome wordt ook door veel mensen gebruikt, maar slaat ondertussen wel je hele surfgedrag, je schoenmaat en de kleur van je onderbroek op. Daarom wordt Google Chrome alleen gebruikt om in te testen.
-
Het allereerste dat je moet invoeren, is het doctype, vóór welke andere code dan ook. Een lay-out met een missend of onvolledig doctype ziet er totaal anders uit dan een lay-out met een geldig doctype. Wát er anders is, verschilt ook nog 'ns tussen de diverse browsers. Als je klaar bent en dan nog 'ns 'n doctype gaat invoeren, weet je vrijwel zeker dat je van voren af aan kunt beginnen met de lay-out.
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.
-
Gebruik het doctype voor html5. Dit is bedoeld voor nieuwe sites.
Het oudere transitional doctype staat talloze tags toe, die in html5 zijn verboden. Deze tags worden al zo'n tien jaar afgeraden. Het transitional doctype is alleen bedoeld om de puinhoop van vroeger, toen niet volgens standaarden werd gewerkt, enigszins te herstellen.
Het (ook al oudere) strict doctype staat verouderde tags niet toe. Daardoor kan met 'n strict doctype, of het nu html of xhtml is, probleemloos worden overgestapt naar html5. Met een transitional doctype en het gebruik van afgekeurde tags kun je niet overstappen naar html5. Je moet dan eerst alle verouderde tags verwijderen, wat echt ontzettend veel werk kan zijn.
Het doctype voor html5 is uiterst simpel:
<!doctype html>. Omdat het doctype voor html5 in alle browsers werkt, zelfs in de gelukkig vrijwel uitgestorven nachtmerrie Internet Explorer 6, is er geen enkele reden dit uiterst simpele doctype niet te gebruiken. - De eerste regel binnen de <head> moet de charset zijn. Dit vertelt de browser, welke tekenset er gebruikt moet worden, zodat letters met accenten en dergelijke overal goed worden weergegeven. Het beste kun je utf-8 nemen. Als je later van charset verandert, loop je 'n grote kans dat je alle aparte tekens als letters met accenten weer opnieuw moet gaan invoeren. In html5 is het simpele
<meta charset="utf-8">voldoende. - Test vanaf het allereerste begin in zoveel mogelijk verschillende browsers in 'n aantal resoluties (schermgroottes). Onder het kopje Getest in kun je in deze uitleg vinden, waar dit voorbeeld in is getest.
- Voor alle voorbeelden geldt: breng veranderingen stapsgewijs aan. Als je bijvoorbeeld foto's wilt laten weergeven, begin dan met het alleen veranderen van de namen van de foto's, zodat je eigen foto's worden weergegeven. Maakt niet uit als de maten niet kloppen en de teksten fout zijn. Als dat werkt, ga dan bijvoorbeeld de maten aanpassen. Dan de teksten. En controleer steeds, of alles nog goed werkt.
-
Als het om een lay-out of iets dergelijks gaat: zorg eerst dat header, kolommen, footer, menu, en dergelijke staan en bewegen, zoals je wilt. Ga daarna pas details binnen die blokken invullen. In eerste instantie gebruik je dus bijvoorbeeld 'n leeg blok op de plaats, waar uiteindelijk het menu komt te staan.
Als je begint met allerlei details, is er 'n heel grote kans dat die de werking van de blokken gaan verstoren. Bouw eerst het huis, en ga dan pas de kamers inrichten. Zorg eerst dat de blokken werken, zoals je wilt. Dan zul je het daarna gelijk merken, als 'n toegevoegd detail als tekst of 'n afbeelding iets gaat verstoren. Daarvoor moet je natuurlijk wel regelmatig controleren in verschillende browsers, of alles nog wel goed werkt.
Je kunt de blokken tijdens het aanpassen opvullen met bijvoorbeeld <br>1<br>2<br>3 enzovoort, tot ze de juiste hoogte hebben. Het is handig om aan het einde even iets toe te voegen als 'laatste', zodat je zeker weet dat er niet ongemerkt drie regels onderaan naar 't virtuele walhalla zijn verhuisd.
Om de breedte te vullen, kun je het best 'n kort woord als 'huis' duizend keer of zo herhalen. Ook hier is het handig om aan 't eind (en hier ook aan 't begin) 'n herkenningsteken te maken, zodat je zeker weet dat je de hele tekst ziet.
- Zolang je in grotere dingen zoals 'n lay-out aan 't wijzigen bent, kan het helpen de verschillende delen een achtergrondkleur of een outline te geven. Je ziet dan goed, waar 'n deel precies staat. Een achtergrondkleur en een outline hebben - anders dan bijvoorbeeld een border - verder geen invloed op de lay-out, dus die zijn hier heel geschikt voor.
- Als je eigenschappen verandert in de css, verander er dan maar één, hooguit twee tegelijk. Als je er zeventien tegelijk verandert, is de kans groot dat je niet meer weet, wat je hebt gedaan. En dat je 't dus niet meer terug kunt draaien.
-
margin,paddingenborderworden bij de breedte en hoogte van het element opgeteld. Hier worden vaak fouten mee gemaakt. Als je bijvoorbeeld in een lay-out 'n border toevoegt aan een van de 'hoofdvakken' (header, footer, kolommen), dan wordt deze er bij opgeteld. Bij 'n border van 2 px rondom de linkerkolom wordt deze dus plotseling 4 px breder (2 px aan beide kanten), en 4 px hoger. Zoiets kan je hele lay-out verstoren, omdat iets net te breed of te hoog wordt. Je moet dan elders iets 4 px kleiner maken. Dat zal vaak zo zijn: als je één maat verandert, zul je vaak ook 'n andere moeten aanpassen.Css geeft de mogelijkheid om met behulp van
box-sizingde padding en border bínnen de breedte en hoogte van de inhoud te zetten, als je dat handiger vindt.Met nieuwere css-eigenschappen als grid en flexbox, die speciaal zijn gemaakt om een lay-out mee te maken, spelen dit soort problemen veel minder. In alle browsers waarop hier nog wordt getest, werken flexbox en grid prima. Maar als je oudere browsers moet ondersteunen, kan dat wel problemen opleveren en moet je ook in die oudere browsers testen.
-
In plaats van een absolute eenheid als
pxkun je ook een relatieve eenheid gebruiken, met nameemenrem. Voordeel vanemenremis dat een lettergrootte, regelhoogte, en dergelijke inemenremin alle browsers kan worden veranderd. Nadeel is dat het de lay-out sneller kan verstoren dan bijvoorbeeldpx. Dit moet je gewoon van geval tot geval bekijken. Voor weergave in mobiele apparaten zijn relatieve eenheden alsemenremvrijwel altijd beter dan absolute eenheden alspx.(De minder bekende
remis ongeveer hetzelfde als deem. Alleen is de lettergrootte bijremgebaseerd op de lettergrootte van het <html>-element, waardoor deremoveral op de pagina precies even groot is. Bij deemkan de lettergrootte worden beïnvloed door de voorouders van het element, bij deremniet.)Zoomen kan trouwens altijd, ongeacht welke eenheid je gebruikt.
-
Valideren, valideren, valideren en dan voor 't slapen gaan nog 'ns valideren.
Valiwie???
Valideren is het controleren van je html en css op 'n hele serie fouten. Computers zijn daar vaak veel beter in dan mensen. Als je 300 keer <h2> hebt gebruikt en 299 keer </h2> vindt 'n computer die ene missende </h2> zonder enig probleem. Jij ook wel, maar daarna ben je misschien wel aan vakantie toe.
Valideren kan helpen om gekmakende fouten te vinden. Valide code garandeert ook dat de weergave in verschillende browsers (vrijwel) hetzelfde is. En valide code is over twintig jaar ook nog te bekijken.
Valideren moet trouwens ook niet worden overdreven. Het is een hulpmiddel om echte fouten te vinden, meer niet. Het gaat erom dat je site goed werkt, niet dat je het braafste kind van de klas bent. Als de code niet valideert, maar daar is een goede reden voor, is daar niets op tegen. Zeker met nieuwere html en css wil de validator nog wel eens achterlopen, terwijl dat al prima is te gebruiken.
Op deze site is alle css en html gevalideerd. Als de code niet helemaal valide is (wat regelmatig voorkomt), staat daar onder Bekende problemen (en oplossingen) de reden van.
Je kunt je css en html valideren als 't online staat, maar ook als het nog in je computer staat.
Html kun je valideren op: validator.w3.org/nu.
Css kun je valideren op: jigsaw.w3.org/css-validator.
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:
-
Gebruik altijd een alt-beschrijving bij een afbeelding. De alt-tekst wordt gebruikt door schermlezers en als afbeeldingen niet kunnen worden getoond of gezien (dat geldt dus ook voor zoekmachines). Als je iets wilt laten zien, als je over de afbeelding hovert, gebruik daar dan het title-attribuut voor, niet de alt-beschrijving.
Als een afbeelding alleen maar voor de sier wordt gebruikt, zet je daarbij
alt="", om aan te geven dat de afbeelding niet belangrijk is voor het begrijpen van de tekst of zo. -
Gebruik in links een tekst die duidelijk aangeeft, waar de link naartoe gaat. Een tekst als 'pagina met externe links' is waarschijnlijk duidelijk genoeg, een tekst als alleen 'links' waarschijnlijk niet. Een duidelijke zwart-witregel is niet te geven, omdat dit ook van tekst en dergelijke in de omgeving van de link afhangt.
Schermlezers kunnen een lijst van alle links in de pagina weergeven, en een duidelijke tekst is daarbij belangrijk. Alleen 'volgende' zegt niets, als dat in 'n lijst met alleen links staat.
-
Accesskeys (sneltoetsen) kun je beter niet gebruiken, deze geven te veel problemen, omdat ze vaak dubbelop zijn met sneltoetsen voor de browser of andere al gebruikte sneltoetsen. Bovendien is voor de gebruiker meestal niet duidelijk, welke toetsen het zijn.
Op zichzelf zijn accesskeys een heel goed idee. Maar helaas zijn ze ook in html5 volstrekt onvoldoende gedefinieerd. Er is nog steeds geen standaard voor de meest gebruikelijke accesskeys, zoals Zoek of Home.
Er is nog steeds niet vastgelegd, hoe accesskeys zichtbaar gemaakt kunnen worden. Voor de makers van browsers zou dit 'n relatief kleine moeite zijn, voor de makers van 'n site is het bergen extra werk.
Hierdoor zijn accesskeys (vrijwel) niet te gebruiken. Misschien kunnen ze nog enig nut hebben op sites, die gericht zijn op 'n specifieke groep gebruikers. Maar voor algemene sites is het advies: normaal genomen niet gebruiken.
-
Met behulp van de Tab-toets (of op 'n soortgelijke manier) kun je door links, invoervelden, en dergelijke lopen. Elke tab brengt je één link, invoerveld, en dergelijke verder, Shift+Tab één plaats terug. Met behulp van het attribuut
tabindexkun je de volgorde aangeven, waarin de Tab-toets werkt. Zondertabindexwordt de volgorde van de html aangehouden bij gebruik van de Tab-toets, maar soms is een andere volgorde logischer.In principe is het beter, als
tabindexniet nodig is, maar gewoon de volgorde van de html wordt aangehouden. Bij verkeerd gebruik kantabindexheel verwarrend zijn. Het is niet bedoeld om van de pagina een hindernisbaan voor kangoeroes te maken, waarop van beneden via links over rechts naar boven wordt gesprongen. (Meer over de Tab-toets is te vinden bij Toetsenbordnavigatie en tabindex.) - Als, zoals hierboven beschreven, een gebruiker van de Tab-toets bij een link, invoerveld, en dergelijke is aangekomen, heeft dit element 'focus'. Dit wordt aangegeven door de link, invoerveld, en dergelijke extra te markeren met een kadertje. Dat kadertje mag je alleen weghalen, als op een andere manier wordt duidelijk gemaakt, welk element focus heeft. Een gebruiker van de Tab-toets kan anders niet zien, waar die zit, en welk element gaat reageren op bijvoorbeeld een Enter. (Meer over focus is te vinden bij focus.)
- In het verleden werd vaak aangeraden de volgorde van de code aan te passen. Een menu bijvoorbeeld kon in de html onderaan worden gezet, terwijl het op het scherm met behulp van css bovenaan werd gezet. Inmiddels zijn schermlezers en dergelijke zo sterk verbeterd dat dit niet meer wordt aangeraden. De volgorde in de html kan tegenwoordig beter hetzelfde zijn als die op het scherm, omdat het anders juist verwarrend kan werken. Schermlezers houden namelijk altijd de volgorde van de html aan en niet een eventueel afwijkende volgorde op het scherm.
-
Een zogenaamde skip-link is vaak nog wel zinvol. Dat is een link die je buiten het scherm parkeert met behulp van css, zodat die normaal genomen niet te zien is. Zo'n link is wel gewoon zichtbaar in speciale programma's zoals tekstbrowsers en schermlezers, want die kijken gewoon naar wat er in de broncode staat.
(Alleen in de schermlezer TalkBack op oudere versies van Android werkt zo'n buiten het scherm geplaatste link niet. TalkBack leest zo'n link wel voor, maar de link kan niet worden gevolgd, als deze buiten het scherm staat. Met ingang van versie 8.1 van Android is dit eindelijk opgelost en werkt een skip-link ook fatsoenlijk in TalkBack.)
Een skip-link staat bovenaan de pagina, nog boven menu, header, en dergelijke, en linkt naar de eigenlijke inhoud van de pagina. Hierdoor kunnen mensen met één toetsaanslag naar de eigenlijke inhoud van de pagina gaan.
Een skip-link is vooral nuttig voor gebruikers van de Tab-toets. Zodra de normaal genomen onzichtbare link door het indrukken van de Tab-toets focus krijgt, kun je de link op het scherm plaatsen, waardoor deze zichtbaar wordt. Bij een volgende tab wordt de link dan weer buiten het scherm geplaatst en is dus niet meer zichtbaar, zodat de lay-out niet wordt verstoord.
-
Van oorsprong is html een taal om wetenschappelijke documenten weer te geven, pas later is deze gebruikt voor lay-out. Maar daar is de taal dus eigenlijk nooit voor bedoeld geweest. Het gebruiken van html voor lay-out leidt tot enorme problemen voor gehandicapten en tot een lage plaats in zoekmachines.
De html hoort alleen inhoud te bevatten, lay-out doe je met behulp van css. Die css moet in een extern stijlbestand staan of, als deze alleen voor één bepaalde pagina van toepassing is, in de <head> van die pagina.
-
Breng een logische structuur aan in je document. Gebruik een <h1> voor de belangrijkste kop, een <h2> voor een subkop, enzovoort. Schermlezers en dergelijke kunnen van kop naar kop springen. En een zoekmachine gaat ervan uit dat <h1> belangrijke tekst bevat.
Dit geldt voor al dit soort structuurbepalende tags.
Als een <h1> te grote letters geeft, maak daar dan met behulp van je css 'n kleinere letter van, maar blijf die <h1> gewoon gebruiken. Op dezelfde manier kun je al dit soort dingen oplossen.
- <table> is fantastisch, maar alleen als die wordt gebruikt om een echte tabel weer te geven, niet als <table> voor opmaak wordt misbruikt. In het verleden is dat op grote schaal gebeurd bij gebrek aan andere mogelijkheden. Een tabel is, als je niet heel erg goed oplet, volstrekt ontoegankelijk voor gehandicapten en zoekmachines. Het lezen van een tabel is ongeveer te vergelijken met het lezen van een papieren krant van links naar rechts: niet per kolom, maar per regel. Dat gaat dus alleen maar goed bij een echte tabel, zoals een spreadsheet. In alle andere gevallen garandeert 'n tabel volstrekte ontoegankelijkheid voor schermlezers en dergelijke en als extra bonus vaak 'n lagere plaats in een zoekmachine.
-
Frames horen bij een volstrekt verouderde techniek, die heel veel nadelen met zich meebrengt. <iframe>'s hebben voor een deel dezelfde nadelen. Eén van die nadelen is dat de verschillende frames voor zoekmachines, schermlezers, en dergelijke als los zand aan elkaar hangen, omdat ze los van elkaar worden weergegeven. Ze staan wel naast elkaar op het scherm, maar er zit intern geen verband tussen.
Als je 'n stuk code vaker wilt gebruiken, zoals 'n menu dat op elke pagina hetzelfde is, voeg dat dan in met PHP. Dan wordt de pagina niet pas in de browser, maar al op de server samengesteld. Hierdoor zien zoekmachines, schermlezers, en dergelijke één pagina, net zoals wanneer je maar één pagina met html zou hebben geschreven.
(Je kunt ook invoegen met behulp van SSI. Maar tegenwoordig kun je beter PHP dan SSI gebruiken, omdat SSI min of meer aan het uitsterven is en PHP veel meer mogelijkheden heeft.)
-
Geef de taal van het document aan, en bij woorden en dergelijke die afwijken van die taal de afwijkende taal met behulp van
lang="...". Op deze site gebeurt dat lang niet overal, omdat de tekst (en vooral de code) een mengsel is van Engels, Nederlands en eigengemaakte namen. Dat soort teksten is gewoon niet goed in te delen in een taal. Maar bij enigszins 'normale' teksten hoor je een taalwisseling aan te geven.Op deze site wordt de lijst op woordenlijst.org gebruikt om te bepalen, of een woord inmiddels 'Nederlands' is. Als het woord in deze lijst voorkomt, wordt geen
lang-attribuut gebruikt, ook niet als het woord oorspronkelijk uit een andere taal komt. - Gebruik de tag <abbr> bij afkortingen. Doe dat de eerste keer op een pagina samen met de title-eigenschap:
<abbr title="ten opzichte van">t.o.v.</abbr>. Daarna kun je op dezelfde pagina volstaan met<abbr>t.o.v.</abbr>. Doe je dit niet, dan is er 'n grote kans dat 'n schermlezer 't.o.v.' uit gaat spreken als 'tof', en 'n zoekmachine kan er ook geen chocola van maken. - Geef een verandering niet alleen door kleur aan. Een grote groep mensen heeft moeite met het onderscheiden van kleuren en/of het herkennen van kleuren. Verander bijvoorbeeld een ronde rode knop niet in een ronde groene knop, maar in een vierkante groene knop. Door ook de vorm te veranderen, is het herkennen van de verandering niet alleen van een kleur afhankelijk.
- Zorg voor voldoende contrast tussen achtergrond- en voorgrondkleur, tussen
background-colorencolor. Soms zie je heel lichtgrijze tekst op een donkergrijze achtergrond, en dan ook nog in een mini-formaat. Dat is dus voor heel veel mensen stomweg volledig onleesbaar. Op de pagina met links staat onder het kopje Toegankelijkheid → Contrast en kleurenblindheid een hele serie sites, waar je kunt controleren of het contrast groot genoeg is. -
De spider van 'n zoekmachine, schermlezers, en dergelijke kunnen geen plaatjes 'lezen'. Het is soms verbazingwekkend om te zien hoe veel, of eigenlijk: hoe weinig tekst er overblijft op een pagina, als de plaatjes worden weggehaald.
Op Linux kun je met Lynx kijken, hoe je pagina eruitziet zonder plaatjes en dergelijke, als echt alleen de tekst overblijft. Een installatie-programma voor Lynx op Windows is te vinden op invisible-island.net/lynx.
Ook kun je in Windows het gratis programma WebbIE installeren. WebbIE laat de pagina zien, zoals een tekstbrowser en dergelijke deze ziet. WebbIE is te downloaden vanaf www.webbie.org.uk.
Ten slotte kun je je pagina nog online op toegankelijkheid laten controleren op 'n behoorlijk aantal sites, zoals:
lowvision.support: laat zien hoe een kleurenblinde de site ziet. Engelstalig.
wave.webaim.org: deze laat grafisch zien, hoe de toegankelijkheid is. Engelstalig. Deze tester is ook als extensie in Firefox en Google Chrome te installeren.
Op de pagina met links kun je onder Toegankelijkheid links naar meer tests en dergelijke vinden.
Getest in
Laatst gecontroleerd op 26 september 2025.
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
Linux (KDE neon 6.4.4) (2560 x 1080 px, resolutie: 96 ppi):
Firefox, Google Chrome en Vivaldi, in grotere en kleinere browservensters.
In Vivaldi is ook ruimtelijke navigatie ('Spatial Navigation') getest.
Laptops
Windows 10 (1600 x 900 px, resolutie: 106 ppi):
Firefox, Google Chrome en Edge, in grotere en kleinere browservensters.
macOS 11.7.10 ('Big Sur') (1440 x 900 px, resolutie: 96 ppi):
Firefox, Safari, Google Chrome en Microsoft Edge, in grotere en kleinere browservensters.
macOS 26 ('Tahoe') (2500 x 1600 px, resolutie: 227 ppi):
Firefox, Safari, Google Chrome en Microsoft Edge, in grotere en kleinere browservensters.
Tablets
iPad met iOS 12.5.7 (2048 x 1536 px, device-pixel-ratio: 2:
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).
iPad met iPadOS 18.6.2 (2160 x 1620 px, resolutie: 264 ppi):
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).
Android 6.0 ('Marshmallow') (1920 x 1200 px, resolutie: 224 ppi):
Samsung Internet, Firefox en Chrome (alle portret en landschap).
Android 8.1 ('Oreo') (1920 x 1200 px, resolutie: 218 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Android 13 ('Tiramisu') (2000 x 1200 px, resolutie: 225 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Smartphones
iPhone met iOS 15.8.4 (1334 x 750 px, resolutie: 326 ppi):
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).
iPhone met iOS 18.6.2 (1334x750, resolutie: 326 ppi): Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).
Android 7.0 ('Nougat') (1280 x 720 px, resolutie: 294 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Android 9.0 ('Pie') (1920 x 1080 px, resolutie: 424 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Android 14 ('Upside Down Cake') (2408 x 1080 px, resolutie: 401 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, iPadOs en Android, waar een aanraakscherm is gebruikt. Op Windows 10 is getest met aanraakscherm, touchpad, toetsenbord, muis, en - waar dat zinvol was - op een combinatie daarvan. Op macOS 11.7.10 en 15.6 is getest met (een combinatie van) toetsenbord, touchpad en muis.
Als in een voorbeeld JavaScript is gebruikt, is ook getest of het werkt zonder JavaScript. Dat is alleen gedaan in de browsers, waarin in de instellingen JavaScript kan worden uitgeschakeld.
Ook 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, Orca 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 Windows 10.
NVDA is een schermlezer, zoals die door blinden wordt gebruikt. Er is getest op Windows 10 in combinatie met Firefox.
TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome op Android 6.0, 7.0, 8.1, 9, 13 en 14
VoiceOver is een in iOS en macOS ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS 12.5.7, 15.8.4 en 18.6.2, iPadOS 18.6.2, macOS 11.7.10 en 26.
Orca is een schermlezer voor Linux. Er is getest in combinatie met Firefox op KDE Neon 6.4.4.
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).
Waar dat zinvol was, is ook nog getest op combinaties als een grote letter in een schermlezer met toetsenbordbediening.
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, toetsenbordnavigatie, tekstbrowsers, schermlezers en zoomen en andere lettergrootte.
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. Bij een onderwerp over toegankelijkheid zijn er soms, naast de opgeloste problemen, ook aanpassingen. In dat geval staan staan die aanpassingen boven de kadertjes met opgeloste problemen.
Als bij het probleem geen oplossing is gevonden, staat de samenvatting in een rode ononderbroken lijn. Bij een onderwerp over toegankelijkheid zijn er soms, naast de problemen, ook aanpassingen. In dat geval staan staan die aanpassingen boven de kadertjes met problemen.
Zonder JavaScript
Probleem: zonder JavaScript is de toegankelijkheid slechter.
Zonder JavaScript werkt alles nog steeds, maar voor gebruikers van schermlezers en Tab-toets werkt het minder handig:
- In browservensters smaller dan 760 px kan het menu alleen worden geopend door een aanraking, een klik of de Spatiebalk. De Enter-toets werkt niet.
- In browservensters smaller dan 760 px kan het menu niet worden gesloten met Escape.
- In browservensters smaller dan 760 px wordt de focus niet op <main> gezet, als het scherm ergens buiten het menu wordt aangeraakt.
- De WAI-ARIA-code aria-expanded houdt altijd de waarde
false, waardoor schermlezers altijd melden dat het menu niet wordt getoond, ook als het wel wordt getoond.
Zonder css
Geen problemen.
Alle links werken gewoon. De venstertjes met informatie staan gelijk achter de links op het scherm. Het geheel ziet er niet uit, maar dat is logisch zonder css.
Toetsenbordnavigatie
Geen problemen.
Bij gebruik van de Tab-toets wordt van link naar link gesprongen, waarbij het bij de link horende venstertje met informatie wordt getoond.
Met behulp van JavaScript kan in browservensters smaller dan 760 px het menu ook worden geopend en gesloten met de Enter-toets, en het kan ook worden gesloten met Escape.
Tekstbrowsers
Probleem: webbIE toont de extra informatie niet.
Lynx toont de links met gelijk daarachter de extra informatie.
In webbIE werken de links gewoon, maar de extra informatie wordt niet getoond.
Schermlezers
Probleem: in TalkBack op Android 6 moet de link twee keer worden geactiveerd, voordat deze wordt gevolgd.
Als de link wordt voorgelezen, opent een eerste aanraking het venstertje met informatie. De volgende aanraking zou de link moeten volgen, maar in TalkBack op Android 6 zijn daar twee aanrakingen voor nodig. In TalkBack op Android 7 speelt dit niet meer.
Probleem: in VoiceOver op iPadOS 18.5 en 18.6 (en ook in 18.6.2) wordt het aankruisvakje voor browservensters smaller dan 760 px voorgelezen, alsof het zou werken.
In browservensters smaller dan 760 px kan het menu worden getoond en verborgen door het aan- of uitvinken van een aankruisvakje. Dit aankruisvakje wordt in vensters met een minimale breedte van 760 px verborgen met behulp van display: none;, Schermlezers zouden het hierdoor volledig moeten negeren.
VoiceOver op iPadOS 18.5 en 18.6 (en ook in 18.6.2) leest het aankruisvakje echter toch voor, en ook aan- en uitvinken kan, ondanks dat de geteste tablets breder dan 760 px zijn. Daardoor lijkt het aan- of uitvinken een functie te hebben, terwijl het in deze bredere browservensters geen enkel effect heeft.
In VoiceOver op een tablet met iOS 15.8.4 speelt dit probleem niet, dus het gaat vermoedelijk om een bug die vroeger of later (hopelijk) zal worden opgelost.
Of dit probleem ook speelt in eerdere versies dan iPadOS, is onduidelijk, want daar wordt niet op getest.
Overigens is dit ook geen wereldprobleem: er wordt alleen gemeld dat het aankruisvakje is aangevinkt of niet, en verder gebeurt er niets.
Probleem: in TalkBack op Android voor versie 7 en in iOS voor versie 13 werkt de skip-link niet.
Als een schermlezer de pagina voorleest, wordt eerst het menu voorgelezen. Dat kan behoorlijk irritant zijn, zeker als het menu wat langer is en op 'n (groot) aantal pagina's bovenaan de pagina staat. Daarom is voor het menu een skip-link neergezet, waarmee het menu in één keer gepasseerd kan worden.
Deze skip-link is normaal genomen onzichtbaar, maar dat zou voor schermlezers geen probleem horen te zijn.
In TalkBack, de schermlezer van Android, werkt zo'n link echter pas in Android versie 7 en later.
In VoiceOver op iOS voor versie 13 werkt een link binnen de pagina gewoon helemaal nooit. De link wordt wel netjes voorgelezen door VoiceOver, maar vervolgens gaat het voorlezen gewoon op dezelfde plaats verder. In iOS 13 en iPadOS 13 en later is dit eindelijk opgelost.
Zoomen en andere lettergrootte
Geen problemen.
Overige problemen
Probleem: of een link is bezocht of niet, wordt alleen met een andere kleur aangegeven.
Als een link is bezocht, krijgt deze aan de onderkant een groene balk. Nog niet bezochte links hebben een rode balk. Omdat bezocht of niet bezocht alleen met een andere kleur wordt aangegeven, kan dit problemen opleveren voor mensen die moeite hebben met het onderscheiden van kleuren.
Hier is helaas niets aan te doen. Omdat websites aan de hand van css-eigenschappen konden zien, welke sites iemand had bezocht, kunnen nog maar heel weinig eigenschappen worden veranderd bij een bezochte link. Daardoor kan alleen de kleur van het balkje worden veranderd, maar niet de stijl of de dikte. Ook andere eigenschappen die naast het verschil in kleur ook een verschil in vorm zouden weergeven, kunnen helaas niet worden gebruikt.
Ook de doorzichtigheid kan niet worden veranderd. Als dat wel zou kunnen, zou je de link als die nog niet is bezocht een doorzichtige balk kunnen geven en die balk pas kleuren, als de link is bezocht.
Probleem: de validator van w3c meldt een fout bij de <input>.
Als de css wordt gevalideerd, meldt de validator dat bij <input> het verplichte WAI-ARIA-attribuut role mist. Dit is echter niet meer nodig. De validator loopt soms wat achter, dus deze melding kan gewoon worden genegeerd.
Wijzigingen
Alleen grotere wijzigingen worden hier vermeld, geen dingen als een link die is geüpdatet.
:
Nieuw opgenomen.
10 augustus 2008:
Bij Bekende problemen (en oplossingen) stukje over verdwijnende letters bij vergroten lettergrootte toegevoegd.
4 oktober 2008:
Bij Bekende problemen (en oplossingen) tekst over Internet Explorer 7 en zoomen toegevoegd.
6 april 2009:
Tekst aangepast aan de nieuw verschenen Internet Explorer 8. De code is hetzelfde gebleven.
16 juli 2013:
De code en de tekst zijn volledig herschreven. Daarom is er geen beginnen aan alle wijzigingen hier te noteren. Een samenvatting:
- Alles voor Internet Explorer 6 en 7 is verwijderd.
- Werkt nu ook op aanraakschermen.
- Voor browservensters smaller dan 760 px is een compleet nieuw deel toegevoegd. Het menu verschijnt hier pas na klikken op of aanraken van de tekst 'Menu open'. Het sluit weer na klikken op of aanraken van 'Menu dicht'.
26 september juni 2025:
Volledig herschreven. De belangrijkste wijzigingen:
- Alle aanpassingen voor Opera, Internet Explorer en webkit (Safari en alle browsers op iOS en iPadOS) weggehaald.
- Alle voorvoegsels als
-webkit-bij css-eigenschappen weggehaald. Deze zijn niet meer nodig. - De tekst in de <a>'s is nu gewone tekst, de informatie in de venstertjes ook. (In eerdere versies werden hier
::afteren::beforevoor gebruikt.) - De links staan nu altijd gewoon binnen het browservenster (in eerdere versies stonden ze pas na hoveren binnen het venster).
- De kleuren rood (bezochte link) en groen (nog niet bezochte link) in de balkjes onder een link omgewisseld, omdat dat eigenlijk veel logischer is: groen geeft nu een bezochte link aan, rood een nog niet bezochte.
-
De hele constructie met links die eerst buiten het browservenster staan (en dus niet aangeklikt kunnen worden) en pas later binnen het venster worden geplaatst, is vervangen door
pointer-events. Bij openen van de pagina worden alle links doorpointer-events: none;uitgeschakeld. Door aanraken van of hoveren over de <li>, waar de <li> in zit, of als de <a> de focus heeft, wordt dit veranderd inpointer-events: auto;.Hierdoor werkt bij hoveren met een muis of touchpad over een <li> de daarin zittende link gelijk (of eigenlijk: de link gaat zo snel werken dat je niet merkt dat die eerst niet werkte). Bij gebruik van de Tab-toets krijgt de <a> de focus en werkt de link ook gelijk. (In eerdere versies had de Tab-toets helemaal geen effect.) Op een aanraakscherm opent de eerste aanraking het venstertje met informatie, de tweede aanraking volgt de link. Schermlezers lezen de link voor en daarna, soms na een korte pauze, de informatie, en kunnen de link gelijk volgen.
- Door al deze veranderingen waren de sluitkruisjes, waarmee op een aanraakscherm de venstertjes met informatie weer konden worden gesloten, niet meer nodig.
- In browservensters smaller dan 760 px kan het venstertje met informatie nu ook worden getoond.
- In browservensters smaller dan 760 px kan het menu worden getoond en verborgen door het aan- en uitvinken van een <input type="checkbox">. Voor schermlezers is daar aria-expanded aan toegevoegd.
- In browservensters smaller dan 760 px kan het menu nu ook met Escape worden gesloten.
- In browservensters smaller dan 760 px kan het menu nu ook met de Spatiebalk worden getoond en verborgen.
- Het voor schermlezers bedoelde
speak: none;weggehaald. Dit wordt inmiddels niet meer gebruikt (en is trouwens nooit ondersteund). titlebij alle links verwijderd. Deze waren bedoeld voor schermlezers, maar leiden alleen maar tot dubbel voorlezen van de tekst in de link.- Aan de link voor de huidige pagina voor schermlezers aria-current toegevoegd. Aan de andere zeven links aria-describedby toegevoegd met een koppeling naar de bijbehorende <span> met het venstertje, en aan de <span> role="tooltip".
- Gelijk onder de <nav> voor schermlezers een <h2> toegevoegd.
- Voor het menu met de acht knoppen voor schermlezers en gebruikers van de Tab-toets een skip-link toegevoegd.
- De knop voor de huidige pagina heeft nu bij focus een rode streep door de tekst in de knop.
- Om de toegankelijkheid te verbeteren wat JavaScript toegevoegd. Ook zonder JavaScript werkt het nog, alleen is het dan lastiger voor gebruikers van schermlezers en Tab-toets.
- Zonder css wordt de informatie uit het venstertje nu gelijk achter de link getoond. (In eerdere versies was die informatie zonder css niet te zien.)
- Aantal nieuwe hoofdstukken, vooral over toegankelijkheid.
- Tig kleinere veranderingen.
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 min of meer 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.
menu-012-dl.html: de pagina Home met het voorbeeld.
menu-012.pdf: deze uitleg (aangepast aan de inhoud van de download).
menu-012-inhoud-download-en-licenties.txt: een kopie van de tekst onder dit kopje (Inhoud van de download en licenties).
012-css-dl:
menu-012-dl.css: stijlbestand voor de acht html-pagina's met de menu's.
012-files-dl
de pagina's 1 tot en met 7 met het voorbeeld.
012-js:
menu-012.js: javascript om de toegankelijkheid te verbeteren.
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 tabindex="-1">
Het attribuut 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.
tabindex="-1" is nodig om op tablets met iOS en iPadOS het venstertje met informatie weer te kunnen verbergen. Meer hierover bij tabindex="-1".
<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 (ä 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 de regel 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 deze 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 deze 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 wordt in vensters smaller dan 760 px het menu alleen op verzoek getoond.
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.
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. Als een iPad in portretstand bijvoorbeeld 768 px breed is, wordt de pagina ook 768 px breed.
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.
<link rel="stylesheet" href="012-css-dl/menu-012-dl.css">
Dit is een koppeling naar een extern stijlbestand, waarin de css staat. In html5 is de toevoeging type="text/css" niet meer nodig, omdat dit standaard al zo staat ingesteld. Je moet uiteraard de naam van en het pad naar het stijlbestand aanpassen aan de naam en plaats, waar je eigen stijlbestand staat.
Voordeel van een extern stijlbestand is onder andere dat deze geldig is voor alle pagina's, waaraan deze is gelinkt. 'n Verandering in de lay-out hoef je dan maar in één enkel stijlbestand aan te brengen, in plaats van in elke pagina apart. Op een grotere site kan dit ontzettend veel werk schelen. Bovendien hoeft de browser zo'n extern stijlbestand maar één keer te downloaden, ongeacht hoeveel pagina's er gebruik van maken. Zou je de css in elke pagina opnieuw aanbrengen, dan worden de te downloaden bestanden veel groter.
<a id="skippy" href="#inhoud">Skip menu</a>
Sommige mensen gebruiken niet de muis, maar de Tab-toets om links, tekstvelden, en dergelijke af te lopen. Dat kan zijn vanwege een handicap, maar soms is het gewoon ook veel sneller dan de muis, bijvoorbeeld in formulieren.
In browservensters minimaal 760 px breed is het menu met de acht links altijd geopend. Als bovenaan elke pagina datzelfde menu staat, moet de gebruiker eerst door al die links heen. Voor elke link moet één keer de Tab-toets worden ingedrukt. Dat kan knap gaan irriteren, als je bovenaan elke pagina steeds dezelfde acht links tegenkomt. Daarom is bovenaan de pagina een zogenaamde skip-link geplaatst.
Omdat het een gewone link is, wordt deze bij gebruik van de Tab-toets bezocht, krijgt focus. Als de gebruiker dan op Enter drukt, wordt de link gevolgd. In dit geval is het een link naar het begin van de echte inhoud van de pagina bij <main>. Op deze manier kan in één keer een heel menu worden gepasseerd.
Normaal genomen is de skip-link onzichtbaar. Zodra de link focus heeft, wordt deze met behulp van css zichtbaar gemaakt. Als de Tab-toets nogmaals wordt ingedrukt, of als de link wordt gevolgd, verliest de skip-link weer focus en verdwijnt weer van het scherm. Hierdoor verpest de skip-link niet de hele lay-out.
Als mensen de Tab-toets niet gebruiken, krijgen ze de skip-link helemaal niet te zien.
In alle op iets nieuwere besturingssystemen werkt deze link ook. Maar schermlezers hebben ook andere manieren om een serie links te passeren. (Meer over waar de skip-link niet werkt is te vinden bij Probleem: in TalkBack ...)
<li><a href="#" aria-current="page">Home</a></li>
Deze link hoort bij de link naar de huidige pagina. De link hier is de link, zoals die er op de pagina Home uitziet. Met behulp van css wordt het uiterlijk van deze link aangepast. Schermlezers hebben niets aan zo'n aanpassing, daarom wordt voor schermlezers aan de link naar de huidige pagina aria-current toegevoegd.
<li tabindex="-1">
Een <li> kan normaal genomen niet de focus krijgen. Maar dat is hier wel nodig, omdat op aanraakschermen een aantal dingen wordt geregeld met behulp van li:focus-within. Door aan de <li> het attribuut tabindex="-1" te geven, kan de <li> op een aanraakscherm bij aanraking toch de focus krijgen.
<a href="012-files-dl/menu-012-1-dl.html" aria-describedby="tt-1">Pagina 1<span></span></a>
Dit is een van de zeven links, die niet bij de huidige pagina hoort. Dit is de link naar Pagina 1. Deze zeven links zijn allemaal hetzelfde, alleen verschilt de href en de tekst in de link iets.
aria-describedby is een verwijzing voor schermlezers naar de bijbehorende span#tt-1 met informatie.
De <span> binnen de <a> wordt gebruikt om een groene of rode streep onder de link te zetten, afhankelijk van of deze al is bezocht of niet.
De tussen 'Pagina' en '1' is een harde spatie (in het Engels 'non-breaking space'). Deze voorkomt dat bij een grotere letter de '1' op de volgende regel komt te staan, onder 'Pagina'.
<span id="tt-1" role="tooltip" aria-hidden="true">Ruimte voor informatie over de inhoud van pagina 1</span>
Deze <span> zorgt voor het venstertje met informatie.
role="tooltip" maakt aan schermlezers duidelijk, dat het hier om aanvullende informatie gaat. Bij de <a> gelijk hierboven is met behulp van aria-describedby een koppeling naar deze <span> aangebracht.
aria-hidden voorkomt dat de tekst in de <span> door schermlezers twee keer wordt voorgelezen.
<main id="inhoud" tabindex="-1">
Een <main> kan normaal genomen niet de focus krijgen. Door aan de <main> het attribuut tabindex="-1" te geven, kan <main> bij een aanraking of met behulp van wat JavaScript toch de focus krijgen. Hierdoor kan in browservensters smaller dan 760 px gelijk naar de eigenlijke inhoud van de pagina worden gegaan, als het menu wordt gesloten.
<script src="012-js/menu-012.js"></script>
Dit is een koppeling naar een klein beetje JavaScript. Ook zonder JavaScript werkt dit voorbeeld, maar het werkt dan (veel) lastiger voor gebruikers van schermlezers of Tab-toets.
Het script past wat elementen op de pagina aan. Om dat te kunnen doen, moeten die elementen eerst zijn geladen. Daarom staat het script helemaal onderaan de pagina, gelijk boven <body>.
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.)
Omdat deze site nou eenmaal (voornamelijk) op css is gericht, wordt hieronder álle css besproken.
Technisch gezien is er geen enkel bezwaar om de css in het stijlbestand 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, krijg je gegarandeerd 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 het stijlbestand 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 stijlbestanden, maar dat heeft een simpele reden: deze uitleg is in feite één groot commentaar.
Op internet zelf is het goed, als het stijlbestand 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 het stijlbestand uploaden. Inspringingen bijvoorbeeld zijn voor mensen handig, een computer heeft ze niet nodig.
Je hebt dan eigenlijk twee stijlbestanden. De uitgebreide versie waarin je dingen uitprobeert, verandert, enzovoort, met commentaar, inspringingen, en dergelijke. Dat is de mensvriendelijke versie. Daarnaast is er dan een stijlbestand dat 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 en verbeteren, gzip, CLS, comprimeren (inclusief theorie), en dergelijke links naar sites vinden, waar je bestanden kunt comprimeren.
(Stijlbestanden op deze site zijn niet gecomprimeerd. Omdat het vaak juist om de css gaat, kunnen mensen dan zonder al te veel moeite de css bekijken.)
css voor alle apparaten en vensters
/* menu-012-dl.css */
Om vergissingen te voorkomen is het een goede gewoonte bovenaan het stijlbestand even de naam neer te zetten. Voor je het weet, zit je anders in het verkeerde bestand te werken.
body
Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.
background: #ff9;
Achtergrondkleurtje.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond‑ en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important heeft gebruikt in een eigen stijlbestand, is er nog niets aan de hand, want dan veranderen achtergrond‑ en voorgrondkleur geen van beide.
font-family: Arial, Helvetica, sans-serif;
Als Arial is geïnstalleerd op de machine van de bezoeker, wordt deze gebruikt, anders Helvetica. Als die ook niet wordt gevonden, wordt in ieder geval een schreefloze letter (zonder dwarsstreepjes) gebruikt.
margin: 0;
Standaardmarge weghalen.
#h2-vb
Het element met id="h2-vb". Een voor schermlezers aangebrachte <h2>. Meer over het waarom van deze <h2> is te vinden bij <nav id="menu-vb" aria-labelledby="h2-vb">.
position: absolute;
Om de <h2> op een bepaalde 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 zo'n voorouder er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.
top: -100px; left: -20000px;
100 px boven en 20000 px links buiten het browservenster zetten. De <h2> wordt ook iets boven het venster gezet, omdat in sommige gevallen de werking van knoppen, links, en dergelijke wordt verstoord, als een element alleen links buiten het venster wordt neergezet.
#skippy
Het element met id="skippy". Een zogenaamde skip-link, waarmee in browservensters minimaal 760 px breed in één keer de acht knoppen met links gepasseerd kunnen worden.
display: none;
In browservensters smaller dan 760 px is deze skip-link niet nodig, omdat het menu eerst geopend moet worden, voordat de knoppen met de links zichtbaar zijn.
main
Alle <main>'s. Dat is er maar één: de belangrijkste inhoud van de pagina staat hierin. Hier is dat alleen een korte beschrijving van de werking van het menu.
background: white;
Witte achtergrond.
color: black;
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 stijlbestand, 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.
border: black solid 1px;
Zwart randje.
padding: 5px;
Kleine afstand tussen inhoud en buitenkant van de <main>.
h1
Alle <h1>'s. Dat is er maar één: de belangrijkste kop. Hier staat daar alleen maar in, welke pagina het is.
font-weight: normal;
Standaard is een <h> vet. Hier wordt dat veranderd in normale tekst.
text-align: center;
Tekst horizontaal centreren.
margin: 0;
Standaard heeft een <h1> een marge aan boven‑ en onderkant. Hier wordt die verwijderd.
h2
Alle <h2>'s.
font-size: 1.2em;
Lettergrootte.
Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
margin-bottom: 0;
Standaard heeft een <h2> een marge aan boven‑ en onderkant. Hier wordt de marge aan de onderkant weggehaald.
main p
Alle <p>'s in <main>.
margin-top: 0;
Standaard heeft een <p> een marge aan boven‑ en onderkant. Hier wordt de marge aan de bovenkant weggehaald.
css alleen voor vensters maximaal 759 px breed
@media screen and (max-width: 759px)
De css die binnen deze 'media query' staat, geldt alleen voor browservensters die maximaal 759 px breed zijn. In deze smallere vensters is het menu bij openen van de pagina verborgen. Pas nat het aanvinken van een <input>, wordt het getoond.
@media: geeft aan dat het om css gaat die alleen van toepassing is, als aan bepaalde voorwaarden wordt voldaan. Al langer bestond de mogelijkheid om met behulp van zo'n @media-regel css voor bijvoorbeeld printers op te geven. css3 heeft dat uitgebreid tot veel meer eigenschappen, zoals de breedte en hoogte van het venster van de browser.
screen: deze regel geldt alleen voor schermweergave.
and: er komt nog een voorwaarde, waaraan moet worden voldaan.
(max-width: 759px): het venster van de browser mag maximaal 759px breed zijn. Is het venster breder, dan wordt de css die binnen deze media query staat genegeerd.
Gelijk na deze regel komt een { te staan, en aan het einde van de css die binnen deze query valt een bijbehorende afsluitende }. Die zijn in de regel hierboven weggevallen, maar het geheel ziet er zo uit:
@media screen and (max-width: 759px) {
body {color: silver;}
(...) rest van de css voor deze media query (...)
footer {color: gold;}
}
Voor de eerste css binnen deze media query staat dus een extra {, en aan het eind staat een extra }.
Als je nou 'n mobieltje hebt met een resolutie van – om maar wat te noemen – 1024 x 768 px, dan geldt deze media query mogelijk toch voor dat mobieltje. Terwijl dat toch echt meer dan 759 px breed is.
Mobiele apparaten, maar ook steeds meer gewone beeldschermen, hebben een hogere resolutiedichtheid. Dat wil zeggen dat ze kleinere pixels hebben, die dichter bij elkaar staan. Daardoor zijn foto's, tekst, en dergelijke veel scherper weer te geven. Hoe kleiner de puntjes (de pixels) zijn, waaruit een afbeelding is opgebouwd, hoe duidelijker het wordt.
Er ontstaat alleen één probleem: als je de pixels twee keer zo klein maakt, wordt ook wat je ziet twee keer zo klein. En inmiddels zijn er al apparaten met pixels die meer dan vier keer zo klein zijn. Een lijntje van 1 px breed zou op die apparaten minder dan 'n kwart van de oorspronkelijke breedte krijgen en vrijwel onzichtbaar zijn. Een normale foto zou in een thumbnail veranderen. Kolommen zouden heel smal worden. Tekst zou onleesbaar klein worden. Allemaal fantastisch scherp, maar je hebt 'n vergrootglas nodig om 't te kunnen zien.
Om dit te voorkomen wordt een verschil gemaakt tussen css-pixels en schermpixels (in het Engels 'device-pixels'). De css-pixels zijn gebaseerd op de – tot voor kort – normale beeldschermen van de desktop. 1 css-pixel is op zo'n beeldscherm 1 pixel. Het aantal schermpixels is het werkelijk op het apparaat aanwezige aantal pixels (dat is het aantal pixels, waarvoor je hebt betaald).
Dat eerder genoemde mobieltje van 1024 x 768 px heeft wel degelijk meer dan 760 px in de breedte. Maar die zitten dichter bij elkaar. Op een gewoon beeldscherm zitten 96 pixels per inch, wat wordt uitgedrukt met de eenheid ppi ('pixels per inch'). (Vaak wordt foutief de eenheid dpi ('dots per inch') gebruikt. Die eenheid is voor printers.) Als dat mobieltje een resolutie van 192 ppi heeft, 192 pixels per inch, zijn de pixels ervan twee keer zo klein als op een origineel beeldscherm. Er zijn per inch twee keer zoveel schermpixels aanwezig.
Om nu te voorkomen dat alles op dat mobieltje twee keer zo klein wordt, geeft het mobieltje niet het echte aantal schermpixels (1024 x 768), maar een lager aantal css-pixels door bij een media query. De 192 ppi van het mobieltje is twee keer zo veel als de 96 ppi van een normaal beeldscherm. Het aantal css-pixels is dan het aantal schermpixels gedeeld door 2. 1024 x 768 gedeeld door 2 is 512 x 384 px. Het aantal css-pixels is 512 x 384 px en zit daarmee dus ruim onder de 760 px van deze media query.
Door deze truc is een lijn van 1 px breed op een normaal beeldscherm ook op het mobieltje nog steeds 1 px breed, alleen wordt die ene (css‑)pixel opgebouwd uit twee schermpixels (feitelijk vier, want het verhaal geldt voor breedte én hoogte). De dikte van het lijntje is hetzelfde, maar het is veel fijner opgebouwd. Bij lijntjes is dat verschil bijvoorbeeld in bochten goed te zien.
Hetzelfde verhaal geldt voor hogere resoluties, Een tablet met een breedte van 4096 schermpixels en een ppi van 384 (vier keer de originele dichtheid) geeft 4096 gedeeld door 4 = 1024 css-pixel door. Het lijntje van 1 px breedte op de originele monitor is nog steeds 1 css-pixel breed op de tablet, maar die ene css-pixel is nu opgebouwd uit zestien schermpixels.
Kort samengevat: omdat niet het aantal schermpixels (waarvoor je hebt betaald), maar het aantal css-pixels (de door de ontwerper bedoelde afmeting) wordt doorgegeven, wordt voorkomen dat een hogeresolutiescherm onleesbaar klein wordt.
Binnen deze media query wordt het tonen en verbergen van het menu in browservensters smaller dan 760 px geregeld. Hier wordt :hover niet gebruikt, dus dit levert geen problemen op een aanraakscherm op. Daarom kan de css voor het openen en sluiten van het menu veel simpeler zijn dan de css voor binnen het menu zelf, die ook het tonen en verbergen van het venstertje met informatie moet regelen.
css alleen voor apparaten met een precieze aanwijzer, zoals een muis
@media (hover: hover) and (pointer: fine)
De css die binnen deze 'media query' staat, is alleen bedoeld voor apparaten die worden bediend met een muis, een touchpad of een soortgelijke nauwkeurige aanwijzer.
De bedoeling is dat het venstertje met informatie gelijk opent, als je met een muis over een van de knoppen hovert. Omdat hoveren in het verleden (en nog wel) werd gebruikt om bijvoorbeeld een menu te openen, wordt hoveren op een aanraakscherm geïmiteerd.
Vaak is dat prima, maar hier niet. Als hoveren op een aanraakscherm zou werken, zou het venstertje met informatie bij aanraken van een knop worden geopend. Maar omdat je tegelijkertijd ook de in de knop zittende <a> aanraakt, wordt ook gelijk de link gevolgd. Daardoor zie je, afhankelijk van browser en besturingssysteem, het venstertje met informatie helemaal niet of alleen in een heel korte flits.
Deze query probeert te voorkomen dat op een aanraakscherm bij het aanraken van een knop bij de eerste aanraking gelijk de link wordt gevolgd, maar dat in plaats daarvan het venstertje met informatie wordt geopend.
Als op een apparaat gehoverd kan worden én de invoermethode is precies, dan zal dat (vrijwel) altijd een desktopcomputer of een laptop zijn. Alleen in dat geval wordt de css binnen deze media query uitgevoerd.
Deze methode is echter niet helemaal waterdicht. Als bijvoorbeeld een muis wordt aangesloten op een tablet, zul je in de regel twee keer moeten klikken: bij de eerste klik wordt het venstertje met informatie getoond, bij de tweede klik wordt de link gevolgd, net als bij een aanraking. Alles werkt dus, zoals het zou moeten werken.
Op een laptop met een aanraakscherm echter zal een aanraking in de regel hetzelfde werken als een klik met een muis: de link wordt gelijk gevolgd en het venstertje met informatie wordt niet of alleen in een flits getoond. Daarom is deze constructie niet geschikt, als in het venstertje met informatie belangrijke informatie staat.
@media: geeft aan dat het om css gaat die alleen van toepassing is, als aan bepaalde voorwaarden wordt voldaan. Al langer bestond de mogelijkheid om met behulp van zo'n @media-regel css voor bijvoorbeeld printers op te geven. css3 heeft dat uitgebreid tot veel meer eigenschappen, zoals of er wel of niet gehoverd kan worden, en of de invoermethode ruw of precies is.
(hover: hover): het 'primaire invoermechanisme' (in het Engels 'primary input mechanism') kan hoveren. Met een muis of touchpad kun je boven iets gaan hangen, waardoor bijvoorbeeld de kleur van iets kan veranderen. Op een aanraakscherm kan dat niet. Weliswaar wordt hoveren vaak geïmiteerd, maar dat is geen echt hoveren zoals met een muis. Ook als je een muis aansluit op een tablet of smartphone is het primaire invoermechanisme niet de muis, maar nog steeds het aanraakscherm.
(hover: hover) staat tussen haakjes, dat hoort gewoon zo bij een @media-regel.
and: er komt nog een voorwaarde.
(pointer: fine): het primaire invoermechanisme moet 'precies' (in het Engels 'fine') zijn. Dat zijn bijvoorbeeld een muis en een touchpad, omdat je met beide heel precies kunt richten.
De andere twee waarden zijn 'none' (geen invoermechanisme) en 'coarse' (een grof invoermechanisme zoals een vinger). Dat geldt niet alleen voor bouwvakkersklauwen, maar ook voor die schattige peutervingertjes: met een muis en dergelijke kun je gewoon veel beter richten.
Ook deze voorwaarde staat weer tussen haakjes.
Gelijk na deze regel komt een { te staan, en aan het einde van de css die binnen deze media query valt een bijbehorende afsluitende }. Die zijn in de regel hierboven weggevallen, maar het geheel ziet er zo uit:
@media (hover: hover) and (pointer: fine) {
body {color: silver;}
(...) rest van de css voor deze media-regel (...)
footer {color: gold;}
}
Voor de eerste css binnen deze media query staat dus een extra {, en aan het eind staat een extra }.
css alleen voor vensters minimaal 760 px breed
@media screen and (min-width: 760px)
De opbouw van deze regel staat beschreven bij @media screen and (max-width: 759px). Er is één verschil: de breedte van het browservenster moet minimaal 760 px zijn.
In browservensters minimaal 760 px breed is voldoende ruimte om de acht knoppen van het menu altijd te tonen. Daarom is de css voor deze bredere vensters gedeeltelijk anders.
Omdat het menu hier altijd is geopend, zou je bij elke pagina alle acht links moeten passeren, voordat je bij de belangrijkste inhoud van de pagina komt. Heel irritant voor gebruikers van de Tab-toets en schermlezers. Daarom staat voor het menu een skip-link, waarmee het menu in één keer gepasseerd kan worden.
body
Deze selector werkt alleen in browservensters minimaal 760 px breed. Voor andere vensters is de uitleg hieronder niet van belang.
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
body {background: #ff9; color: black; font-family: Arial, Helvetica, sans-serif; margin: 0;}
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.
font-size: 110%;
Iets groter dan standaard in deze grotere browservensters. 't Zal de leeftijd zijn, maar de standaardgrootte is wat 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.
#skippy
Deze selector werkt alleen in browservensters minimaal 760 px breed. Voor andere vensters is de uitleg hieronder niet van belang.
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
#skippy {display: none;}
Het element met id="skippy". Een zogenaamde skip-link, waarmee in browservensters minimaal 760 px breed in één keer de acht knoppen met links gepasseerd kunnen worden.
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 stijlbestand, 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.
Normaal genomen zou je de kleur van de tekst in een link door de browser laten bepalen, zodat te zien is of de link al is bezocht of niet. (Of je moet dat op een andere manier aangeven, zoals in dit voorbeeld gebeurt bij de acht knoppen met links.)
Hier maakt die kleur niets uit, omdat het niet uitmaakt of een skip-link als is bezocht of niet. Bovendien is het belangrijk dat de kleur van de tekst voldoende contrast heeft met de achtergrondkleur. Bij wit op blauw is dat het geval.
clip: rect(1px, 1px, 1px, 1px); clip-path: inset(50%);
Deze twee eigenschappen doen hetzelfde. De eerste eigenschap clip is voor oudere browsers, de tweede eigenschap clip-path is voor nieuwere. (Deze nieuwere eigenschap heeft veel meer mogelijkheden, maar die worden hier niet gebruikt.)
Oudere browsers kennen clip-path niet en negeren de tweede eigenschap. Nieuwere browsers kennen clip-path wel en omdat clip-path na clip in de css staat, 'wint' clip-path van clip en wordt clip-path gebruikt.
Gelijk hieronder krijgt de skip-link een breedte en hoogte van 1 px en aan alle kanten een border van 3 px breed. Daardoor zou de skip-link nog steeds zichtbaar zijn als een vierkant rood blokje met, als je heel goed kijkt, een wit blokje in het midden van 1 px breed en hoog. Deze twee eigenschappen verbergen ook dat laatste restje skip-link.
clip: rect(1px, 1px, 1px, 1px): geef het element weer binnen de vier opgegeven grenzen. De vier waarden horen bij bovenkant, rechterkant, onderkant en linkerkant.
Bovenkant en onderkant worden vanaf de bovenkant gerekend: geef het element weer vanaf 1 px vanaf de bovenkant tot aan 1 px vanaf de bovenkant. Oftewel: helemaal niets.
Linker- en rechterkant worden vanaf links gerekend: geef het element weer vanaf 1 px vanaf de linkerkant tot aan 1 px vanaf de linkerkant. Wat ook weer als resultaat helemaal niets oplevert.
clip-path: inset(50%): omdat maar één waarde is opgegeven, geldt deze voor boven, rechts, onder en links. Geef het element weer vanaf 50% van alle vier de kanten. Als je dat doet, blijft er helemaal niets over om weer te geven.
De skip-link is nu volledig onzichtbaar, maar nog wel bereikbaar voor schermlezers en Tab-toets.
display: block;
Eerder is de skip-link met display: none; verborgen, omdat deze in browservensters smaller dan 760 px niet nodig is. Hier wordt de link weer zichtbaar gemaakt.
width: 1px; height: 1px; overflow: hidden;
Breedte en hoogte minimaal maken.
Als de inhoud van een element er niet in past, zoals hier het geval is, wordt die inhoud normaal genomen toch getoond. In het algemeen is dat prima: beter 'n wat minder mooie lay-out dan dat er tekst of zo verdwijnt.
Hier moet de skip-link pas zichtbaar worden als deze de focus heeft, daarom wordt hier wat niet in de breedte en hoogte past met overflow: hidden; verborgen.
Breedte en hoogte 0 px maken is geen goed idee, omdat de link dan niet meer werkt in alle schermlezers en browsers.
font-size: 1.2em;
Lettergrootte.
Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
line-height: 2.4em;
Regelhoogte. Deze is tamelijk groot, waardoor de skip-link meer opvalt.
Als eenheid wordt de relatieve eenheid em gebruikt, omdat bij gebruik van een absolute eenheid zoals px de regelhoogte niet mee verandert met de lettergrootte. Zoomen kan wel altijd, ongeacht welke eenheid voor de regelhoogte wordt gebruikt.
text-align: center;
Tekst horizontaal centreren.
border: red solid 3px;
Dikke rode rand, zodat de skip-link meer opvalt.
position: absolute;

Door de skip-link absoluut te positioneren, trekken andere elementen er zich niets van aan. Zonder absolute positie zou de skip-link de positie van andere elementen beïnvloeden.
Op de afbeelding links is de skip-link absoluut gepositioneerd en heeft geen invloed op de positie van de andere elementen.
Op de afbeelding in het midden is de skip-link niet absoluut gepositioneerd. Daardoor wordt de <nav> met de knoppen iets omlaag gedrukt. Niet veel, want de skip-link is heel klein.
Op de afbeelding rechts heeft de skip-link de focus en is daardoor een stuk groter. Nu wordt het hele menu echt 'n heel stuk naar onderen gedrukt.
Door de skip-link absoluut te positioneren, blijft het menu met de knoppen altijd op dezelfde plaats staan, of de skip-link nu de focus heeft of niet.
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 zo'n voorouder er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.
Een <a> is van zichzelf een inline-element, waardoor eigenschappen als breedte en hoogte niet gebruikt kunnen worden. Door de <a> absoluut te positioneren verandert deze in een soort blok-element, waardoor dit soort eigenschappen wel is te gebruiken.
z-index: 250;
Normaal genomen worden elementen in de volgorde van de html op het scherm gezet. Wat later in de html staat, wordt over eerdere elementen gezet. Om te zorgen dat de skip-link altijd bovenaan staat, krijgt deze een hogere z-index.
Een z-index werkt alleen in bepaalde omstandigheden. Eén van die omstandigheden is een absolute positie. Die is iets hierboven aan de skip-link gegeven, dus dat is geregeld.
#skippy:focus
Deze selector werkt alleen in browservensters minimaal 760 px breed. Voor andere vensters is de uitleg hieronder niet van belang.
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in het stijlbestand staat, zodat alles hier overzichtelijk bij elkaar staat.
#skippy {background: white; color: black; clip: rect(1px, 1px, 1px, 1px); clip-path: inset(50%); width: 1px; height: 1px; overflow: hidden; font-size: 1.2em; line-height: 2.4em; text-align: center; margin: -1px; border: red solid 3px; padding: 0; position: absolute; top: 0; left: 0; z-index: 250;}
Het element met id="skippy", maar alleen als dit element de focus heeft. De skip-link is hierboven bij #skippy onzichtbaar gemaakt. Daardoor kan deze alleen met de Tab-toets (en door schermlezers) worden bereikt. Precies de bedoeling, want bij gebruik van een muis of aanraakscherm is de skip-link overbodig.
clip: auto; clip-path: none;
Eerder is de skip-link met clip: rect(1px, 1px, 1px, 1px); en clip-path: inset(50%); onzichtbaar gemaakt. Hier worden de standaardwaarden voor deze eigenschappen opgegeven, waardoor de skip-link zichtbaar wordt.
width: 10.5em; height: 4.8em;
Eerder heeft de skip-link een breedte en hoogte van 1 px gekregen. Dat leest mogelijk wat lastig. Daarom wordt hier een veel grotere breedte en hoogte opgegeven. Veel groter dan nodig is voor de tekst erin, zodat de skip-link goed opvalt en niet per ongeluk gepasseerd kan worden.
Als eenheid wordt de relatieve eenheid em gebruikt, zodat de breedte en hoogte mee veranderen met de lettergrootte. Bij gebruik van een absolute eenheid zoals px veranderen de breedte en hoogte niet mee met de lettergrootte. Zoomen kan wel altijd, ongeacht welke eenheid voor de breedte en hoogte wordt gebruikt.
main
Deze selector werkt alleen in browservensters minimaal 760 px breed. Voor andere vensters is de uitleg hieronder niet van belang.
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
main {background: white; color: black; border: black solid 1px; padding: 5px;}
Alle <main>'s. Dat is er maar één: de belangrijkste inhoud van de pagina staat hierin. Hier is dat alleen een korte beschrijving van de werking van het menu.
width: 45rem;
Een <main> is een blok-element en wordt daardoor standaard even breed als z'n ouder <body>. Body is ook een blok-element en wordt daardoor 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. Daardoor zou <main> in brede vensters heel breed worden, wat veel te lange, moeilijk leesbare regels oplevert. Hier wordt de breedte beperkt tot 45 rem.
Als eenheid wordt de relatieve eenheid rem gebruikt, omdat bij gebruik van een absolute eenheid zoals px de breedte niet mee verandert met de lettergrootte. Zoomen kan wel altijd, ongeacht welke eenheid wordt gebruikt.
De minder bekende rem is ongeveer hetzelfde als de em. Alleen is de lettergrootte bij rem gebaseerd op de lettergrootte van het <html>‑element, waardoor de rem overal op de pagina precies even groot is, ook als de bezoeker de lettergrootte heeft veranderd. Bij de em kan de lettergrootte worden beïnvloed door de voorouders van het element, bij de rem niet.
max-width: 96vw;
Maximumbreedte.
Hier gelijk boven is een breedte van 45 rem opgegeven. Als de letters sterk worden vergroot, zouden de regels hierdoor breder worden dan het venster van de browser, waardoor je voortduren horizontaal zou moeten scrollen. In sommige browsers op sommige systemen verschijnt hierbij een horizontale scrollbalk. Door de breedte een maximum te geven, wordt dit voorkomen.
De eenheid vw is gebaseerd op de breedte van het venster van de browser. 1 vw is 1% van de breedte van het venster, en 96 vw is 96% van de breedte. De <main> wordt hierdoor nooit breder dan 96% van de breedte van het venster, ongeacht de breedte van het venster.
margin: 0 auto;
Omdat voor onder en links geen waarden zijn opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 0 auto 0 auto in de volgorde boven – rechts – onder – links.
Boven en onder geen marge. Links en rechts auto, wat hier hetzelfde betekent als evenveel. Hierdoor komt <main> altijd horizontaal gecentreerd binnen ouder <body> te staan. <body> is een blok-element en wordt daardoor normaal genomen automatisch even breed als de ouder ervan: <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser.
Hierdoor staat uiteindelijk <main> altijd horizontaal gecentreerd binnen het venster van de browser, ongeacht de breedte van het venster. En daarmee ook de in <main> zittende tekst.
Deze manier van horizontaal centreren van een blok-element werkt alleen, als het blok-element een breedte heeft, want anders zou het normaal genomen even breed worden als de ouder ervan. Dat is geregeld, want iets hierboven heeft <main> een breedte van 45 rem en een maximumbreedte van 96 vw gekregen.
h1
Deze selector werkt alleen in browservensters minimaal 760 px breed. Voor andere vensters is de uitleg hieronder niet van belang.
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
h1 {font-weight: normal; text-align: center; margin: 0;}
Alle <h1>'s. Dat is er maar één: de belangrijkste kop. Hier staat daar alleen maar in , welke pagina het is.
margin-top: 20px;
Kleine afstand tussen de <h1> en de bovenkant van <main>.
css alleen voor apparaten met een precieze aanwijzer, zoals een muis, én met vensters minimaal 760 px breed
@media (hover: hover) and (pointer: fine)
De css die binnen deze 'media query' staat, is alleen bedoeld voor apparaten die worden bediend met een muis of een touchpad of een soortgelijke nauwkeurige aanwijzer. De beschrijving hiervan is te vinden bij media (hover: hover) and (pointer: fine).
Er is één verschil: deze @media query staat binnen een andere media query: media screen and (min-width: 760px). Daarom geldt hier als extra voorwaarde dat het browservenster minimaal 760 px breed moet zijn. De css binnen deze media query werkt dus alleen op apparaten die worden bediend met een muis of een touchpad of een soortgelijke nauwkeurige aanwijzer én alleen in vensters die minimaal 760 px breed zijn.
JavaScript
De code is geschreven in een afwijkende lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code) is in de hele uitleg onderstippeld blauw. (In dit voorbeeld is dat alleen JavaScript die nodig is voor toegankelijkheid.) Alle niet-essentiële code is bruin.
Bij de uitleg van deze code zijn allerlei haakjes en dergelijke grotendeels weggelaten, want dat voert hier te ver. Als je je in dat soort dingen wilt verdiepen, kun je beter naar sites gaan die meer voor JavaScript zijn bedoeld.
Zonder JavaScript werkt dit menu wel, maar is het lastiger toegankelijk voor schermlezers en met Toetsenbordnavigatie. Daarom wordt een groot deel van het JavaScript tot de essentiële code gerekend. Ook andere gebruikers kunnen er voordeel van hebben, maar dat is eigenlijk min of meer toeval.
Als je onderstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.
// menu-012.js(function () {
"use strict";if(window.innerWidth >= 760) return;const toonMenuVb = document.querySelector("#toon-menu-vb");toonMenuVb.addEventListener("click", function() {
this.setAttribute("aria-expanded", this.checked);
});document.querySelector("body").addEventListener("keyup", openSluitVb);
document.querySelector("body").addEventListener("click", openSluitVb);function openSluitVb(e) {
if (e.key === "Escape") {
toonMenuVb.checked = false;
toonMenuVb.setAttribute("aria-expanded", false);
if (e.target.parentElement.parentElement.id === "menu-ul-vb") {
toonMenuVb.focus();
} else {
document.querySelector("main").focus();
}
} else if (e.key ==="Enter" && e.target.id === "toon-menu-vb") {
toonMenuVb.checked = !toonMenuVb.checked;
toonMenuVb.setAttribute("aria-expanded", toonMenuVb.checked);
} else if (document.querySelector(#menu-vb").contains(e.target)) {
return;
} else {
toonMenuVb.checked = false;
toonMenuVb.setAttribute("aria-expanded", false);
}
}}) ();
Als je bovenstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.
Hieronder wordt de werking van dit script uitgelegd, maar dit is zeker geen cursus JavaScript. Daar is deze site niet voor bedoeld.
Als je deze uitleg gaat lezen, wordt dat heel lastig als je het script niet ernaast legt. Het is dan haast onmogelijk om te zien, waar een bepaald stuk code begint en eindigt. Het script staat hier gelijk boven, maar het is beter het als apart bestand te opene, zodat je niet steeds tussen uitleg en script heen en weer hoeft te vliegen. Het script is te vinden in de map 012-js.
Dit script wijzigt, in browservensters smaller dan 760 px, de html. Om dat te kunnen zien moet je niet de gewone broncode, maar de Gegenereerde code bekijken.
(function () {
function: het sleutelwoord waarmee het begin van een functie wordt aangegeven. Een functie is een stukje bij elkaar horende code. (Het haakje helemaal aan het begin wordt iets verderop beschreven.)
(): achter een functie moeten twee haakjes staan. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie, maar bij deze functie gebeurt dat niet.
{: geeft het begin van de code binnen de functie aan. Aan het eind van de functie, dat is in dit geval helemaal onderaan in de laatste regel van het script, staat een bijbehorende }.
In die laatste regel staat in dit geval nog meer dan alleen de } die het einde van de code aangeeft: }) ();
}: dit is de eerder genoemde afsluitende }, waarmee het einde van de code in de functie wordt aangegeven.
): dit afsluitende haakje is de tegenhanger van het haakje dat voor de functie staat. Samen zorgen ze ervoor dat de hele functie, met alles erop en eraan, tussen haakjes staat. De reden van deze haakjes wordt iets hieronder besproken.
(): dit is weer gewoon een taalregel van JavaScript. In dit geval moeten er achter de }) nog twee haakjes staan. Een computer is gewoon niet zo slim, anders weet de ziel niet wat er moet gebeuren.
;: de puntkomma geeft het einde van de regel aan. In gewone tekst zou je hier een punt gebruiken.
We hebben hier een script, waarin alle code binnen een functie is geplaatst. Alle code staat tussen { en }, zodat de computer het begin en einde van de functie kan herkennen.
Een functie is een stukje bij elkaar horende code dat je, zo vaak als je wilt, kunt uitvoeren. Als je de tafel van twaalf op het scherm wilt zetten, hoef je niet twaalf vermenigvuldigingen in JavaScript te schrijven, maar schrijf je 'n functie voor één vermenigvuldiging, die je vervolgens tien keer (op steeds iets andere wijze) uitvoert.
Een functie heeft echter één probleem: de code in de functie wordt pas uitgevoerd, als de functie wordt aangeroepen. Dat aanroepen kan op allerlei manieren gebeuren, bijvoorbeeld als de gebruiker 'n toets indrukt, als de pagina is geladen, als het 13:13 is op vrijdag de dertiende, noem maar op. Maar zonder te worden aangeroepen doet een functie helemaal niets.
In dit script is dat ook zo. Er zit bijvoorbeeld een functie in die reageert op het indrukken van een toets. Om die functie goed te laten werken, moet de computer eerst wat voorbereidend werk verrichten. Daarvoor moet het script worden gelezen. Maar dat hele script zit in een functie, en die functie doet dus pas wat, als die wordt aangeroepen.
Om te zorgen dat de buitenste functie, die waar alle code in zit, toch vanzelf wordt uitgevoerd, zet je er een ( voor. En helemaal aan het eind, achter de afsluitende }, zet je de tegenhanger ). Om te zorgen dat de functie echt vanzelf wordt uitgevoerd, moeten hierachter nog twee haakjes () worden gezet. Nu wordt de functie automatisch uitgevoerd, zonder dat deze hoeft te worden aangeroepen. En kan de code in het script worden gelezen, waardoor het benodigde voorbereidende werk kan worden uitgevoerd.
(Je kunt de code ook in een niet alles omvattende functie zetten. Dan wordt de code ook gelijk uitgevoerd. Maar dat brengt belangrijke risico's met zich mee. In dit script worden namen voor variabelen gebruikt als toonMenuVb. Als nou een ander JavaScript toevallig dezelfde namen zou gebruiken, gaat het gruwelijk mis. Door het hele script in een functie te stoppen, voorkom je dat. Als je hier meer over wilt weten, kun je op internet zoeken naar 'JavaScript name conflict' of 'JavaScript name clash'.)
"use strict";
Deze regel zorgt ervoor dat bepaalde slordigheden in de code, die makkelijk tot grote problemen kunnen leiden, niet meer mogen. Een validator (die controleert op fouten in de code) is nu strenger en keurt meer dingen af.
if(window.innerWidth >= 760) return;
Als het venster van de browser 760 px of meer breed is, wordt het script niet uitgevoerd. (In die vensters is de menubalk met de zes knoppen altijd zichtbaar.)
if: dat betekent gewoon 'als': als er aan de voorwaarde hierachter is voldaan. Die voorwaarde staat tussen haakjes, omdat dat nou eenmaal zo hoort. Het is het hele deel tussen de twee haakjes achter de if.
window: als een pagina wordt geopend, wordt allerlei informatie in de browser opgeslagen.
Die informatie kan door onder andere JavaScript gebruikt worden. De informatie is overzichtelijk opgeslagen in allerlei afdelingen en onderafdelingen, die in JavaScript 'object' heten.
Een van die objecten is het 'window' object. Daarin zit allerlei meer algemene informatie, die betrekking heeft op de pagina en op het browservenster. window geeft alleen maar aan, dat wat achter de punt staat te vinden is in het window-object.
innerWidth: zo'n stukje informatie is innerWidth: de breedte van het browservenster in px, inclusief een eventuele scrollbalk.
>=: meer dan of gelijk aan. Het =‑teken betekent 'is gelijk aan'. Het '>'‑teken wordt vaak gebruikt om groter dan aan te geven. De combinatie >= betekent daarom: meer dan of gelijk aan: wat links van deze twee tekens staat, moet meer zijn dan of gelijk zijn aan wat rechts van deze tekens staat.
760: gewoon een getal. De eenheid px wordt in JavaScript weggelaten, alleen de waarde is genoeg.
(window.innerWidth >= 760): als je het hele deel tussen de haakjes in gewone taal samenvat, staat hier: als de breedte van het venster van de browser 760 px of meer is. Als dat zo is, is aan de voorwaarde voldaan.
return;: de code die wordt uitgevoerd, als aan deze if-voorwaarde wordt voldaan.
Meestal wordt die code tussen accolades gezet (aan het begin van de code { en } aan het eind). Het script weet dan, wat bij deze if hoort.
Omdat het hier maar om heel weinig code gaat (één woord, om precies te zijn), staat alles op één regel. In dat geval mogen de accolades worden weggelaten.
De hier uit te voeren code is return: ga onmiddellijk terug naar waar je vandaan kwam en voer de rest van de code niet uit.
Omdat dit helemaal aan het begin van het script staat, betekent teruggaan in dit geval het hele script verlaten en daar verder helemaal niets van uitvoeren.
;: achter return staat nog een ;. Daarmee geef je in JavaScript het eind van een regel aan. Het is vergelijkbaar met een punt in gewone taal.
De hele regel in gewone taal: als het browservenster een breedte heeft van 760 px of meer, voer het script dan niet uit, maar ga terug naar waar je vandaan kwam: de pagina met html.
this.setAttribute("aria-expanded", this.checked);
Dit is de code die tussen de { gelijk achter function() en de } op de volgende regel staat, zodat het script weet, waar de bij de functie horende code begint en eindigt.
this: in deze context verwijst het sleutelwoord this naar het object, dat de functie aanriep. Dat is hier de in variabele toonMevuVb opgeslagen input#toon-menu-vb.
setAttribute(): hiermee kan een attribuut bij een element worden aangebracht of gewijzigd. Omdat het attribuut hier al in de html aanwezig is (het gaat om aria-expanded="false"), wordt het niet nieuw aangebracht, maar wordt eventueel de waarde gewijzigd.
Tussen de haakjes staat voor de komma de naam van het attribuut, achter de komma staat de waarde die het attribuut moet krijgen.
"aria-expanded": de naam van het attribuut. Hiermee wordt voor schermlezers aangegeven, of het bij de <input> horende menu is uitgevouwen en daarmee zichtbaar, of ingeklapt en daarmee onzichtbaar is.
this.checked:
this: dit verwijst weer naar het object dat de functie aanriep: input#toon-menu-vb.
checked: hierin is opgeslagen, of input#toon-menu-vb is aangevinkt of niet. Als de <input> is aangevinkt, heeft checked de waarde true. Als de <input> niet is aangevinkt, heeft checked de waarde false.
this.checked samen is dus altijd true of false.
;: De puntkomma geeft het eind van dit deel van de regel aan. In gewone tekst zou je hier een punt gebruiken.
De hele regel this.setAttribute("aria-expanded", this.checked); zorgt ervoor dat aria-expanded de waarde true of false krijgt, waardoor schermlezers kunnen melden of het menu zichtbaar is of niet.
Als de <input> niet is aangevinkt, is this.checked false en komt bij input#toon-menu-vb in de html aria-expanded="false" te staan. Als de <input> is aangevinkt, is this.checked true en komt bij input#toon-menu-vb in de html aria-expanded="true" te staan.
(Als je deze veranderingen wilt zien, moet je niet naar de gewone code, maar naar de Gegenereerde code kijken.)
});: dan zijn er nog de afsluitende accolade en het afsluitende haakje.
De afsluitende accolade is de tegenhanger van de { achter function() en geeft het einde van de bij function() horende code aan.
Het afsluitende haakje hoort bij het haakje gelijk achter addEventListener, want die was nog niet afgesloten.
De ; daarachter geeft het eind van de bij toonMenuVb.addEventlistener horende code aan.
(Om te bepalen welk haakje bij welk haakje hoort en dergelijke, hoeft je geen cursus helderziendheid te volgen. Elke goede editor geeft de bij elkaar horende haakjes, accolades, en dergelijke aan. Wat bepaald helpt bij het voorkomen van acute wanhoop bij dit soort haakjeskerstbomen.)
document.querySelector("body").addEventListener("keyup", openSluitVb);
document.querySelector("body"): het opzoeken van het element <body>.
Het middelste stukje querySelector is een zogenaamde 'functie'. Een functie is een stukje in de browser ingebakken code, waarmee je iets kunt doen. Deze functie is te vinden in het object document, vandaar dat document ervoor staat.
Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.
JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.
Met de methode querySelector() uit document kan JavaScript het eerste element opzoeken, dat aan een bepaalde voorwaarde voldoet, zoals het element met een bepaalde id, het eerste element met een bepaalde class, en dergelijke. Het gegeven waarnaar wordt gezocht, staat tussen aanhalingstekens tussen de haakjes:
querySelector("body")
Hierbij is de syntax van het deel tussen de aanhalingstekens precies hetzelfde als bij een selector in css. In bovenstaande regel wordt naar het element <body> gezocht. Net zoals je in css in een selector body {...} zou gebruiken.
addEventListener: er wordt een zogenaamde 'eventlistener' gekoppeld aan het voor de punt staande document.querySelector("body"), dus eigenlijk aan <body>.
Een eventlistener luistert naar een gebeurtenis. Die gebeurtenis, de 'event', kan van alles zijn: het indrukken van een toets, klikken, scrollen, de video is afgespeeld, van alles. Tussen de haakjes van addEventListener() staat, naar welke soort gebeurtenis moet worden geluisterd, en wat er moet gebeuren, als die gebeurtenis zich voordoet. Zeg maar 'n soort rampenplan: áls gebeurtenis is 'doodsmak', dán handeling is 'bel 112'.
"keyup": tussen aanhalingstekens, zodat het script weet dat dit een letterlijke naam is, een 'string' (dit is gewoon een van de taalkundige regels van JavaScript). Dit is de naam van de gebeurtenis, waarnaar wordt geluisterd, waarop wordt gewacht: 'keyup': als een toets weer wordt losgelaten, nadat deze is ingedrukt. Maakt niet uit welke toets. Deze regel roept de functie aan, die het eigenlijke werk gaat doen.
openSluitVb: deze naam staat niet tussen aanhalingstekens, omdat het hier niet om een letterlijke naam of zo, een 'string', gaat. De naam verwijst naar een 'functie', iets wat moet gebeuren. Die functie staat iets hieronder bij function openSluitVb(e) { en zorgt dat het openen en sluiten van het menu toegankelijker is voor gebruikers van schermlezers en Tab-toets.
;: de puntkomma geeft het einde van de regel aan. In gewone tekst zou je hier een punt gebruiken.
De hele regel in gewone taal: als een toets wordt ingedrukt en weer wordt losgelaten, maakt niet uit welke toets of waar, voer dan de functie 'openSluitVb' uit.
De eventlistener wordt hier aan <body> gekoppeld. Dat betekent dat de functie overal wordt aangeroepen, waar het scherm wordt aangeraakt of ‑geklikt. Je zou de eventlistener ook kunnen koppelen aan een deel van de pagina, maar dat is hier niet nodig: het maakt in dit geval niets uit, wanneer een toets wordt ingedrukt.
document.querySelector("body").addEventListener("click", openSluitVb);
Deze regel doet precies hetzelfde als die gelijk hierboven bij document.querySelector("body").addEventListener("keyup", openSluitVb); Het enige verschil: deze eventlistener luister naar een klik of, op een aanraakscherm, naar een aanraking.
function openSluitVb(e) {
Ook deze functie is, zoals elke functie, weer een stukje bij elkaar horende code. Maar anders dan de buitenste functie wordt deze niet automatisch uitgevoerd. (Waarom de buitenste functie wel automatisch wordt uitgevoerd, is te vinden bij (function () {.)
De code in deze functie wordt alleen uitgevoerd, als de functie wordt aangeroepen. Dat aanroepen gebeurt, als een toets wordt losgelaten, of als het browservenster ergens wordt aangeraakt of ‑geklikt. Het luisteren naar dat loslaten wordt geregeld bij document.querySelector("body").addEventListener("keyup", openSluitVb);, het luisteren naar het klikken of aanraken bij document.querySelector("body").addEventListener("click", openSluitVb);.
De code in deze functie zorgt ervoor dat het menu ook getoond en verborgen kan worden met Enter en Escape. Bovendien regelt deze functie mede dat het voor schermlezers belangrijke aria-expanded de juiste waarde krijgt.
* Als Escape wordt ingedrukt, wordt het menu verborgen.
Als Escape binnen het menu wordt ingedrukt, wordt de focus teruggezet op de <input>, waarmee het menu getoond en verborgen kan worden.
Als Escape buiten het menu wordt ingedrukt, wordt de focus op <main> gezet.
* Als de <input> waarmee het menu kan worden getoond en verborgen de focus heeft, kan het menu ook met de Enter-toets worden getoond of verborgen. (Normaal genomen heeft een Enter-toets geen effect op een <input>.)
* Als het browservenster buiten het menu wordt aangeraakt of ‑geklikt, wordt het menu verborgen.
function: het sleutelwoord waarmee het begin van een functie wordt aangegeven.
openSluitVb: de naam van de functie. Als het beestje geen naam heeft, kun je het ook niet aanroepen en heb je er dus niets aan. (Dit klopt niet helemaal. JavaScript kent ook equivalenten van 'hé!', 'hé, jij daar!', 'hé, jij daar in die zwarte jas', en dergelijke, maar die worden hier niet gebruikt. En het is zo al ingewikkeld genoeg.)
Het is bij namen in JavaScript gebruikelijk om nieuwe woorden met een hoofdletter te beginnen, omdat spaties, koppeltekens, en dergelijke niet gebruikt mogen worden in een naam. In css zou je hier bijvoorbeeld open-sluit-vb kunnen gebruiken in plaats van openSluitVb.
(e): die haakjes horen nou eenmaal zo na het sleutelwoord function. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie. Zoals de plaats waar het scherm is aangeraakt of ‑geklikt. In dit geval wordt e doorgegeven.
e is een zogenaamd object. In een object zitten allerlei gegevens over hoe de functie is aangeroepen (over dat aanroepen later meer). In dit geval wordt deze functie aangeroepen door het indrukken van een toets, of door het aanraken of ‑klikken van het scherm. In e zit bijvoorbeeld, welke toets is ingedrukt, of de toets blíjft ingedrukt (repeteert), en de taal waarvoor het toetsenbord is geconfigureerd.
Los hiervan voegt JavaScript aan e allerlei methodes toe: functies binnen het object, waarmee je allerlei dingen kunt doen.
Heel formeel is e eigenlijk geen object, maar is e een parameter, iets dat wordt doorgegeven aan de functie, zodat het binnen die functie gebruikt kan worden. e is de naam van het object, en de inhoud van e is een object. Om het object iets te kunnen vragen, of het iets te laten doen, moet het beestje 'n naam hebben: e.
De naam e voor het object is niet verplicht, maar 'n soort afspraak, zodat code makkelijker door anderen is te begrijpen. Maar als je het object niet e, maar 'hetIsStervenskoud' wilt noemen, is daar technisch geen enkel bezwaar tegen. Het is dan wel verstandig een cursus zelfverdediging te volgen, voor het geval iemand anders ooit je code moet bekijken.
(e is een afkorting van 'event', gebeurtenis. De functie reageert op een gebeurtenis, in dit geval het indrukken van een toets, een klik of een aanraking. In e zit het object dat bij díé gebeurtenis hoort. Bij bijvoorbeeld een muisklik krijg je een ander object met andere informatie dan bij het indrukken van een toets.)
{: geeft het begin van de code binnen de functie aan. Aan het eind van de functie staat een bijbehorende }.
if (e.key === "Escape") {
Deze regel is onderdeel van function openSluitVb(e)
De bij deze if horende code wordt alleen uitgevoerd, als aan onderstaande voorwaarde is voldaan:
– Escape is ingedrukt.
if: dat betekent gewoon 'als': als er aan de voorwaarde hierachter is voldaan. Die voorwaarde staat tussen haakjes, omdat dat nou eenmaal zo hoort. Het is het hele deel tussen de twee buitenste haakjes achter de if.
e: in e zit een zogenaamd object, waarin allerlei informatie zit. Bij function openSluitVb(e) {, de functie waar deze regel een onderdeel van is, is dit object aan de functie doorgegeven. Hierdoor kan de code in de functie de informatie uit dit object gebruiken.
key: dit is zo'n stukje informatie uit het hierboven genoemde object: hierin zit de naam van de ingedrukte toets.
===: wat hiervoor staat moet precies, echt helemaal precies, hetzelfde zijn, als wat hierachter staat. Om dat echt helemaal volkomen precies hetzelfde aan te geven, worden drie isgelijktekens gebruikt.
"Escape": dit is in JavaScript de naam van de Escape-toets. De inhoud van key, oftewel de naam van de ingedrukte toets moet 'Escape' zijn: de Escape-toets moet zijn ingedrukt.
{: de code die wordt uitgevoerd, als aan deze if-voorwaarde wordt voldaan, wordt tussen accolades gezet. Het script weet dan, wat bij deze if hoort. Aan het eind van de code bij deze if staat de afsluitende }.
De hele regel in gewone taal: als Escape is ingedrukt, voer dan de code tussen de {} achter de if uit.
if (e.target.parentElement.parentElement.id === "menu-ul-vb") {
Als je in de html een andere id dan 'menu-ul-vb' hebt gebruikt bij ul#menu-ul-vb, moet je die id ook in bovenstaande regel aanpassen. Dit is de enige plaats in het script, waar je dit moet aanpassen.
Deze regel is onderdeel van function openSluitVb(e)
Deze regel wordt alleen uitgevoerd, als aan deze eerder bij if gestelde voorwaarde is voldaan:
– Escape is ingedrukt.
De bij deze if horende code wordt alleen uitgevoerd, als aan onderstaande voorwaarde is voldaan:
- Escape is ingedrukt terwijl een element, waarvan de grootouder ul#menu-ul-vb is, de focus had (met andere woorden: het element is een van de links in het menu).
if: dat betekent gewoon 'als': als er aan de voorwaarde hierachter is voldaan. Die voorwaarde staat tussen haakjes, omdat dat nou eenmaal zo hoort. Het is het hele deel tussen de twee buitenste haakjes achter de if.
e: in e zit een zogenaamd object, waarin allerlei informatie zit. Bij function openSluitVb(e) {, de functie waar deze regel een onderdeel van is, is dit object aan de functie doorgegeven. Hierdoor kan de code in de functie de informatie uit dit object gebruiken.
target: dit is zo'n stukje informatie uit het hierboven genoemde object. Hierin zit, ook weer in de vorm van een object met veel informatie, het element dat de focus had op het ogenblik dat Escape werd ingedrukt.
parent: dit is zo'n stukje informatie uit target: het is de ouder van het element dat de focus had op het ogenblik dat Escape werd ingedrukt.
parent: en dit is weer de ouder van die ouder. De grootouder van het element dat de focus had dus.
id: de id van dat element, de id van de grootouder.
===: wat hiervoor staat moet precies, echt helemaal precies, hetzelfde zijn, als wat hierachter staat. Om dat echt helemaal volkomen precies hetzelfde aan te geven, worden drie isgelijktekens gebruikt.
"menu-ul-vb": dit is de id die bij de ul met het menu hoort: ul#menu-ul-vb.
Elke <a> van het menu zit in een <li>, die weer in deze <ul> zit. De <ul> is dus de grootouder van de <a>. Alleen als een <a> de focus had op het ogenblik dat Escape werd ingedrukt, is de id van de grootouder 'menu-ul-vb'. Als welk ander element dan ook de focus had op het moment dat Escape werd ingedrukt, of als geen enkel element de focus had, kan de grootouder nooit de id 'menu-ul-vb' hebben, en wordt dus niet aan de voorwaarde voldaan.
{: de code die wordt uitgevoerd, als aan deze if-voorwaarde wordt voldaan, wordt tussen accolades gezet. Het script weet dan, wat bij deze if hoort. Aan het eind van de code bij deze if staat de afsluitende }.
De hele regel in gewone taal: als de id van de grootouder van het element dat de focus had op het ogenblik dat Escape werd ingedrukt 'menu-ul-vb' is.
} else {
Deze regel is onderdeel van function openSluitVb(e)
Deze regel wordt alleen uitgevoerd, als aan deze eerder bij if gestelde voorwaarde is voldaan:
– Escape is ingedrukt.
Deze else hoort bij een eerdere if. De code bij deze else wordt alleen uitgevoerd, als aan onderstaande voorwaarde is voldaan:
– De id van de grootouder van het element dat de focus had op het ogenblik dat Escape werd ingedrukt, is niet 'menu-ul-vb' (het element was niet een van de knoppen met een link).
}: dit is de afsluitende accolade van de code die bij de hierboven genoemde if hoort. Die heeft dus eigenlijk niets met deze else te maken.
else: als aan de voorwaarde bij die if niet wordt voldaan, voer dan de code tussen de {} bij deze else uit. Er staat hier verder geen voorwaarde of zo: deze code wordt gewoon altijd uitgevoerd, als aan de voorwaarde bij de if niet wordt voldaan.
{: de code die wordt uitgevoerd, als aan deze else wordt voldaan, wordt tussen code tussen accolades gezet. Het script weet dan, wat bij deze else hoort. Aan het eind van de code bij deze else staat de afsluitende }.
De regel in gewone taal: voer de code tussen de {} bij de else uit, als niet aan de voorwaarde bij de if is voldaan, als de id van de grootouder van het element dat de focus had op het ogenblik dat Escape werd ingedrukt, niet 'menu-ul-vb' is.
document.querySelector("main").focus();
Deze regel is onderdeel van function openSluitVb(e)
Deze regel wordt alleen uitgevoerd, als aan deze eerder bij if gestelde voorwaarde is voldaan:
– Escape is ingedrukt.
Deze regel hoort bij de iets hierboven staande } else {. De regel wordt alleen uitgevoerd, als aan onderstaande voorwaarde is voldaan:
– De id van de grootouder van het element dat de focus had op het ogenblik dat Escape werd ingedrukt, is niet 'menu-ul-vb' (het element was niet een van de knoppen met een link).
Vaak is het beter om iets in een variabele op te slaan, zoals beschreven bij const toonMenuVb = document.querySelector("#toon-menu-vb");, omdat anders iets steeds opnieuw moet worden opgezocht. Of omdat er iets ingewikkelds met iets moet gebeuren. Hier gaat het om een simpele handeling, die mogelijk zelfs nooit wordt uitgevoerd.
Deze regel wordt alleen uitgevoerd, als Escape wordt ingedrukt, terwijl geen van de <a>'s in het menu de focus heeft. Dit zal geen tientallen keren achter elkaar gebeuren.
Daarom wordt hier de hele handel gelijk in één keer uitgevoerd: het opzoeken van een element en het uitvoeren van de bewerking daarop, zonder de tussenliggende stap van het opslaan van het element in een variabele.
document: dit is een zogenaamd 'object'. Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.
JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.
querySelector("main"): dit is een van die hierboven genoemde methodes. Deze methode is te vinden in het object document, vandaar dat document ervoor staat.
Met de methode querySelector() uit document kan JavaScript het eerste element van 'n bepaalde soort opzoeken, zoals de eerste <div>, het eerste element met een class="hoera", en dergelijke. Het gegeven waarnaar wordt gezocht, staat tussen aanhalingstekens tussen de haakjes:
querySelector("main")
Hierbij is de syntax van het deel tussen de aanhalingstekens precies hetzelfde als bij een selector in css. In bovenstaande regel wordt naar het element <main> gezocht, net zoals je in css in een selector main {...} zou gebruiken.
Zou je naar de eerste <span> zoeken die een eerste kind is, dan zou je de volgende regel gebruiken:
querySelector("span:first-child")
Precies zoals selectors in css werken.
In document.querySelector("main") wordt dus het element <main> opgeslagen, ook weer in de vorm van een object. De stap voor het opslaan in een variabele wordt overgeslagen, maar verder werkt het min of meer hetzelfde als bij een variabele: ook in dit tijdelijke object (het wordt niet echt opgeslagen) zit heel veel informatie over <main>, en ook kunnen weer allerlei methoden worden gebruikt. Zo zit in het object bijvoorbeeld alle css, die aan <main> is gegeven. Maar niet alleen de in het stijlbestand opgegeven css, ook alle standaardwaarden, en ook alle css die van voorouders wordt geërfd. Alle nakomelingen van <main> en hun css, attributen, enzovoort, zitten ook in het object.
Van al deze informatie in het object kan het script gebruik maken. En veel dingen binnen het object kunnen worden veranderd door het script, zoals een kleur veranderen, of een element verwijderen, of juist toevoegen.
.focus(): dit is zo'n methode. <main>, het element dat bij het gevonden object hoort, krijgt de focus.
Als gebruikers van de Tab-toets door het menu lopen, wordt het menu op een gegeven moment verlaten. Maar het menu staat dan nog wel open en kan een deel van de rest van de pagina afdekken. Gebruikelijk is dat je zo'n menu dan kunt sluiten door het indrukken van Escape. Dat zit niet standaard ingebakken in html, daarom is dit in de regels hierboven met behulp van JavaScript geregeld.
Als Escape wordt ingedrukt, terwijl één van de <a>'s in het menu de focus heeft, wordt de focus teruggezet op input#toon-menu-vb, waarmee het menu getoond en verborgen kan worden. Vervolgens kan met één toetsaanslag het menu weer worden getoond of in z'n geheel worden gepasseerd.
Maar als Escape wordt ingedrukt, terwijl geen van de <a>'s in het menu de focus had, zou het wat onhandig zijn de focus weer terug te zetten op input#toon-menu-vb. Daarom wordt de focus nu op <main> gezet, het element met de belangrijkste inhoud van de pagina. Normaal genomen kan <main> geen focus krijgen, maar door het toevoegen van tabindex="-1" aan <main>, kan dat hier wel.
;: De puntkomma geeft het eind van de regel aan. In gewone tekst zou je hier een punt gebruiken.
De hele regel in gewone taal: geef de focus aan <main>.
} else if (e.key === "Enter" && e.target.id === "toon-menu-vb") {
Als je in de html een andere id dan 'toon-menu-vb' hebt gebruikt bij input#toon-menu-vb, moet je die id ook in bovenstaande regel aanpassen.
Deze else if hoort bij een eerdere if. De code bij deze else if wordt alleen uitgevoerd, als aan onderstaande voorwaarden is voldaan:
– Escape is niet ingedrukt.
– Enter is ingedrukt, terwijl input#toon-menu-vb de focus had.
Als aan de voorwaarde bij de eerdere if, waar deze } else if { bij hoort, niet is voldaan, volgt hier een herkansing. Ook dit ziet er ingewikkeld uit, maar in stukjes gehakt wordt het weer veel overzichtelijker. (Die voorwaarde bij de eerdere if was dat Escape moest zijn ingedrukt.)
} else if: de } aan het begin is de afsluitende } van de code, die wordt uitgevoerd als aan de voorwaarde bij de if is voldaan. Die heeft dus eigenlijk niets met deze else if te maken.
else if letterlijk vertaald betekent 'anders als'. Oftewel: als aan de eerdere bij if gestelde voorwaarde niet is voldaan, kijk dan of aan deze andere voorwaarde misschien wel wordt voldaan.
(): tussen de haakjes staan de (in dit geval twee) voorwaarden, waaraan moet worden voldaan om de code bij deze else if uit te voeren:
e.key === "Enter" && e.target.id === "toon-menu-vb"
e: in e zit een zogenaamd object, waarin allerlei informatie zit. Bij function openSluitVb(e) {, de functie waar deze regel een onderdeel van is, is dit object aan de functie doorgegeven. Hierdoor kan de code in de functie de informatie uit dit object gebruiken.
key: dit is zo'n stukje informatie uit het hierboven genoemde object: hierin zit de naam van de ingedrukte toets.
===: wat hiervoor staat moet precies, echt helemaal precies, hetzelfde zijn, als wat hierachter staat. Om dat echt helemaal volkomen precies hetzelfde aan te geven, worden drie isgelijktekens gebruikt.
"Enter": dit is in JavaScript de naam van de Enter-toets. De inhoud van key, oftewel de naam van de ingedrukte toets moet 'Enter' zijn: de Enter-toets moet zijn ingedrukt.
De eerste voorwaarde, waaraan moet worden voldaan, is dus dat Enter is ingedrukt.
De code binnen deze else if zorgt ervoor dat bij indrukken van Enter het menu wordt getoond, als dat was verborgen, en juist wordt verborgen, als dat al wordt getoond. Als dit zo wordt gelaten, zou Enter overal op de pagina werken. Als iemand dan ergens Enter zou indrukken, zou bijvoorbeeld 'Menu openen' veranderen in 'Menu sluiten', en omgekeerd. Ook zou op onverwachte momenten het menu getoond en verborgen kunnen worden door het indrukken van Enter. Daarom wordt nog een tweede voorwaarde voor het uitvoeren van de code bij de else if toegevoegd:
&& e.target.id === "toon-menu-vb"
&&: dit betekent in JavaScript én. Zowel aan de voorwaarde voor als aan de voorwaarde na de && moet worden voldaan. Als niet wordt voldaan aan de voorwaarde voor de &&, wordt niet eens meer gekeken naar de voorwaarde achter de &&.
e: in e zit een zogenaamd object, waarin allerlei informatie zit. Bij function openSluitVb(e) {, de functie waar deze regel een onderdeel van is, is dit object aan de functie doorgegeven. Hierdoor kan de code in de functie de informatie uit dit object gebruiken.
target: dit is zo'n stukje informatie uit het hierboven genoemde object. Hierin zit, ook weer in de vorm van een object met veel informatie, het element dat de focus had op het ogenblik dat Escape werd ingedrukt.
id: de id van dat element.
===: wat hiervoor staat moet precies, echt helemaal precies, hetzelfde zijn, als wat hierachter staat. Om dat echt helemaal volkomen precies hetzelfde aan te geven, worden drie isgelijktekens gebruikt.
"menu-ul-vb": dit is de id die bij de ul met het menu hoort: ul#menu-ul-vb. Alleen als ul#menu-ul-vb de focus had op het ogenblik dat Enter werd ingedrukt, is de id van het element 'menu-ul-vb'. Als welk ander element dan ook de focus had op het moment dat Enter werd ingedrukt, of als geen enkel element de focus had, kan het element nooit de id 'menu-ul-vb' hebben, en wordt dus niet aan de voorwaarde voldaan.
De tweede voorwaarde, waaraan moet worden voldaan, is dus dat de id van het element dat de focus heeft, op het moment dat Enter wordt ingedrukt, 'toon-menu-vb' is.
{: het begin van de eventueel bij deze else if uit te voeren code wordt aangegeven met de { aan het eind van de regel. Het eind van de eventueel bij deze else if uit te voeren code wordt aangegeven met een }. In dit geval is dat de } bij } else if (document.querySelector(#menu-vb").contains(e.target)) { iets verderop.
De hele regel in gewone taal: als de ingedrukte toets Enter is én als de id van het element dat de focus had op het ogenblik dat Enter werd ingedrukt 'toon-menu-vb' is.
De code tussen de {} achter de else if wordt alleen uitgevoerd, als aan beide voorwaarden is voldaan: Enter moet zijn ingedrukt terwijl input#toon-menu-vb de focus had. Als aan één van beide voorwaarden niet wordt voldaan, wordt de code tussen de {} niet uitgevoerd.
return;
Deze regel is onderdeel van function openSluitVb(e)
Deze regel wordt alleen uitgevoerd, als aan deze eerder else if gestelde voorwaarde is voldaan:
- Het element dat werd aangeraakt of ‑geklikt is een nakomeling van nav#menu-vb.
Doe verder niets. Daar zorgt deze regel voor: stop en ga terug naar waar je vandaan kwam.
Dat 'terug naar waar je vandaan kwam' betekent: terug naar de plek, waarvandaan is aangeroepen. In dit geval is er geen terug, want function openSluitVb(e), waar deze return een onderdeel van is, is niet aangeroepen door een ander deel van het script, maar door een klik, een aanraking of het indrukken van een toets: deze functie is vanuit de html 'aangeroepen'. 'Terug naar waar je vandaan kwam' betekent hier dus: weg uit het script en 'terug' naar de html. Oftewel: de rest van het script wordt niet uitgevoerd.
De puntkomma geeft het einde van de regel aan. In gewone tekst zou je hier een punt gebruiken.
In de css is geregeld dat bij een aanraking van een van de knoppen met een link een venstertje met informatie wordt geopend. Daarom hoeft het script verder niets te doen: de css handelt dit af.
} else {
Deze regel is onderdeel van function openSluitVb(e)
Deze else hoort bij een eerdere if en twee eerdere else if's: else if en else if
De code bij deze else wordt alleen uitgevoerd, als aan onderstaande voorwaarden is voldaan:
– Escape werd niet ingedrukt.
– Enter is niet ingedrukt, terwijl input#toon-menu-vb de focus had.
– Het element dat werd aangeraakt of ‑geklikt is geen nakomeling van nav#menu-vb.
}: dit is de afsluitende accolade van de code die bij de hierboven genoemde if hoort. Die heeft dus eigenlijk niets met deze else te maken.
else: als aan de voorwaarden bij de if en de eerdere else if 's niet wordt voldaan, voer dan de code tussen de {} bij deze else uit. Er staat hier verder geen voorwaarde of zo: deze code wordt gewoon altijd uitgevoerd, als aan de voorwaarden bij de if en de else if's niet wordt voldaan.
{: de code die wordt uitgevoerd, als aan de voorwaarde bij deze else wordt voldaan, wordt tussen accolades gezet. Het script weet dan, wat bij deze else hoort. Aan het eind van de code bij deze else staat de afsluitende }.
Als aan geen van de eerdere voorwaarden bij de if en de else if's is voldaan, is de enige mogelijkheid nog dat het scherm ergens buiten het menu is aangeraakt of ‑geklikt.
