Uitleg lange tekst met inhoudsopgave. Inhoudsopgave en tekst zijn onafhankelijk te scrollen
Laatst aangepast: .

Korte omschrijving
In de inhoudsopgave staan koppelingen naar de tekst. In bredere vensters is de inhoudsopgave altijd zichtbaar, in smallere vensters alleen op verzoek. Inhoudsopgave en tekst kunnen onafhankelijk van elkaar scrollen.
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.
Alles op deze site kan vrij worden gebruikt, met drie beperkingen:
* Je gebruikt het materiaal op deze site volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte info zitten. Voor eventuele schade die door gebruik van materiaal van deze site ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.
* Deze uitleg wordt regelmatig bijgewerkt. Het is daarom niet toegestaan deze uitleg op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat de uitleg afkomstig is van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.
* Het kan zijn dat materiaal is gebruikt dat van anderen afkomstig is. Dat materiaal kan onder een bepaalde licentie vallen, waardoor het mogelijk niet onbeperkt gebruikt mag worden. Als dat zo is, wordt dat vermeld onder Inhoud van de download en licenties.
Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.
Alle code is geschreven in een afwijkende
lettersoort en -kleur. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles vanwege de leesbaarheid in een gewone letter.)
Opmerkingen
- Waarom de grondwet? Dat is de soort tekst die goed bruikbaar is voor dit voorbeeld. En nu is hij nog in deze vorm te lezen. Als bepaalde hele en halve fascisten 't voor 't zeggen krijgen in dit land, zal deze grondwet er straks anders uitzien. Voor bijvoorbeeld het verbieden van 'n godsdienstig boek zul je namelijk toch echt eerst de grondwet moeten wijzigen. Als er dan überhaupt nog 'n grondwet is...
- Om de links in de inhoudsopgave er weer onbezocht uit te laten zien, moet je de geschiedenis van de browser verwijderen.
-
In dit voorbeeld wordt een klein JavaScript gebruikt, om te voorkomen dat elke link in de inhoudsopgave na klikken in de geschiedenis van de browser komt te staan. Als je dit script wilt testen, moet dat online gebeuren, of je moet zelf een server installeren. Omdat kwaadwillenden dit soort scripts zouden kunnen misbruiken, werkt het in steeds meer browsers niet meer offline.
Zonder dit script moet je na het aanklikken van tweehonderd links in de inhoudsopgave tweehonderd keer op de Terug-toets van de browser klikken, om weer 'n pagina terug te gaan. Eerst worden alle tweehonderd links in de inhoudsopgave weer teruggespoeld. Zonder script werkt dit voorbeeld nog steeds, maar dan werkt de geschiedenis op deze standaardmanier. Je kunt nog wel gewoon 'n favoriet (of bookmark, of hoe het beestje ook heet) van het adres van de link maken. Ook zit het adres nog gewoon in de lijst met bezochte adressen.
- Bij dit voorbeeld is een inhoudsopgave vrij zinloos. Overigens is dit voorbeeld natuurlijk alleen maar 'n voorbeeld. Je moet toch 'n beetje, eh, apart zijn om ruim tweehonderd links te maken naar artikelen die deels maar 1 regel hoog zijn. Maar dezelfde techniek kan ook worden gebruikt voor teksten die langer zijn.
Links in deze uitleg, vooral links naar andere sites, kunnen verouderd zijn. Op de pagina met links vind je steeds de meest recente links.
Dit voorbeeld is gemaakt op een systeem met Linux (Kubuntu). Daarbij is vooral gebruik gemaakt van Visual Studio Code, GIMP en Firefox met extensies. De pdf-bestanden zijn gemaakt met LibreOffice.
Vragen of opmerkingen? Fout gevonden? Ga naar het forum.
Achterliggend idee
De inhoudsopgave staat in een <nav>, de tekst staat in een <main>. Deze twee elementen staan samen weer in een gezamenlijke ouder: div#wrapper
.
Door div#wrapper
absoluut te positioneren binnen boven- en onderkant van het browservenster, wordt het venster van boven tot onder gevuld. <nav> en <main> kunnen dan absoluut binnen div#wrapper
worden gepositioneerd, waardoor ze los van elkaar kunnen scrollen.
(In eerdere versies hadden inhoud en tekst geen gemeenschappelijke ouder. De inhoud stond fixed gepositioneerd, de tekst niet. Bij deze constructie scrolt op iOS de tekst mee met de inhoud, dus deze constructie moest worden aangepast.)
De inhoudsopgave bestaat uit een hele serie links, die in een ongeordende lijst <ul> worden gezet. Klikken op of aanraken van een link zorgt ervoor dat de juiste plek in de tekst bovenaan wordt gezet. De links verwijzen naar ankers in de tekst. Dat die tekst naast de inhoudsopgave staat maakt niets uit voor de werking.
Een tekst als deze is uitstekend geschikt om te werken met kopregels (<h1>, <h2>, enzovoort). De belangrijkste titel geef je <h1>, hoofdstukken <h2> en paragrafen en artikelen <h3>. Je zou ook paragrafen h3 kunnen geven en artikelen h4, maar paragrafen worden nogal onregelmatig gebruikt, dus dat is niet gedaan. Door het gebruik van kopregels kunnen schermlezers makkelijk door de tekst heen 'springen'.
In smallere browservensters ontstaat een probleem. Het lijkt wat onwaarschijnlijk dat mensen echt heel blij worden van een inhoudsopgave, die vier vijfde van het venster vult. Daarom wordt de inhoudsopgave in smallere vensters verborgen. Pas na het aanraken van een knop wordt de inhoudsopgave zichtbaar.
Boven de inhoudsopgave is een kleine ruimte vrijgelaten. Hierdoor is het begin van bij de gekozen link horende tekst te zien. Je kunt daardoor zien, of je de juiste tekst hebt gekozen, zonder dat je de inhoudsopgave eerst weer moet sluiten.
Browsers bewaren bezochte links in de browsergeschiedenis. Hierdoor kun je snel naar 'n bezochte site terug‑ of vooruitgaan met behulp van de Terug‑ of Vooruit-toets van de browser, of met behulp van een toetscombinatie als Alt+← of Alt+→. Dat betekent echter ook dat alle gevolgde links in de inhoudsopgave worden opgeslagen, wat niet erg zinvol lijkt. Dit wordt voorkomen met behulp van JavaScript. Favorieten (of bookmarks, of hoe het beestje ook heet) kunnen wel gewoon worden gemaakt. Ook zitten de links gewoon in de lijst met bezochte adressen.
De voorvoegsels -moz-, -ms- en -webkit-
Voordat een nieuwe css-eigenschap wordt ingevoerd, is er in de regel een experimentele fase. Browsers passen het dan al toe, maar met een aangepaste naam. Tijdens deze fase kunnen problemen worden opgelost en worden veldslagen uitgevochten, over hoe de standaard precies moet worden toegepast.
Als iedereen het overal over eens is en alle problemen zijn opgelost, wordt de officiële naam uit de standaard gebruikt.
De belangrijkste browsers hebben elk een eigen voorvoegsel:
Firefox: -moz-
, naar de maker: Mozilla.
Op webkit gebaseerde browsers, zoals Google Chrome, Opera, Safari en Android browser: -webkit-
.
(Google Chrome is van webkit overgestapt op een eigen weergave-machine: Blink. Blink gaat geen voorvoegsels gebruiken. Het is echter een aftakking van webkit, dus het zal nog wel even duren voor -webkit-
hier helemaal uit is verdwenen. Ook Opera gebruikt Blink.)
Internet Explorer: -ms-
, naar de maker: Microsoft. (Edge gebruikt geen voorvoegsels, maar vanwege compatibiliteit met oudere sites kunnen er nog wat aanwezig zijn.)
Zodra de experimentele fase voorbij is, wordt het voorvoegsel weggelaten. Omdat dat moment niet bij alle browsers hetzelfde is, zet je nu ook al de officiële naam erbij. Deze wordt als laatste opgegeven. Bijvoorbeeld Android browser herkent -webkit-linear-gradient
. Zodra Android browser linear-gradient
gaat herkennen, zal dit -webkit-linear-gradient
overrulen, omdat het er later in staat. Dat ze er beide in staan, is dus geen enkel probleem.
In dit voorbeeld worden transform
, -webkit-overflow-scrolling
, -webkit-animation
en @-webkit-keyframes
gebruikt.
transform
Op dit moment moet je nog het volgende schrijven:
{-webkit-transform: ...; transform: ...;}
In de toekomst kun je volstaan met:
{transform: ...;}
-webkit-overflow-scrolling
Als op iOS niet de hele pagina, maar binnen een element wordt gescrold, zoals hier binnen <nav> en <main> gebeurt, gaat dat scrollen om een of andere duistere reden ongelooflijk schokkerig. Met deze eigenschap kan voor vloeiend scrollen worden gezorgd.
Omdat dit alleen voor iOS nodig is, wordt van deze eigenschap alleen de -webkit
-versie gebruikt: buiten iOS is hij niet nodig (en werkt ook niet).
Deze eigenschap kan grote problemen opleveren en moet grondig worden getest. Meer hierover is te vinden bij Bekende problemen (en oplossingen) onder het kopje Zoomen op iOS in vensters minstens 760 px breed.
-webkit-animation en @-webkit-keyframes
Deze twee eigenschappen worden alleen maar gebruikt om een bug in sommige oudere op webkit gebaseerde browsers te repareren. Daarom hoeft alleen maar op browsers gelet te worden, die op webkit zijn gebaseerd. In dit geval is daarom het volgende voldoende:
{-webkit-animation: ...;}
Hetzelfde geldt voor @keyframes
:
@-webkit-keyframes {...}
In nieuwere browsers is deze bug niet meer aanwezig, dus de versie zonder voorvoegsel hoeft in dit geval helemaal niet gebruikt te worden.
(In het algemeen is het een bijzonder slechte gewoonte om van een eigenschap alleen één bepaalde versie te gebruiken. Dit gebeurt nogal eens voor iOS, waarmee Apple actief wordt geholpen om sites en dergelijke ontoegankelijk te maken voor andere browsers dan Safari. Ontwikkelaars die dit doen, werken mee aan de totstandkoming van eenzelfde wantoestand als in het verleden met het monopolie van Internet Explorer 6 heeft bestaan.
Maar in dit geval maakt het niet uit, omdat het alleen om een bug gaat. Andere browsers hebben deze css helemaal niet nodig.)
Inmiddels is de algemene mening dat 'vendor prefixes', zoals deze voorvoegsels in het Engels heten, geen groot succes zijn. Eén van de grootste problemen: veel sitemakers gebruiken alleen de -webkit-
variant. Daar kwamen ze in het verleden nog mee weg, omdat Apple op mobiel zo'n beetje 'n monopolie had. Inmiddels is dat niet meer zo, maar deze gewoonte bestaat nog steeds. Waardoor 'n site alleen in op webkit georiënteerde browsers goed is te bekijken.
Dit is zo'n groot probleem dat andere browsers soms de variant met -webkit-
ook maar zijn gaan implementeren, naast de standaard. Want als 'n site het niet goed doet in 'n bepaalde browser, krijgt in de regel niet de site maar de browser de schuld.
Vanwege alle problemen met 'vendor prefixes' worden deze door steeds meer browsers niet meer gebruikt. Nieuwe, experimentele css-eigenschappen zitten inmiddels in bijvoorbeeld Firefox, Google Chrome en Safari achter een zogenaamde vlag: de gebruiker moet iets veranderen in de instellingen, waarna de eigenschap gebruikt (en getest) kan worden. Als alles werkt, zoals het hoort te werken, schakelt de browsermaker de vlag standaard in.
Voorlopig zijn we echter nog niet van deze voorvoegsels af. Als je ze gebruikt, gebruik dan álle varianten, en eindig met de variant zonder voorvoegsel, zoals die uiteindelijk ooit gebruikt gaat worden. Als je alleen de -webkit-
variant gebruikt, ben je in feite 'n onbetaalde reclamemaker voor Apple. (Dit geldt dus niet voor de hierboven genoemde -webkit-overflow-scrolling
, @-webkit-keyframes
en -webkit-animation
, want deze worden alleen gebruikt om een probleem in oudere webkit-browsers en op iOS op te lossen.)
Semantische elementen en WAI-ARIA
Deze twee onderwerpen zijn samengevoegd, omdat ze veel met elkaar te maken hebben.
Semantische elementen
De meeste elementen die in html worden gebruikt, hebben een semantische betekenis. Dat wil zeggen dat je aan de gebruikte tag al (enigszins) kunt zien, wat voor soort inhoud er in het element staat. In een <h1> staat een belangrijke kop. In een <h2> staat een iets minder belangrijke kop. In een <p> staat een alinea. In een <table> staat een tabel (en geen lay-out, als het goed is!). Enzovoort.
Door het op de goede manier gebruiken van semantische elementen, kunnen zoekmachines, schermlezers, enzovoort de structuur van een pagina begrijpen. De spider van een zoekmachine is redelijk te vergelijken met een blinde. Het is dus ook in je eigen belang om semantische elementen zo goed mogelijk te gebruiken. Een site die toegankelijk is voor mensen met een handicap, is in de regel ook goed te verwerken door een zoekmachine en maakt dus een grotere kans gevonden en bezocht te worden.
Als het goed is, wordt het uiterlijk van de pagina bepaald met behulp van css. Het uiterlijk staat hierdoor (vrijwel) los van de semantische inhoud van de pagina. Met behulp van css kun je een <h1> heel klein weergeven en een <h6> heel groot, terwijl schermlezers, zoekmachines, en dergelijke nog steeds weten dat de <h1> een belangrijke kop is.
Slechts enkele elementen, zoals <div> en <span>, hebben geen semantische betekenis. Daardoor zijn deze elementen uitstekend geschikt om met behulp van css het uiterlijk van de pagina aan te passen: de semantische betekenis verandert niet, maar het uiterlijk wel. Voor een schermlezer of zoekmachine verandert er (vrijwel) niets, voor de gemiddelde bezoeker krijgt het door de css een heel ander uiterlijk.
(De derde laag, naast html voor de inhoud en css voor het uiterlijk, is JavaScript. Die zorgt voor de interactie tussen site en bezoeker. De min of meer strikte scheiding tussen css en html aan de ene kant en JavaScript aan de andere kant is met de komst van css3 en html5 veel vager geworden. Je kunt nu bijvoorbeeld ook met css dingen langzaam verplaatsen en met html deels de invoer in formulieren controleren.)
Html5 heeft een aantal nieuwe elementen, die speciaal zijn bedoeld om de opbouw van een pagina aan te geven. In dit voorbeeld worden hiervan <nav> en <main> gebruikt. Beide gedragen zich als een gewone <div>, maar dan een <div> met een semantische betekenis. Hierdoor kunnen schermlezers, zoekmachines, en dergelijke beter zien, hoe de pagina is samengesteld.
<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, waarmee je naar andere pagina's en dergelijke kunt gaan.
Omdat <nav> alleen aangeeft dat hierin een of andere vorm van navigatie is ondergebracht, maar niet wat voor navigatie, staat gelijk onder de openingstag <nav> een <h2>. De <h2> geeft aan, wat voor soort navigatie hier staat: 'Inhoudsopgave grondwet'. Deze <h2> wordt links buiten het scherm geparkeerd, zodat je hem niet ziet. Maar schermlezers en dergelijke lezen de kop gewoon voor, ook al zie je hem niet. Hierdoor is voor gebruikers van schermlezers duidelijk, wat voor soort navigatie hier staat.
In het voorbeeld staat maar één soort navigatie, maar bijvoorbeeld op de site staan niet alleen de links van het voorbeeld, maar ook de navigatie voor de site zelf. Door op de site beide <nav>'s van een verborgen kop te voorzien, kunnen schermlezers en dergelijke achterhalen, om welke navigatie het gaat.
<main>
Hierbinnen staat de belangrijkste inhoud van de pagina (in dit voorbeeld is dat de tekst van de grondwet).
Met behulp van dit soort nieuwe semantische elementen kan bijvoorbeeld een schermlezer in één keer een heel menu passeren en gelijk naar de echte inhoud gaan. Alleen hadden deze nieuwe elementen tot voor kort één probleem: ze hadden in de praktijk nog weinig nut, omdat schermlezers en dergelijke ze nog niet herkenden. Daarom werd een zogenaamde WAI-ARIA-code toegevoegd aan deze elementen. Dat is een al veel langer bestaande code, die schermlezers en dergelijke wel herkennen. Voor <main> ziet dat er zo uit:
<main role="main">
Inmiddels is dit behoorlijk veranderd. Het advies is nu om deze speciale toevoeging niet meer te gebruiken, omdat de meeste schermlezers en dergelijke dit soort nieuwe elementen inmiddels herkennen.
WAI-ARIA-codes
WAI-ARIA wordt vaak ingekort tot ARIA. Voluit betekent het Web Accessibility Initiative – Accessible Rich Internet Applications.
Er wordt in dit voorbeeld één WAI-ARIA-code gebruikt: aria-hidden
.
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.
In dit voorbeeld kunnen de <input> en de <label> voor schermlezers uiterst verwarrend zijn. In browservensters smaller dan 760 px wordt de inhoudsopgave niet getoond, maar kan deze met behulp van de <input> en de <label> zichtbaar worden gemaakt.
Voor schermlezers heeft dit echter geen enkel nut. De inhoudsopgave staat links buiten het scherm geparkeerd. Maar voor schermlezers is de inhoudsopgave gewoon zichtbaar en wordt dus gewoon voorgelezen. (Als ze met display: none;
of visibility: hidden;
zouden zijn verborgen, zou een schermlezer ze ook niet zien.)
Omdat voor schermlezers de inhoudsopgave altijd zichtbaar is, hebben <input> en <label> geen zin. Met behulp van aria-hidden
worden ze verborgen:
<input id="checkbox-voor-smal" type="checkbox" aria-hidden="true">
<label id="toon-menu" for="checkbox-voor-smal" aria-hidden="true">Inhoudsopgave</label>
(Dit verhaal klopt niet helemaal voor de schermlezer TalkBack. Meer daarover is te vinden bij Bekende problemen (en oplossingen) onder het kopje Schermlezers.)
Tabindex en Tab-toets
Links, invoervelden in formulieren, en dergelijke kunnen met behulp van de Tab-toets (of een soortgelijke toets) één voor één worden bezocht, in de volgorde waarin ze in de html voorkomen. Shift+Tab-toets keert de volgorde van de Tab-toets om. Dit is een belangrijk hulpmiddel voor mensen die om een of andere reden de muis niet kunnen of willen gebruiken. (En het is vaak ook veel sneller dan de muis, vooral in formulieren.)
In sommige browsers en/of besturingssystemen is dit vreemd genoeg standaard uitgeschakeld en is een zoektocht in de instellingen nodig om dit aan te zetten. Maar gebruikers van de Tab-toets zullen dit al hebben gedaan.
Als je met behulp van de Tab-toets een element hebt bereikt, heeft dit 'focus': als het een link is en je drukt op Enter, wordt de link gevolgd. Bij een tekstveld kun je tekst gaan invoeren. Enzovoort.
De Tab-toets volgt normaal genomen de volgorde van de elementen in de html. Het maakt niet uit, in welke volgorde ze op het scherm staan. Als je met behulp van css de elementen van plaats verwisselt op het scherm, wordt toch gewoon de volgorde in de html gevolgd.
De volgorde van de Tab-toets kan worden veranderd met behulp van het tabindex
-attribuut: <div tabindex="3">
. Deze <div> zal nu als derde worden bezocht, ook al krijgt een simpele <div> normaal genomen nooit bezoek van de Tab-toets.
Normaal genomen is het gebruik van een tabindex niet nodig. Het is zeker niet bedoeld om de bezoeker als een kangoeroe op een hindernisbaan van onder via links over rechts naar boven te laten springen. Maar soms kan het handig zijn voor kleinere correcties, als de normale volgorde in de html niet optimaal is. Of om een element bereikbaar te maken voor de Tab-toets, zoals de hierboven genoemde <div>.
Schermlezers blijven altijd de volgorde van de html volgen, dus als de tabindex sterk afwijkt van de volgorde in de html, kan dat behoorlijk verwarrend zijn.
De tabindex kan drie verschillende waarden hebben: -1, 0 of een positief getal.
In principe is de volgorde bij gebruik van de Tab-toets als volgt: eerst worden alle positieve getallen in volgorde afgewerkt. Als twee tabindexen dezelfde waarde hebben, wordt de volgorde in de html aangehouden. Een waarde van '0' wordt, afhankelijk van browser en besturingssysteem, verschillend behandeld, waarover iets hieronder bij Tabindex="0" meer.
tabindex="-1"
Een negatieve waarde van -1 zorgt ervoor dat het element volledig wordt genegeerd door de Tab-toets. Zelfs een link met een negatieve tabindex wordt volledig genegeerd. Normaal genomen heeft een tabindex="-1"
maar één nut: je kunt dan met behulp van JavaScript toch focus aan het element geven, zonder dat gebruikers van de Tab-toets erdoor worden gehinderd.
In dit voorbeeld wordt tabindex="-1"
niet gebruikt, maar het is eventueel te gebruiken op ongeveer dezelfde manier als hieronder bij tabindex="0"
wordt beschreven.
tabindex="0"
Volgens de specificatie van html 4.01 moest een tabindex="0"
pas worden bezocht, nadat tabindexen met een positief nummer waren bezocht. Sommige browsers hielden zich hier echter niet aan: een tabindex="0"
werd gewoon tussen de positieve tabindexen gezet.
In html5 is de situatie nog fijner. Nu staat er alleen dat, wat betreft de volgorde, de gewoonte van het platform wordt gevolgd. Oftewel: doe maar raak. Maar hoe dan ook: als je tabindex="0"
gebruikt, kan een element focus krijgen met behulp van de Tab-toets. Ook als dat element normaal genomen geen focus kan krijgen. Hiervan wordt in dit voorbeeld gebruik gemaakt.
Als de gebruiker van een Tab-toets bij een link aankomt en op Enter drukt, wordt die link gevolgd: je gaat naar een andere pagina.
Binnen de pagina zelf werkt dat op ongeveer dezelfde manier: je gaat naar een andere plaats op dezelfde pagina, 'n 'anker'. Als de gebruiker vervolgens nogmaals op de Tab-toets drukt, zou je verwachten dat vanaf dat anker verder wordt gegaan. Tot voor kort deed echter alleen Firefox dat. Sommige browsers gingen, bij nogmaals indrukken van de Tab-toets, terug naar de gevolgde link en gingen vanaf daar verder. Sommige browsers gedroegen zich nog vreemder: die gingen terug naar de bovenkant van de pagina, en gaven dan aan de bovenste link, knop, of iets soortgelijks focus.
Voor scrollen met de pijltjestoetsen en dergelijke gold hetzelfde: behalve in Firefox werd gescrold vanaf de link die was gevolgd, of vanaf de bovenkant van de pagina, maar niet vanaf het bezochte anker op de pagina.
Inmiddels gedragen alle browsers zich hetzelfde als Firefox: als een link binnen een pagina wordt gevolgd en je drukt vervolgens op de Tab-toets, gaat de focus naar de eerste link, knop, en dergelijke die volgt op het bezochte anker. Ook kan vanaf die plaats worden gescrold met de pijltjestoetsen en dergelijke, zonder dat het anker eerst aangeklikt of aangeraakt moet worden.
Maar dit werkt kennelijk nog niet helemaal perfect in alle browsers. Als je in Firefox, Internet Explorer en Edge een link in de inhoudsopgave volgt, gaat het zoals hierboven beschreven. Nogmaals tabben brengt je naar de eerstvolgende link en dergelijke na het bezochte anker, en scrollen met de pijltjestoetsen en dergelijke kan gelijk, zonder dat je eerst de tekst moet aanklikken of aanraken.
In Safari, Opera, UC browser en Google Chrome werkt dit ook zo, maar niet als de link die wordt gevolgd in een element staat, dat niet met de tekst mee kan scrollen. En dat is het geval met de <nav>, waarbinnen de links uit de inhoudsopgave staan. Die <nav> is absoluut gepositioneerd tussen boven- en onderkant van het browservenster.
Als je in deze browsers bijvoorbeeld op 'Artikel 10' klikt – of bij focus van die link op Enter drukt –, wordt de tekst met 'Artikel 10' bovenaan het browservenster gezet. Maar bij nogmaals indrukken van de Tab-toets krijgt de link met 'Artikel 11' uit de inhoudsopgave focus. Ook kun je de tekst pas scrollen, als de tekst is aangeklikt of aangeraakt. Zonder aanraken of -klikken van de tekst laten pijltjestoetsen en dergelijke niet de tekst, maar de inhoudsopgave scrollen. (Terug naar de bovenkant van de pagina gaat gelukkig geen enkele browser meer.)
Als je aan de ankers (het doel van de links in de inhoudsopgave) het attribuut tabindex="0"
toevoegt, gedragen alle browsers zich op dezelfde manier als Firefox, Internet Explorer en Edge. Als een link naar een anker wordt gevolgd, brengt een volgende tab je naar de op het anker volgende link, knop, en dergelijke. Scrollen met de pijltjestoetsen en dergelijke gebeurt nu gelijk vanaf de plaats van het anker, zonder dat een klik of aanraking nodig is.
<h3 id="art-10" tabindex="0">Artikel 10</h3>
Hier boven staat het kopje van 'Artikel 10' in de tekst. Door het toevoegen van tabindex="0"
gedragen ook deze browsers zich nu op dezelfde manier. Als de link naar 'Artikel 10' is gevolgd, kan gelijk vanaf die plaats worden gescrold. Een volgende tab gaat naar de eerste link, knop, en dergelijke in de tekst die volgt op 'Artikel 10', en niet naar de link in 'Artikel 11' in de inhoudsopgave.
Er is nog een bijkomend voordeel. Bij gebruik van de Tab-toets wordt een <h> normaal genomen genegeerd: alleen links, tekstvelden, knoppen, en dergelijke worden bezocht. Maar door de tabindex="0"
worden ook de <h>'s (en andere elementen) nu bezocht door de Tab-toets.
Als een gebruiker door de inhoudsopgave heen tabt en op 'n gegeven moment 'n bepaalde link volgt, brengt een volgende tab de gebruiker naar de volgende <h>. Na de eerste keuze kan de gebruiker dus op precies dezelfde manier verdergaan met de Tab-toets, als wanneer door de inhoudsopgave werd getabd.
Als je tabindex="-1"
gebruikt in plaats van tabindex="0"
, klopt bovenstaand verhaal nog steeds. Alleen kun je nu niet meer met de Tab-toets van anker naar anker springen, want een negatieve tabindex wordt genomen genegeerd door de Tab-toets. Alleen bij tabindex="0"
worden elementen zoals een <h> door de Tab-toets bezocht.
Binnen de inhoudsopgave zelf staan ook nog skip-links:
<li class="li-skippy"><a class="skippy" href="l-hs-2">Skip links naar hoofdstuk 1</a></li>
Met behulp van deze links kunnen gebruikers van de Tab-toets (en van de meeste schermlezers) een deel van de inhoud overslaan. Deze skip-links staan binnen de <nav> met de inhoudsopgave, en het doel van de link, het anker, staat ook binnen de <nav>. Daarom spelen de hierboven beschreven problemen hier niet: alle browsers gaan verder vanaf het anker, als de Tab-toets nogmaals wordt ingedrukt.
(Meer over deze skip-links is te vinden bij <li class="li-skippy">...)
(Overigens zijn dit soort problemen soms minder groot, dan ze lijken. Schermlezers bijvoorbeeld kunnen van kopregel naar kopregel springen. Mensen die de muis echt niet kunnen gebruiken, hebben vaak een programmaatje, waardoor ze met behulp van toetsen de cursor kunnen bewegen, klikken, en dergelijke.)
tabindex="..."
Op de plaats van de puntjes moet een positief getal worden ingevuld: het volgnummer. Positieve tabindexen worden in dit voorbeeld niet gebruikt.
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 vooral geen FrontPage, Publisher of Word (alle drie van Microsoft). Deze programma's maken niet-standaard code die alleen goed te bekijken is in Internet Explorer. In alle andere browsers zie je grotendeels bagger, áls je al iets ziet.
Publisher en Word zijn niet bedoeld om websites mee te maken. FrontPage is zwaar verouderd en wordt 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 natuurlijk ook een goed gratis programma gebruiken. Links naar dat soort programma's vind je op de pagina met links onder Gereedschap → wysiwyg-editor.
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 touchscreen.
Inmiddels hebben veel browsers mogelijkheden voor het simuleren van weergave op een kleiner scherm in de ontwikkelgereedschappen ingebouwd. Ook dit blijft een simulatie, maar geeft vaak wel een beter beeld dan zoomen.
-
Ik maak zelf het liefst een site in Firefox. Als je 'n site maakt in Firefox, Opera, Safari, Google Chrome of Edge, is er 'n hele grote kans dat hij in alle browsers werkt. Ik geef de voorkeur aan Firefox, omdat het de enige grote browser 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 ik heb dus wat moeite met hoe Google je hele surfgedrag, je schoenmaat en de kleur van je onderbroek vastlegt. Daarom gebruik ik Google Chrome zelf alleen 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 een 'strict' doctype of (beter!) het doctype voor html5. Deze zijn bedoeld voor nieuwe sites. Het transitional doctype is bedoeld voor al bestaande sites, niet voor nieuwe.
Het transitional doctype staat talloze tags toe, die in html5 zijn verboden. Deze tags worden al zo'n tien jaar afgeraden. Het transitional doctype is echt alleen bedoeld om de puinhoop van vroeger, toen niet volgens standaarden werd gewerkt, enigszins te herstellen.
Het 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. - Als tweede voer je de charset in. 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. Ook van Internet Explorer kun je meerdere versies naast elkaar draaien. Op de pagina met links staan onder de kopjes Gereedschap → Meerdere versies van Internet Explorer draaien en Gereedschap → Weergave testen 'n aantal links die daarbij kunnen helpen. De compatibiliteitsweergave in Internet Explorer is niet geschikt om in te testen, omdat deze enigszins verschilt van de weergave in échte browsers.
- 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, zou ik je aanraden de verschillende delen een achtergrondkleur te geven. Je ziet dan goed, waar 'n deel precies staat. Een achtergrondkleur heeft – anders dan bijvoorbeeld een border – verder geen invloed op de lay-out, dus die is hier heel geschikt voor.
- Als je instellingen verandert in de style, 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, padding en border worden bij de hoogte en breedte 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 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-sizing
padding en border bínnen de breedte en hoogte van de inhoud te zetten, als je dat handiger vindt. -
In plaats van een absolute eenheid als
px
kun je ook een relatieve eenheid gebruiken, met nameem
. Voordeel vanem
is dat een lettergrootte, regelhoogte, en dergelijke inem
in 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 alsem
vrijwel altijd beter dan vaste eenheden alspx
.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.
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, 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. Dat kun je ook doen, als uit de tekst bij de afbeelding al duidelijk wordt, wat de afbeelding is. Een alt-tekst zou dan 'n beetje dubbelop zijn. - Als uit de tekst bij een link niet duidelijk blijkt, waar de link naartoe leidt, gebruik dan een title bij de link. Een tekst als 'pagina met externe links' is waarschijnlijk duidelijk genoeg, een tekst als alleen 'links' mogelijk niet. Een duidelijke zwart-witregel is niet te geven, omdat dit ook van tekst en dergelijke in de omgeving van de link afhangt.
-
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.
Voor mij redenen om accesskeys (vrijwel) niet te gebruiken. Ik kan me wel voorstellen dat ze, op sites die gericht zijn op 'n specifieke groep gebruikers, nog enig nut kunnen hebben. Maar voor algemene sites zou ik zeggen: normaal genomen niet gebruiken.
-
Met behulp van de Tab-toets (of op 'n soortgelijke manier) kun je in de meeste browsers 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
tabindex
kun je de volgorde aangeven, waarin de Tab-toets werkt. Zondertabindex
wordt 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
tabindex
niet nodig is, maar gewoon de volgorde van de html wordt aangehouden. Bij verkeerd gebruik kantabindex
heel 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. - Als, zoals hierboven beschreven, een gebruiker van de Tab-toets bij een link, invoerveld, en dergelijke is aangekomen, wordt dit 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 zij of hij zit, en welk element gaat reageren op bijvoorbeeld een Enter.
- 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.
-
Een zogenaamde skip-link is wel vaak nog zinvol. Dat is een link die je buiten het scherm parkeert met behulp van css, zodat hij 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.
Een skip-link staat boven menu, header, en dergelijke en linkt naar de eigenlijke inhoud van de pagina, zodat mensen met één toetsaanslag naar de eigenlijke inhoud van de pagina kunnen 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 hem op het scherm plaatsen, waardoor hij zichtbaar wordt. Bij een volgende tab wordt hij dan weer buiten het scherm geplaatst en is dus niet meer zichtbaar, zodat de lay-out niet wordt verstoord.
Op pagina's en in voorbeelden waar dat nuttig is, wordt op deze site een skip-link gebruikt. (Althans: nog niet in alle voorbeelden die daarvoor in aanmerking komen, zit een skip-link. Maar geleidelijk aan worden dat er steeds meer.)
-
Van oorsprong is html een taal om wetenschappelijke documenten weer te geven, pas later is hij gebruikt voor lay-out. Maar daar is hij 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 externe stylesheet staan of, als hij 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 hij 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 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 of SSI. 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 beter PHP dan SSI gebruiken, omdat SSI min of meer aan het uitsterven is en PHP veel meer mogelijkheden heeft. Op deze site wordt in enkele voorbeelden nog SSI gebruikt, maar zodra die worden bijgewerkt, gaat dat vervangen worden door PHP.)
- 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 maar af en toe, 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. - 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 groene rode 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 tekstkleur, tussen
background-color
encolor
. 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. Een uitstekende online contrastchecker is bijvoorbeeld te vinden op snook.ca. -
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. Hetzelfde geldt voor die fantastisch mooie flash-pagina's, als daarbij geen voorzieningen voor dit soort programma's zijn aangebracht.
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 hem zien. WebbIE is te downloaden vanaf www.webbie.org.uk.
-
Ten slotte kun je je pagina nog online 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.
Op de pagina met links kun je onder Toegankelijkheid links naar testen en dergelijke vinden.
Getest in
Laatst gecontroleerd op 11 maart 2018.
Onder dit kopje staat alleen maar, hoe en waarin is getest. Alle eventuele problemen, ook die met betrekking tot zoomen, lettergroottes, toegankelijkheid, uitstaan van JavaScript en/of css, enzovoort staan iets hieronder bij Bekende problemen (en oplossingen). Het is belangrijk dat deel te lezen, want uit een test kan ook prima blijken dat iets totaal niet werkt!
Dit voorbeeld is getest op de volgende systemen:
Desktopcomputers
Windows 7 (1280 x 1024 px, resolution: 96 ppi):
Firefox, UC Browser, Google Chrome, Opera en Internet Explorer 11, in grotere en kleinere browservensters.
OS X 10.11.6 ('El Capitan') (1680 x 1050 px, resolution: 96: ppi, device-pixel-ratio: 1):
Firefox, Safari, Opera en Google Chrome, in grotere en kleinere browservensters.
Linux (Kubuntu 14.04 LTS, 'Trusty Tahr') (1280 x 1024 px, resolution: 96 ppi):
Firefox, Opera en Google Chrome, in grotere en kleinere browservensters.
Laptops
Windows 8.1 (1366 x 768 px, resolution: 96 ppi):
Bureaublad-versie: Firefox, UC Browser, Google Chrome, Opera en Internet Explorer 11, in grotere en kleinere browservensters.
Startscherm-versie: Internet Explorer 11.
Windows 10 (1600 x 900 px, resolution: 96 ppi):
Firefox, UC Browser, Google Chrome, Internet Explorer 11, Opera en Edge, in grotere en kleinere browservensters.
Tablets
iPad met iOS 9.3.5 (1024 x768 px, device-pixel-ratio: 1):
Safari, Chrome for iOS, UC Browser, Firefox (alle portret en landschap).
Opera Mini (Opera Turbo) portret en landschap.
iPad met iOS 11.2.6 (2048 x 1536 px, device-pixel-ratio: 2 ('retina'):
Safari, Chrome for iOS, Firefox (alle portret en landschap).
Opera Mini (Opera Turbo) portret en landschap.
Android 4.4.2 ('Kitkat') (1280 x 800 px, resolution: 96 ppi):
Android browser, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Android 4.4.2 ('Kitkat') (2560 x 1600 px, resolution: 192 ppi):
Android browser, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Android 6.0 ('Marshmallow') (1920 x 1200 px, resolution: 144 ppi):
Dolphin, Samsung Internet, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Android 7.0 ('Nougat') (1920 x 1200 px, resolution: 144 ppi):
Dolphin, Samsung Internet, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Smartphones
Windows 10 Mobile (1280 x 720 px, resolution: 192 ppi):
Edge en UC browser (portret en landschap).
Android 4.1.2 ('Jelly Bean') (800 x 480 px, resolution: 144 ppi):
Chrome, Android browser, UC Browser en Firefox (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Android 7.0 ('Nougat') (1280 x 720 px, resolution: 192 ppi):
Dolphin, Samsung Internet, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Er is op de aan het begin van dit hoofdstukje genoemde controledatum getest in de meest recente versie van de browser, die op het betreffende besturingssysteem kon draaien. Het aantal geteste browsers en systemen is al tamelijk fors, en als ook nog rekening gehouden moet worden met (zwaar) verouderde browsers, is het gewoon niet meer te doen. Surfen met een verouderde browser is trouwens vragen om ellende, want updates van browsers hebben heel vaak met beveiligingsproblemen te maken.
In- en uitzoomen en – voor zover de browser dat kan – een kleinere en grotere letter zijn ook getest. Er is ingezoomd en vergroot tot zover de browser kan, maar niet verder dan 200%.
Er is getest met behulp van muis en toetsenbord, behalve op de iPad, Android, Windows Phone en Windows 10 Mobile, waar een touchscreen is gebruikt. Op Windows 8.1 en 10 is getest met een touchscreen, met een combinatie van toetsenbord en touchpad, en met een combinatie van toetsenbord en muis.
Als JavaScript is gebruikt, is op de desktop ook getest zonder JavaScript. (Op iOS, Android en Windows 10 Mobile is niet getest zonder JavaScript, omdat je JavaScript in een toenemend aantal mobiele browsers niet uit kunt zetten. Bovendien is een mobiel apparaat zonder JavaScript niet veel meer dan een duur en groot uitgevallen horloge.) Ook is getest zonder css en - als afbeeldingen worden gebruikt - zonder afbeeldingen.
Schermlezers en dergelijke
Naast deze 'gewone' browsers is ook getest in Lynx, WebbIE, NVDA, TalkBack, VoiceOver, ChromeVox en Verteller.
Lynx is een browser die alleen tekst laat zien en geen css gebruikt. Er is getest op Linux.
WebbIE is een browser die gericht is op mensen met een handicap. Er is getest op Windows 7.
NVDA is een schermlezer, zoals die door blinden wordt gebruikt. Er is getest op Windows 7 en Windows 10 in combinatie met Firefox.
TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome op Android 4.4,2, 6.0 en 7.0.
VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS (9.3.5 en 11.0.2) en OS X 10.11.6.
ChromeVox is een schermlezer in de vorm van een extensie bij Google Chrome. Er is getest op een systeem met Kubuntu Linux 14.04.
Verteller (Narrator) is een in Windows 10 ingebouwde schermlezer. Er is getest in combinatie met Edge.
Als het voorbeeld in deze programma's toegankelijk is, zou het in principe toegankelijk moeten zijn in alle aangepaste browsers en dergelijke. En dus ook voor zoekmachines, want een zoekmachine is redelijk vergelijkbaar met een blinde.
Eventuele problemen in schermlezers (en eventuele aanpassingen om die te voorkomen) staan iets hieronder bij Bekende problemen (en oplossingen).
Alleen op de hierboven genoemde systemen en browsers is getest. Er is dus niet getest op bijvoorbeeld 'n Blackberry. De kans is (heel erg) groot dat dit voorbeeld niet (volledig) werkt op niet-geteste systemen en apparaten. Om het wel (volledig) werkend te krijgen, zul je vaak (kleine) wijzigingen en/of (kleine) aanvullingen moeten aanbrengen, bijvoorbeeld met JavaScript.
Er is ook geen enkele garantie dat iets werkt in een andere tablet of smartphone dan hierboven genoemd, omdat fabrikanten in principe de software kunnen veranderen. Dit is anders dan op de desktop, waar browsers altijd (vrijwel) hetzelfde werken, zelfs op verschillende besturingssystemen. Iets wat in Android browser werkt, zal in de regel overal werken in die browser, maar een garantie is er niet. De enige garantie is het daadwerkelijk testen op een fysiek apparaat. En aangezien er duizenden mobiele apparaten zijn, is daar eigenlijk geen beginnen aan.
De html is gevalideerd met de validator van w3c, de css ook. Als om een of andere reden niet volledig gevalideerd kon worden, wordt dat bij Bekende problemen (en oplossingen) vermeld.
Nieuwe browsers worden pas getest, als ze uit het bèta-stadium zijn, omdat er anders 'n redelijke kans is dat je tegen 'n bug zit te vechten, die voor de uiteindelijke versie nog gerepareerd wordt. Dit voorbeeld is alleen getest in de hierboven met name genoemde browsers. Vragen over niet-geteste browsers kunnen niet worden beantwoord, en het melden van fouten in niet-geteste browsers heeft ook geen enkel nut. (Melden van fouten, problemen, enzovoort in wel geteste browsers: graag!)
Bekende problemen (en oplossingen)
Waarop en hoe is getest, kun je gelijk hierboven vinden bij Getest in.
Als je hieronder geen oplossing vindt voor een probleem dat met dit voorbeeld te maken heeft, kun je op het forum proberen een oplossing te vinden voor je probleem. Om forumspam te voorkomen, moet je je helaas wel registreren, voordat je op het forum een probleem kunt aankaarten.
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 bij toegankelijkheid aanpassingen en problemen bij elkaar.
Voor zover van toepassing wordt eerst het ontbreken van JavaScript, css en/of afbeeldingen besproken. Vervolgens problemen en aanpassingen met betrekking tot toegankelijkheid voor specifieke groepen bezoekers, zoals zoomen en andere lettergrootte, Tab-toets, tekstbrowsers en schermlezers. Als laatste volgen algemene problemen in alle of in specifieke browsers.
Als in een onderdeel één of meer problemen wordt besproken, staat in een rood kadertje een korte samenvatting daarvan. Bij een onderwerp over toegankelijkheid zijn er soms geen problemen, maar alleen aanpassingen. In dat geval staat in een groen kadertje 'Geen problemen'.
Zonder JavaScript
Probleem: alles werkt, maar elke gevolgde link uit de inhoud wordt in de browsergeschiedenis opgeslagen.
Browsers slaan bezochte pagina's op in de browsergeschiedenis. Met behulp van de Terug‑ en Vooruit-toets, of met toetscombinaties als Alt+← en Alt+→, kan door deze geschiedenis worden gebladerd.
Niet alleen pagina's, maar ook bezochte ankers op een pagina worden in de geschiedenis opgeslagen. Als je in dit voorbeeld een link in de inhoudsopgave volgt, wordt ook het bij die link horende anker opgeslagen. Als je tweehonderd links in de inhoudsopgave aanklikt en dan terug bladert door de geschiedenis, kom je al de bij die tweehonderd links horende ankers in omgekeerde volgorde tegen. Pas daarna kom je bij de pagina, waar je vandaan kwam, voordat je dit voorbeeld bezocht.
Zoiets kan handig zijn, omdat je zo de leesgeschiedenis van de pagina weer kunt terughalen. Maar bij ruim tweehonderd links naar alleen artikelen lijkt dit niet echt 'n fantastisch hulpmiddel.
Daarom wordt met behulp van JavaScript voorkomen dat links binnen de pagina worden opgeslagen in de browsergeschiedenis. Alle links naar een andere pagina worden gewoon opgeslagen, maar links naar ankers binnen de pagina met het voorbeeld niet.
Als JavaScript uitstaat, werkt alles nog gewoon. Alleen valt de browser dan terug op het standaardgedrag en worden ook de ankers in de geschiedenis opgeslagen.
In Android browser, Opera en UC browser op Android 4.1.2 en 4.4.2 werkt dit script niet. In deze browsers worden bezochte ankers altijd in de geschiedenis opgeslagen.
Als je dit script wilt testen, moet dat online gebeuren, of je moet zelf een server installeren. Omdat kwaadwillenden dit soort scripts zouden kunnen misbruiken, werkt het in steeds meer browsers niet meer offline. (Iets meer hierover is te vinden bij Dit script manipuleert...)
Zonder css
Geen problemen.
Zonder css werkt alles, maar het uiterlijk is – uiteraard – volkomen anders.
De inhoud staat niet naast, maar boven de tekst. Ook in smallere browservensters is de inhoud altijd zichtbaar. Het aankruisvakje om de inhoud in smallere vensters zichtbaar te maken is altijd zichtbaar, maar aan- of uitvinken heeft geen enkel effect.
Gebruikers Tab-toets
Probleem: in Firefox en Internet Explorer is de bestemming van de link niet altijd te zien.
- Bovenaan de pagina is een skip-link aangebracht, waarmee in één keer de hele inhoudsopgave gepasseerd kan worden. Deze link wordt alleen zichtbaar, als de Tab-toets wordt gebruikt.
- Binnen de inhoudsopgave is onder elk hoofdstuk een skip-link aangebracht, waarmee in één keer naar het volgende hoofdstuk in de inhoudsopgave kan worden gegaan. Deze links worden alleen zichtbaar, als de Tab-toets wordt gebruikt.
- Als een link uit de inhoudsopgave focus heeft, verkleurt de achtergrond van de link. (Het kadertje dat normaal genomen de focus aangeeft, is door de constructie van de links wat onduidelijk.) Ook wordt de tekst wat vetter, zodat het herkennen van de focus niet alleen van kleur afhankelijk is.
- Aan elk anker in de pagina (elk doel van 'n link in de inhoudsopgave) is het attribuut
tabindex="0"
aangegeven. Hierdoor kan, als een link is gevolgd, met de Tab-toets verder door de tekst worden gesprongen. De elementen dietabindex="0"
hebben gekregen komen overeen met de links in de inhoudsopgave, dus in feite spring je door de inhoudsopgave. Meer hierover is te vinden bij Tabindex en Tab-toets. -
Als met de Tab-toets door de inhoudsopgave wordt gelopen, wordt op een gegeven ogenblik de onderkant van het browservenster bereikt. Zodra dat gebeurt, wordt de inhoudsopgave door de browser naar boven geschoven, zodat de links zichtbaar blijven.
In Firefox en Internet Explorer levert dit een probleem op, want in die browsers schuift de inhoud maar 'n heel klein stukje omhoog: precies genoeg om de link met focus aan de onderkant van het browservenster te zetten. Dat is precies dezelfde plaats, waar de bestemming van de link wordt getoond. Hierdoor is de link zelf niet meer te zien. Alle andere browsers zetten de link met focus halverwege het venster, zodat dit niet speelt.
(Dit klopt eigenlijk niet helemaal: als de onderkant van het browservenster wordt bereikt, valt in alle browsers de link met focus weg onder de bestemming. Maar bij de volgende tab wordt de volgende link halverwege het venster gezet. Hierdoor is dit eigenlijk nauwelijks echt storend.)
Dit is in Firefox en Internet Explorer niet alleen in dit voorbeeld het geval, het werkt altijd zo in deze browsers. Helaas is hier niets aan te doen, want je kunt dit soort intern gedrag van de browser niet van buitenaf veranderen. Je zou de inhoudsopgave korter kunnen maken, maar dat is echt foeilelijk.
Internet Explorer heeft dit gedrag, Edge niet. Kennelijk heeft Microsoft dit dus veranderd. Ook voor Firefox is er dus nog hoop, zullen we maar optimistisch zeggen.
Bij hoveren met de muis gaat het trouwens wel goed, want dan wordt de bestemming aan de andere kant van het browservenster gezet, als anders de link afgedekt zou worden.
(In Firefox zat hier ooit de statusbar, waarin onder andere de bestemming werd getoond. Hierdoor stond de bestemming nooit over de eigenlijke pagina heen. In haar ijver om een volmaakte kloon van Google Chrome te worden, is deze statusbar helaas verwijderd. Het tonen van de bestemming is echter kennelijk (nog) niet gekloond van Google Chrome.)
Zoomen en andere lettergrootte
Probleem: bij zoomen kan op iOS niet worden gescrold in vensters minimaal 760 px breed.
Zoomen (vergroten en verkleinen) en een andere lettergrootte levert geen problemen op, behalve op het technisch superieure iOS.
Dit probleem heeft te maken met -webkit-overflow-scrolling
.
In browservensters smaller dan 760 px wordt dit alleen gebruikt bij nav
en levert het kennelijk geen problemen op. In vensters met een breedte van minstens 760 px wordt het ook gebruikt bij main
en levert het wel problemen op.
Zodra je in iOS inzoomt (vergroot), kan niet meer worden gescrold. Tekst die niet op het scherm staat op het moment dat je inzoomt, komt gewoon niet meer tevoorschijn.
Bij nav
en main
staat de regel -webkit-overflow-scrolling: touch;
. Zodra deze regel wordt verwijderd, speelt dit probleem niet meer. Het scrollen heeft dan echter de opmerkelijke soepelheid van een een tapdansende olifant met eksterogen en acute jicht. Normaal genomen blijft de tekst nog even doorscrollen, maar zonder deze regel stopt het scrollen onmiddellijk als het scherm wordt losgelaten. Wat niet echt lekker werkt.
Hier is geen oplossing voor: of zoomen kan niet, of scrollen loopt niet echt lekker.
Als je deze eigenschap gebruikt, moet je trouwens altijd heel grondig testen. Internet staat vol met verhalen over verdwijnende tekst en andere rampen bij gebruik van deze eigenschap.
Er zijn al jaren allerlei problemen met -webkit-overflow-scrolling
. En er worden ook al jaren oplossingen gegeven, die helaas geen van alle werkten in dit geval. Omdat Apple zich weer 'ns volledig in stilzwijgen hult, is de oorzaak van deze bug onbekend. En of 't ooit wordt gerepareerd, tja, er zijn al jaren problemen mee, dus... Omdat dit Apple is, is het trouwens mogelijk geen bug, maar 'n feature.
Omdat Apple op iOS alle browsers verplicht gebruik te maken van de superieure weergave-machine van Safari, speelt dit probleem in alle browsers op iOS.
Tekstbrowsers
Geen problemen.
In Lynx en WebbIE werkt alles, zoals het hoort te werken. Inclusief de skip-links.
Lynx toont ook het aankruisvakje om in smallere browservensters de inhoudsopgave te tonen. Werken doet dat verder niet, want de inhoudsopgave is gewoon altijd zichtbaar. WebbIE laat het aankruisvakje en de bijbehorende <label> niet zien, omdat WebbIE de WAI-ARIA-code aria-hidden
ondersteunt.
Schermlezers
Probleem: in TalkBack werken de links in de inhoud niet in browservensters smaller dan 760 px.
Probleem: in TalkBack werken de skip-links niet in browservensters minimaal 760 px breed.
-
In smallere browservensters wordt de inhoudsopgave getoond en verborgen met behulp van een <input type="checkbox"> (aankruisvakje). Deze <input> met bijbehorende <label> en dergelijke worden met behulp van de WAI-ARIA-code
aria-hidden="true"
voor schermlezers verborgen.In alle geteste schermlezers zijn alle links gewoon te gebruiken, ook de skip-links. Alleen in TalkBack werken de links niet, omdat in TalkBack minimaal 1 x 1 px van een link, knop, en dergelijke op het scherm moet staan. Bovendien mag die pixel niet worden verborgen onder een andere element. In dit voorbeeld zouden meer dan tweehonderd links elk één pixel ergens moeten hebben staan. Als iemand per ongeluk zo'n pixel aan zou raken, wordt de link gevolgd. Dat gaat dus niet.
Je zou het aankruisvakje om de inhoudsopgave te tonen kunnen laten werken in schermlezers, maar dat helpt weinig. Als de links pas later zichtbaar worden, werken ze grotendeels niet in TalkBack. (Wanneer en waarom ze wel of niet werken, is één van de grote kosmische raadselen.)
Je kunt in TalkBack nog steeds naar <main> gaan en daar de <h>'s volgen.
(Dit speelt alleen in browservensters smaller dan 760 px, want in bredere vensters is de inhoudsopgave gewoon zichtbaar. Hopelijk wordt dit ooit opgelost, want er wordt al jaren over geklaagd.)
- In TalkBack werken in browservensters met een breedte van minstens 760 px de skip-links binnen de inhoudsopgave in de <nav> niet. (Met deze skip-links kan in de inhoudsopgave in één keer een heel hoofdstuk worden overgeslagen.) Dit heeft dezelfde oorzaak als hierboven staat beschreven voor smallere vensters: er moet minstens 1 x 1 px van de link op het scherm staan.
- De hele inhoudsopgave staat in een <ul>, die weer in een <nav> staat, zodat deze voor schermlezers snel is te passeren.
- Bovenin de <nav> staat een <h2> met 'Inhoudsopgave grondwet', zodat duidelijk is waarvoor de <nav> dient. Deze <h2> is verder onzichtbaar, alleen schermlezers 'zien' de <h2>.
-
Alle artikelen zijn ondergebracht in <h>'s. Schermlezers kunnen dus van <h> naar <h> springen. Elke link in de inhoudsopgave heeft een bijbehorende <h>, dus eigenlijk hebben schermlezers die hele inhoudsopgave niet echt nodig.
De <h>'s zijn ingedeeld van belangrijk naar minder belangrijk. Alleen de <h1> met de titel staat niet helemaal goed, want die staat onder de <h2> in de <nav>. Het zou hier wat onlogisch zijn van de <h2> in de <nav> de belangrijkste kopregel te maken.
Opera Mini op Android in vensters smaller dan 760 px
De inhoudsopgave kan niet terug naar boven worden gescrold
Dit speelt in versie 4.1.2 en in versie 7.0 (andere versies zijn niet getest), en alleen in browservensters smaller dan 760 px.
Als de <nav> met de inhoudsopgave naar beneden wordt gescrold, kan de <nav> niet meer terug naar boven worden gescrold. Althans: als je de <nav> scrolt, blijft deze staan, maar de onder de <nav> zittende <main> met de tekst scrolt wel. Pas als de <main> helemaal bovenaan staat, kan de <nav> met de inhoudsopgave weer naar boven worden gescrold.
Een oplossing hiervoor is niet gevonden. Het is op het ogenblik zelfs onduidelijk of Opera Mini position: fixed;
(wat is gebruikt om de <nav> in die smallere vensters vast te zetten) wel of niet ondersteunt. Volgens caniuse.com zou Opera Mini dit niet ondersteunen, maar volgens nogal wat andere sites wel. Opera zelf heeft geen overzicht van wat wel en niet wordt ondersteund. Ook heeft Opera Mini geen manier om enigszins fatsoenlijk naar bugs te kunnen zoeken.
Dit maakt het feitelijk onmogelijk om naar een oplossing te zoeken, want misschien wordt het gewoon helemaal niet ondersteund, of misschien is het 'n bekende bug.
Testen met @supports
op ondersteuning voor position: fixed;
kan in dit geval ook niet worden gebruikt, omdat een aantal oudere browsers position: fixed;
wel ondersteunt, maar @supports
niet. css speciaal voor Opera Mini zou daardoor ook voor deze browsers werken, terwijl het voor die browsers niet nodig is. Bovendien zijn er ook verhalen dat ook heel oude versies van Opera Mini ten onrechte beweren dat ze position: fixed;
ondersteunen, als je @supports
gebruikt.
Sommige versies van Android browser, Opera Mobile en UC browser op Android 4.1.2 en 4.4.2
Bij gebruik van de Terug-toets van de browser worden alle bezochte ankers nogmaals bezocht
Als je tweehonderd links in de inhoudsopgave hebt gevolgd en je gebruikt de Terug-toets van de browser, worden eerst de tweehonderd bij die links horende ankers in omgekeerde volgorde weergegeven.
Dit is standaardgedrag van elke browser, dat meestal erg handig is. Maar hier niet. In alle andere browsers wordt dit standaardgedrag voorkomen met behulp van JavaScript. In de genoemde browsers werkt dit script niet altijd. Omdat fabrikanten van smartphones en tablets zelf Android kunnen aanpassen, is niet precies te zeggen, in welke versies zich dit voordoet.
Omdat het hier om tamelijk oude versies van Android gaat, is hier niet verder naar gekeken. In Firefox en Chrome (en waarschijnlijk in nog veel meer op Chrome gebaseerde browsers) op deze versies van Android werkt het script wel. Mensen die met alle geweld één van de genoemde drie browsers willen gebruiken, moeten dit dan maar zien als een meditatieve oefening.
Sommige versies van Android browser en Opera op Android 4.1.2 en Android 4.4.2 in vensters smaller dan 760 px
Er wordt in de balk bovenaan niet altijd een gradiënt getoond
Soms wordt in de balk bovenin geen gradiënt, maar een effen witte kleur getoond. Omdat fabrikanten van smartphones en tablets zelf Android kunnen aanpassen, is niet precies te zeggen, in welke versies zich dit voordoet.
Deze browsers hebben een oudere syntax nodig. Als je gelijk voor de regel voor de gradiënt bij #toon-menu de volgende regel invoegt:
background: -webkit-linear-gradient(top, #fff 0%, #bbb 100%);
hebben ook deze browsers een gradiënt. Omdat deze browsers snel aan het verdwijnen zijn, is dat in dit voorbeeld niet gedaan.
Alle browsers als offline wordt gewerkt
Alle bezochte artikelen worden in de geschiedenis opgeslagen
Met behulp van JavaScript wordt voorkomen dat alle bezochte artikelen in de geschiedenis van de browser worden opgeslagen. Hiermee wordt voorkomen dat je, bij gebruik van de Terug-toets, de Vooruit-toets of een toetscombinatie als alt+← of alt+→, eerst weer door alle bezochte artikelen gaat, voordat je 'n vorige of volgende pagina bereikt.
Browsers worden steeds strenger beveiligd tegen misbruik. Dit script zou misbruikt kunnen worden, daarom werkt het in veel browsers alleen online of op een zelf geïnstalleerde server. Als je het script wilt testen, kan dat alleen online of op een zelf geïnstalleerde server betrouwbaar. Bij testen op de desktop is er een grote kans dat dit script niet werkt.
Een iets uitgebreider verhaal hierover is te vinden bij Dit script manipuleert...
Wijzigingen
Alleen grotere wijzigingen worden hier vermeld, geen dingen als een link die is geüpdatet.
:
Nieuw opgenomen
2 februari 2009:
:focus
en :active
werken nu hetzelfde als :hover
bij de links in de linkerkolom.
10 april 2009:
Tekst aangepast aan de nieuw verschenen Internet Explorer 8. De code is niet veranderd.
11 oktober 2010:
Kleine wijzigingen in de tekst aangebracht, vooral over toegankelijkheid.
11 maart 2018:
- De code en de tekst zijn grotendeels herschreven. Alleen de belangrijkste wijzigingen staan hieronder.
- Code omgezet van xhtml 1.0 naar html5.
- Alles voor Internet Explorer 10 en eerder verwijderd, zoals
:active
. - In browservensters smaller dan 760 px wordt de inhoudsopgave alleen op verzoek geopend.
- Inhoudsopgave en tekst worden maximaal 800 px breed, waardoor te lange en daardoor slecht leesbare zinnen worden voorkomen.
- Selectors wat korter gemaakt, voor zover dat zonder gevaar kon.
- 230 keer <span class="lid-letter"> verwijderd en vervangen door
::first-letter
in de css (dit werkt inmiddels in alle browsers probleemloos). - Klein stukje JavaScript toegevoegd om te voorkomen dat elk bezocht artikel in de geschiedenis van de browser wordt opgeslagen.
- Bezochte links in de inhoudsopgave krijgen nu rechts een groen streepje.
- Links in de inhoudsopgave groter gemaakt, zodat ze niet alleen voor kleutervingers geschikt zijn. (Een kleuter die de grondwet leest lijkt me 'n aanduiding voor een ernstig probleem, maar dat terzijde.)
- Contrast in de inhoudsopgave verbeterd, zodat het nu aan de richtlijnen voor toegankelijkheid voldoet. (Ja, ja, dat was inderdaad slordig in eerdere versies...)
- Bij alle links in de inhoudsopgave de title weggehaald. (Zoals veel sitebouwers dacht ook ik dat deze handig waren voor schermlezers, maar het tegendeel is waar: title én tekst uit de link werden voorgelezen, en die waren hetzelfde, dus je hoorde alles twee keer.)
- Voor gebruikers van de Tab-toets elk anker (elk doel van 'n link in de inhoudsopgave)
tabindex="0"
gegeven, waardoor alle browsers nu voor gebruikers van de Tab-toets op dezelfde manier werken. Bovendien kan nu met de Tab-toets door de tekst worden getabd. Meer hierover is te vinden bij Tabindex en Tab-toets. - Voor gebruikers van de Tab-toets bovenaan de pagina een skip-link aangebracht, waarmee in één keer de hele inhoudsopgave kan worden gepasseerd.
- Voor gebruikers van de Tab-toets in de inhoudsopgave onder elk hoofdstuk een skip-link aangebracht, waarmee in één keer alle links voor dat hoofdstuk in de inhoudsopgave kunnen worden gepasseerd.
- Inhoudsopgave staat in de html niet meer onder, maar boven de tekst. Op het scherm staat de inhoudsopgave ook voor de tekst (in browservensters minimaal 760 px breed). Schermlezers kunnen tegenwoordig die hele inhoud in één keer overslaan, dus dit was niet meer nodig.
- Aantal nieuwe hoofdstukken, vooral over mobiel en toegankelijkheid.
- Tig kleinere wijzigingen in de tekst.
- Grondwetswijzigingen uit 2017 in de tekst aangebracht. (Hopelijk allemaal, maar dat is niet zeker, want je zoekt je het lazarus op die site.)
Inhoud van de download en licenties
De inhoud van deze download kan vrij worden gebruikt, met drie beperkingen:
* Sommige onderdelen die van 'n andere site of zo afkomstig zijn, vallen mogelijk onder een of andere licentie. Dat is hieronder bij het betreffende onderdeel te vinden.
* Je gebruikt het materiaal uit deze download volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte code en dergelijke zitten. Voor eventuele schade die door gebruik van materiaal uit deze download ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.
* Dit voorbeeld (en de bijbehorende uitleg en dergelijke) wordt regelmatig bijgewerkt. Het is daarom niet toegestaan dit voorbeeld (en de bijbehorende uitleg en dergelijke) op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat voorbeeld, uitleg, en dergelijke afkomstig zijn van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.
Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.
tekst-029-dl.html: de pagina met het voorbeeld.
tekst-029.pdf: deze uitleg (aangepast aan de inhoud van de download).
tekst-029-inhoud-download-en-licenties.txt: een kopie van de tekst onder dit kopje (Inhoud van de download en licenties).
029-css-dl:
tekst-029-dl.css: stylesheet voor tekst-029-dl.html.
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.
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.
<!DOCTYPE html>
Een document moet met een doctype beginnen om weergaveverschillen tussen browsers te voorkomen. Zonder doctype is de kans op verschillende (en soms volkomen verkeerde) weergave tussen verschillende browsers heel erg groot.
Geldige doctypes vind je op www.w3.org/QA/2002/04/valid-dtd-list.
Gebruik het volledige doctype, inclusief de eventuele url, anders werkt het niet goed.
Het hier gebruikte doctype is dat van html5. Dit kan zonder enig probleem worden gebruikt: het werkt zelfs in Internet Explorer 6.
<html lang="nl">
De toevoeging lang="nl"
bij <html> geeft aan dat de pagina in het Nederlands is. De taal is van belang voor schermlezers, automatisch afbreken, automatisch genereren van aanhalingstekens, juist gebruik van decimale punt of komma, en dergelijke.
<meta charset="utf-8">
Zorgt dat de browser letters met accenten en dergelijke goed kan weergeven.
utf-8 is de beste charset (tekenset), omdat deze alle talen van de wereld (en nog heel veel andere extra tekens) bestrijkt, maar toch niet meer ruimte inneemt voor de code, dan nodig is. Als je utf-8 gebruikt, hoef je veel minder entiteiten (ä
en dergelijke) te gebruiken, maar kun je bijvoorbeeld gewoon ä gebruiken.
Deze regel moet zo hoog mogelijk komen te staan, als eerste regel binnen de <head>, omdat hij anders door sommige browsers niet wordt gelezen.
In html5 hoeft deze regel niet langer te zijn, dan wat hier staat.
<meta name="viewport" content="width=device-width, initial-scale=1">
Mobiele apparaten variëren enorm in breedte. En dat is een probleem. Sites waren, in ieder geval tot voor kort, gemaakt voor desktopbrowsers. En die hebben, in vergelijking met bijvoorbeeld een smartphone, heel brede browservensters. Hoe moet je op 'n smartphone een pagina weergeven, die is gemaakt voor de breedte van een desktop? Je kunt natuurlijk wachten tot álle sites zijn omgebouwd voor smartphones, tablets, enzovoort, maar dan moet je waarschijnlijk heel erg lang wachten.
Mobiele browsers gokken erop dat een pagina een bepaalde breedte heeft. Safari voor mobiel bijvoorbeeld gaat ervan uit dat een pagina 980 px breed is. De pagina wordt vervolgens zoveel versmald dat hij binnen het venster van het apparaat past. Op een iPhone wordt de pagina dus veel smaller dan op een iPad. Vervolgens kan de gebruiker inzoomen op het deel van de pagina dat hij of zij wil zien.
Dit betekent ook dat bij het openen van de pagina de tekst meestal heel erg klein wordt weergegeven. (Meestal, want niet alle browsers en apparaten doen het op dezelfde manier.) Niet erg fraai, maar bedenk maar 'ns 'n betere oplossing voor bestaande sites.
Nieuwe sites of pagina's kunnen echter wel rekening houden met de veel kleinere vensters van mobiele apparaten. Op deze pagina bijvoorbeeld wordt in browservensters smaller dan 760 px de inhoudsopgave 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.
Een iPad in portretstand bijvoorbeeld is 768 px breed. De kreet width=device-width
zegt tegen de mobiele browser dat de breedte van de weer te geven pagina gelijk is aan de breedte van het apparaat. Voor een iPad in portretstand dus 768 px.
Er staat nog een tweede deel in de tag: initial-scale=1
. Sommige mobiele apparaten zoomen een pagina gelijk in of uit. Ook weer in een poging behulpzaam te zijn. Ook dat is hier niet nodig. Er is ook een instructie om zoomen helemaal onmogelijk te maken, maar die gebruik ik niet. De bezoeker kan zelf nog gewoon zoomen, wat belangrijk is voor mensen die wat slechter zien.
<link rel="stylesheet" href="029-css-dl/tekst-029-dl.css">
Dit is een koppeling naar een externe stylesheet (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 de stylesheet aanpassen aan de naam en plaats, waar je eigen stylesheet staat.
Voordeel van een externe stylesheet 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 enkele stylesheet 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 externe stylesheet 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.
In dit voorbeeld heeft een extern stylesheet eigenlijk geen nut, omdat er maar één pagina is die dit stylesheet gebruikt. In dit geval kun je de css beter in de <head> van de html-pagina zelf zetten. Voor de omvang maakt het hier niets uit, want de css wordt hoe dan ook altijd precies één keer gedownload, en nooit vaker. Voor het onderhoud maakt het ook geen verschil, want ook hier hoef je de css maar op één plaats te wijzigen. Maar het scheelt wel een extra aanroep naar de server, omdat geen apart stylesheet hoeft te worden gedownload.
Dat opnemen in de <head> gaat heel simpel: je kopieert gewoon het hele stylesheet en zet die bovenin de <head>, tussen <style> en </style>:
<style>
body {color: black;}
(...) rest van de css (...)
div {color: red;}
</style>
Maar zodra een stylesheet op meerdere pagina's wordt gebruikt, wat meestal het geval zal zijn, is een extern stylesheet beter.
(De reden dat er toch een extern stylesheet is, terwijl hierboven omstandig wordt beweerd dat dat in dit voorbeeld eigenlijk geen nut heeft: overzichtelijkheid. Nu kun je html en css los van elkaar bekijken.)
<a class="skippy" href="#content">Skip inhoudsopgave grondwet</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 de inhoudsopgave staan meer dan tweehonderd links. Voordat de eigenlijke tekst wordt bereikt, moet de gebruiker eerst door al die links heen. Voor elke link moet één keer de Tab-toets worden ingedrukt. 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 en 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 links buiten het scherm geparkeerd en daardoor onzichtbaar. Zodra de link focus heeft, wordt deze met behulp van css op het scherm geplaatst. 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 de meeste schermlezers werkt deze link ook. Maar schermlezers hebben ook andere manieren om een serie links te passeren.)
<input id="checkbox-voor-smal" type="checkbox" aria-hidden="true">
<label id="toon-menu" for="checkbox-voor-smal" aria-hidden="true">Inhoudsopgave</label>
In browservensters smaller dan 760 px is de inhoudsopgave links buiten het scherm geplaatst, waardoor deze onzichtbaar is. Pas na aanklikken of aanraken van een knop wordt de inhoudsopgave getoond.
Voor schermlezers maakt het niets uit dat de inhoudsopgave links buiten het scherm staat: het wordt gewoon voorgelezen. Daarom is de inhoudsopgave ook niet verborgen met display: none;
of visibility: hidden;
. Als de inhoudsopgave daarmee zou worden verborgen, zou het ook voor schermlezers onzichtbaar zijn. Maar dat het buiten het scherm staat, maakt niets uit.
Met behulp van de <input> in de eerste regel hierboven kan de inhoudsopgave worden geopend. Aan deze <input> hebben schermlezers niets, het werkt alleen maar verwarrend. Daarom worden de <input> en de bij de <input> horende <label> voor schermlezers verborgen met de WAI-ARIA-code aria-hidden="true"
.
Vaak wordt een <input> binnen de bijbehorende <label> gezet:
<label>Inhoudsopgave<input type="checkbox"></label>
Dat heeft een aantal voordelen. Hier kan dat echter niet, omdat de <input> in een aantal selectors met behulp van ~
en +
is 'gekoppeld' aan latere elementen. Als de <input> binnen de <label> zou staan, werken ~
en +
niet.
(De schermlezer TalkBack leest de links wel voor, maar ze werken niet. Meer hierover is te vinden bij Bekende problemen (en oplossingen) onder het kopje Schermlezers.)
<h2>Inhoudsopgave grondwet</h2>
Mensen die de inhoudsopgave kunnen zien, zullen gelijk herkennen, waar die voor is. Maar voor gebruikers van schermlezers is dat niet duidelijk. De <nav>, waarin de inhoudsopgave staat, geeft aan dat het om een serie links om te navigeren gaat, maar niet om wat voor soort links.
Daarom wordt deze < h2> bovenaan de <nav> gezet. Omdat de <h2> links buiten het scherm wordt geparkeerd, is hij onzichtbaar. Maar schermlezers lezen hem gewoon voor.
In theorie zou je hetzelfde moeten kunnen doen met:
<nav aria-label="Inhoudsopgave grondwet">
De WAI-ARIA-code tekst achter aria-label
is onzichtbaar, maar wordt wel voorgelezen door schermlezers. Althans: dat zou zo moeten zijn. Veel schermlezers negeren dit attribuut echter, als het bij <nav> wordt gebruikt. Daardoor is het in de praktijk op dit moment nog volstrekt onbruikbaar.
Deze <h2> is de eerste <h> op de pagina. Normaal genomen staan <h>'s van belangrijk naar minder belangrijk, van <h1> naar <h6>. Bovenaan staat dan de belangrijkste kop, de <h1>. Dat is handig voor schermlezers, die snel naar kopregels van een bepaald niveau kunnen springen. Als de titel van de pagina in een <h1> staat, de titels van hoofdstukjes in een <h2>, van paragrafen in een <h3>, enzovoort, is dat heel overzichtelijk.
Hier echter is de eerste kopregel in de html niet de titel van de pagina of iets soortgelijks, maar de omschrijving van de inhoudsopgave. Daarom is het in dit geval beter die eerste kopregel toch in een <h2> te zetten. De <h1> met de kopregel met de echte titel volgt daar dan op.
<li class="li-skippy"><a class="skippy" href="#l-hs-2">Skip links naar hoofdstuk 1</a></li>
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 de inhoudsopgave staan meer dan tweehonderd links. Voordat de eigenlijke tekst wordt bereikt, moet de gebruiker eerst door al die links heen. Voor elke link moet één keer de Tab-toets worden ingedrukt. Daarom is bovenaan de pagina een zogenaamde skip-link geplaatst, waarmee in één keer de hele inhoudsopgave kan worden gepasseerd.
Dat is mooi, maar niet als je naar 'n additioneel artikel onderaan wilt, want dan moet je nog steeds zo'n 170 keer de Tab-toets indrukken.
Daarom is onder elke link naar een hoofdstuk in de inhoudsopgave nog een skip-link gezet. Deze staat normaal genomen links buiten het scherm, maar wordt zichtbaar als de Tab-toets deze bereikt. Door dan op Enter te drukken, worden alle links van dat hoofdstuk in één keer gepasseerd. Nu kunnen de additionele artikelen met acht tabs worden bereikt.
Ook schermlezers kunnen van deze links gebruikmaken, behalve TalkBack. Deze schermlezer leest de links wel voor, maar ze werken niet. Meer hierover is te vinden bij Bekende problemen (en oplossingen) onder het kopje Schermlezers.)
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.)
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.
Technisch gezien is er geen enkel bezwaar om de css in de stylesheet allemaal achter elkaar op één regel te zetten:
div#header-buiten {position: absolute; right: 16px; width: 100%; height: 120px; background: yellow;} div p {margin-left 16px; height: 120px; text-align: center;}
Maar als je dat doet, garandeer ik je hele grote problemen, omdat het volstrekt onoverzichtelijk is. Beter is het om de css netjes in te laten springen:
div#header-buiten {
position: absolute;
right: 16px;
width: 100%;
height: 120px;
background: yellow;
}
div p {
margin-left: 16px;
height: 120px;
text-align: center;
}
Hiernaast is het heel belangrijk voldoende commentaar (uitleg) in de stylesheet te schrijven. Op dit moment weet je waarschijnlijk (hopelijk...), waarom je iets doet. Maar over vijf jaar kan dat volstrekt onduidelijk zijn. Op deze site vind je nauwelijks commentaar in de stylesheets, maar dat heeft een simpele reden: deze uitleg is in feite één groot commentaar.
Op internet zelf is het goed, als de stylesheet juist zo klein mogelijk is. Dus voor het uploaden kun je normaal genomen het beste het commentaar weer verwijderen. Veel mensen halen zelfs alles wat overbodig is weg, voordat ze de stylesheet uploaden. Inspringingen bijvoorbeeld zijn voor mensen handig, een computer heeft ze niet nodig.
Je hebt dan eigenlijk twee stylesheets. De uitgebreide versie waarin je dingen uitprobeert, verandert, enzovoort, met commentaar, inspringingen, en dergelijke. Dat is de mensvriendelijke versie. Daarnaast is er dan een stylesheet die je op de echte site gebruikt: een gecomprimeerde versie.
Dat comprimeren kun je met de hand doen, maar er bestaan ook hulpmiddelen voor. Op de pagina met links kun je onder Gereedschap → Snelheid, testen, gzip, comprimeren links naar sites vinden, waar je bestanden kunt comprimeren.
(Stylesheets op deze site zijn niet gecomprimeerd. Omdat het vaak juist om de css gaat, kunnen mensen dan zonder al te veel moeite de css bekijken.)
css voor alle vensters
/* tekst-029-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.
@-webkit-keyframes bugfix-0 {from {padding-left: 0;} to {padding-left: 0;}}
Bij nav wordt een animatie toegevoegd om een bug in oudere versies van Android browser en Opera Mini op Android 4.1.2 op te lossen. Die animatie wordt hier opgegeven.
Op een aantal plaatsen wordt in een selector gebruik gemaakt van het teken ~
(de 'general sibling'-selector) om in browservensters smaller dan 760 px de inhoudsopgave te tonen of te verbergen. De genoemde browsers tonen de inhoudsopgave niet, omdat ze problemen hebben met de ~
. Door het toevoegen van een animatie werkt het toch zoals bedoeld.
Als je nou denkt dat hier niets wordt uitgevoerd, omdat de padding links van 0 px in een padding links van 0 px wordt veranderd, dan heb je helemaal gelijk. Toch neutraliseert deze flauwekul de bug. De padding links is 0 px, omdat bij <nav> helemaal geen padding is opgegeven. In dat geval heeft de padding de standaardwaarde van 0. Zou de padding links bij <nav> wel een waarde hebben, dan zou je hier die waarde gebruiken.
Bij nav, waar de animatie daadwerkelijk wordt gebruikt, staat bij -webkit-animation
het sleutelwoord infinite:
de animatie wordt eindeloos herhaald. Verder staat daar nog de waarde 1s
1 seconde. Dat is de tijdsduur van de animatie. Door hier een tamelijk lange waarde voor te nemen, wordt de animatie niet al te vaak afgespeeld. (Voor zover je hier van 'afspelen' kan spreken, want er gebeurt gewoon helemaal niets.)
Omdat er in feite helemaal niets gebeurt bij deze animatie, wordt de pagina ook niet opnieuw opgemaakt door de browser. Kennelijk werkt dit als 'n soort waakhond: áls er iets is veranderd, wordt het weergegeven. Anders gebeurt er niets.
Normaal genomen is het een bijzonder slecht idee css te gebruiken voor slechts één weergave-machine: webkit. Maar in dit geval is dit terecht, want de bug zit alleen in op webkit gebaseerde browsers. Het heeft dus geen zin om Internet Explorer of Firefox ook met deze ongein te belasten.
Waarom dit alleen in webkit-browsers werkt, staat bij De voorvoegsels -moz-, -ms- en -webkit-.
body
Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.
background: #ff9;
Achtergrondkleurtje.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
font-family: Arial Helvetica, sans-serif;
Als Arial is geïnstalleerd op de machine van de bezoeker, wordt deze gebruikt, anders Helvetica. Als die ook niet wordt gevonden, wordt in ieder geval een schreefloze letter (zonder dwarsstreepjes) gebruikt.
margin: 0; padding: 0;
Slim om te doen vanwege verschillen tussen browsers.
.skippy, .li-skippy .skippy

De elementen met class="skippy". Dit zijn de skip-link bovenaan de pagina en de skip-links binnen de inhoudsopgave.
Hiernaast staat de skip-link bovenaan de pagina afgebeeld. Deze link is natuurlijk foeilelijk, en dat is precies de bedoeling: nu valt hij goed op.
Al deze elementen zijn een <a> met class="skippy". In principe zou daarom alleen de selector voor de komma genoeg zijn. Maar verderop bij li a:hover, li a:focus wordt css opgegeven voor alle <a>'s binnen een <li>, waardoor het uiterlijk van de <a>'s verandert bij hoveren over of focus van 'n <a> in de inhoudsopgave.
Ook de skip-links in de inhoudsopgave zijn <a>'s binnen een <li>, dus ook deze zouden daardoor van uiterlijk veranderen. Dat is niet de bedoeling. Daarom staat hier achter de komma nog een tweede selector: .li-skippy .skippy
: elementen met class="skippy" binnen een element met class="li-skippy". Skip-links in de inhoudsopgave hebben class "skippy" en staan binnen een <li> met class="li-skippy".
Normaal genomen wordt css uitgevoerd in de volgorde, waarin het in de stylesheet staat. Maar dat kan worden overruled door 'n eerdere selector mee specificiteit, meer 'gewicht', te geven.
Voor specificiteit worden alle selectors apart bekeken. De verderop staande selectors li a:hover
en li a:focus
moeten apart worden bekeken, ze worden niet 'bij elkaar opgeteld'. In beide selectors zitten twee elementen: li
en a
. Daarnaast zit in elke selector nog een pseudo-class: :hover
en :focus
. Voor wat betreft specificiteit heeft een pseudo-class evenveel gewicht als een gewone class. De specificiteit van beide selectors is dus twee elementen en 1 class.
De hier gebruikte selector .li-skippy .skippy
bestaat uit twee classes: .li-skippy
en .skippy
.
We hebben dus hier een selector met twee classes, en verderop een selector met één element en één class. Een selector met meer classes heeft altijd meer specifiteit, meer 'gewicht', dan een selector met minder classes (als er geen id's aanwezig zijn). Oftewel: de hier gebruikte .li-skippy .skippy
heeft meer specificiteit dan de verderop gebruikte li a:hover
en li a:focus
. Hierdoor wordt toch de css van de selector hier gebruikt voor de skip-links, en niet die van de selectors verderop.
Als hier alleen .skippy
zou zijn gebruikt, zou maar één class aanwezig zijn. In dat geval zou de css van de selectors verderop worden gebruikt. Deze staan lager in de stylesheet, én ze hebben meer specificiteit: één element en één class.
Hetzelfde verhaal geldt voor een andere selector verderop, li a: alle <a>'s binnen een <li>. Ook skip-links in de inhoudsopgave vallen onder deze selector. In li a
zitten alleen twee elementen, daarom heeft de selector .li-skippy .skippy
met z'n twee classes meer specificiteit en 'wint' deze dus van li a
.
De skip-link bovenaan de pagina is grotendeels hetzelfde als de skip-links in de inhoudsopgave, daarom wordt hier voor alle skip-links css opgegeven. Hier iets onder bij .li-skippy .skippy worden dan voor de skip-links in de inhoudsopgave 'n paar dingen aangepast.
background: white;
Witte achtergrond.
color: black;
Normaal genomen krijgt de tekst in een link een afwijkende kleur. Dat is hier niet nodig.
width: 12em;
Breedte. De skip-link moet goed opvallen, zodat deze niet wordt gemist. Daarom wordt de skip-link heel breed gemaakt.
Als eenheid wordt de relatieve eenheid em
gebruikt, zodat de breedte mee verandert met een eventuele andere lettergrootte. Bij gebruik van een absolute eenheid zoals px
zou dat niet gebeuren. Zoomen kan wel altijd, ongeacht welke eenheid voor de breedte wordt gebruikt.
font-size: 2em;
Heel grote letter. Als eenheid wordt de relatieve eenheid em
gebruikt, omdat bij gebruik van een absolute eenheid zoals px
niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
line-height: 2em;
Regelhoogte.
Omdat verder geen hoogte is opgegeven voor het element, is dit tevens de hoogte van de skip-link.
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.
Tekst wordt normaal genomen automatisch halverwege de regelhoogte gezet, dus de tekst staat hierdoor gelijk verticaal gecentreerd.
text-align: center;
Tekst horizontaal centreren.
text-decoration: underline;
Standaard wordt tekst in een <a> onderstreept. Bij li a verderop wordt de onderstreping echter weggehaald. Ook de skip-links in de inhoudsopgave vallen onder de selector li a
. Daarom wordt hier expliciet opgegeven dat in de skip-links de onderstreping moet blijven staan.
Hoe het komt dat deze regel 'wint' van de lagere regel bij li a
wordt iets hierboven bij de selector beschreven.
border: red solid 3px;
Brede rode rand in het kader van opvallen.
position: absolute;
Om de skip-link op de juiste plaats neer te kunnen zetten.
Hier iets onder bij .li-skippy .skippy wordt dit voor de skip-links in de inhoudsopgave veranderd in position: fixed;
dus dit geldt alleen voor de skip-link bovenaan de pagina.
Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een andere positie dan 'static' heeft. Als die 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. Daardoor zijn eigenschappen als breedte niet te gebruiken. Door de <a> absoluut te positioneren, verandert de <a> in een soort blok-element en zijn dit soort eigenschappen wel te gebruiken.
top: 20px;
20 px vanaf de bovenkant neerzetten.
left: -20000px;
Ver links buiten het scherm parkeren. Pas als dat nodig is, wordt bij .skippy:focus de link binnen het scherm gezet en daarmee zichtbaar.
z-index: 50;
Door de hogere z-index staan deze links altijd bovenaan, ongeacht wat er verder op de pagina staat.
Een z-index werkt alleen in bepaalde omstandigheden. Een van die omstandigheden is een absolute of fixed positie. Die absolute positie is iets hierboven opgegeven, dus dat is geregeld.
(Voor de skip-links wordt dat gelijk hieronder veranderd in een fixed positie, maar ook dat zorgt ervoor dat een z-index werkt.)
.li-skippy .skippy
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.skippy, .li-skippy .skippy {background: white; color: black; width: 12em; font-size: 2em; line-height: 2em; text-align: center; text-decoration: underline; border: red solid 3px; position: absolute; top: 20px; left: -20000px; z-index: 50;}

De elementen met class="skippy" die binnen een element met class="li-skippy" staan. Dit zijn de skip-links binnen de inhoudsopgave.
De meeste css is iets hierboven bij .skippy, .li-skippy .skippy al opgegeven, samen met de css voor de skip-link bovenaan de pagina. Voor de skip-links binnen de inhoudsopgave worden hier alleen wat kleine wijzigingen opgegeven, omdat deze er iets anders uitzien dan de skip-link bovenaan de pagina.
width: 20em;
Omdat voor de breedte de eenheid em
is gebruikt, is de breedte gebaseerd op de lettergrootte van de skip-links. Bij een andere lettergrootte verandert de breedte mee met de lettergrootte. (Bij een vaste eenheid als px
zou dat niet gebeuren.)
Iets hierboven is bij .skippy, .li-skippy .skippy een lettergrootte van 2 em opgegeven. Maar een lettergrootte in em
wordt geërfd, is gebaseerd op de lettergrootte van de voorouders van het element.
De skip-links in de inhoudsopgave zijn nakomelingen van <nav>, waarin de hele inhoudsopgave gaat. Bij nav wordt de lettergrootte van <nav> verkleind tot 0,7 em. De voor de skip-links opgegeven lettergrootte van 2 em is gebaseerd op die 0,7 em. Als je het met de rest van de pagina vergelijkt is de feitelijke lettergrootte van de skip-links in de inhoudsopgave daardoor niet 2 keer de normale lettergrootte, maar 2 keer 0,7 keer de normale lettergrootte, oftewel: 1,4 em.
Voor de lettergrootte is dat prima, want de tekst van deze skip-links is wat lang. Als de bezoeker de lettergrootte zelf ook heeft vergroot, kan de tekst daardoor wat slecht gaan passen.
Maar de breedte van de skip-link wordt hierdoor wat te weinig, want die is gebaseerde op de lettergrootte en dus eigenlijk geen niet meer de eerder bij .skippy, .li-skippy .skippy opgegeven 12 em, maar 0,7 x 12 em. Daarom wordt de breedte voor de skip-links in de inhoudsopgave hier verhoogd.
font-weight: normal;
Bij li a:hover, li a:focus wordt de tekst vet gemaakt, als over een link wordt gehoverd of als deze focus heeft. Dat is prima voor de gewone links in de inhoudsopgave, maar deze skip-links zijn bepaald al groot genoeg. Als ze ook nog vet worden, is dat niet mooi. Daarom wordt hier opgegeven dat de tekst in de skip-links niet vet wordt.
(Hoe het kan dat deze regel de verderop bij li a:hover, li a:focus
staande css overrulet, staat iets hoger beschreven bij de selector .skippy, .li-skippy .skippy.)
line-height: 5em;
Zelfde verhaal als bij width: 20em;
iets hier boven, maar nu voor de regelhoogte. Omdat de eenheid em
is gebruikt, is de regelhoogte gebaseerd op de lettergrootte. En omdat deze kleiner is, zijn meer em
nodig om de regelhoogte hoog genoeg te maken. (Hoog genoeg om goed op te vallen, de tekst past er altijd wel in.)
position: fixed;
Bij .skippy, .li-skippy .skippy zijn de skip-links absoluut gepositioneerd, om ze op de juiste plaats neer te kunnen zetten.
Voor de skip-link bovenaan de pagina is dat prima, want die staat gepositioneerd ten opzichte van het venster van de browser. En dat venster wordt nooit verplaatst, tenzij je het hele scherm optilt of – in een groter scherm – het hele venster verschuift. En dan gaat die skip-link gewoon mee.
Bij een absolute positie wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een positie heeft. Bij de skip-links in de inhoudsopgave is zo'n voorouder, anders dan bij de skip-link voor de hele pagina, wel aanwezig. De skip-links zijn nakomelingen van <nav>, die bij nav fixed wordt gepositioneerd. De skip-links in de inhoudsopgave worden hierdoor gepositioneerd ten opzichte van <nav>.
En dat is een probleem, want <nav> kan worden gescrold. Als je de skip-links positioneert ten opzichte van de bovenkant van <nav>, en je gaat <nav> scrollen, dan komen de meeste skip-links (ver) boven het venster van de browser te staan, waardoor ze onzichtbaar zijn.
Daarom worden de skip-links in de inhoudsopgave fixed gepositioneerd. Nu staan ze vast ten opzichte van het venster van de browser. Ook al zijn ze nakomelingen van <nav>, ze scrollen nu niet meer mee met <nav>.
Een <a> is van zichzelf een inline-element. Daardoor zijn eigenschappen als breedte niet te gebruiken. Door de <a> fixed te positioneren, verandert de <a> in een soort blok-element en zijn dit soort eigenschappen wel te gebruiken.
top: 200px;
200 px vanaf de bovenkant van het browservenster neerzetten. Dat is beter dan aan de bovenkant van het venster, want hier vallen ze meer op.
.skippy:focus
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.skippy, .li-skippy .skippy {background: white; color: black; width: 12em; font-size: 2em; line-height: 2em; text-align: center; text-decoration: underline; border: red solid 3px; position: absolute; top: 20px; left: -20000px; z-index: 50;}
.li-skippy .skippy {width: 20em; font-weight: normal; line-height: 5em; position: fixed; top: 200px;}
Als een element met class='skippy' focus heeft.
Alleen de <a>'s die bij een skip-link horen hebben class='skippy'. Deze zijn bij .skippy, .li-skippy .skippy links buiten het scherm geparkeerd, zodat ze onzichtbaar zijn. Maar voor gebruikers van de Tab-toets zijn ze gewoon bereikbaar. Ook schermlezers kunnen ze gewoon gebruiken. (Met uitzondering van TalkBack, waarover meer is te vinden bij Bekende problemen (en oplossingen) onder het kopje Schermlezers.)
left: 30px;
30 px vanaf de rechterkant van het browservenster neerzetten. Op deze plaats passen ze altijd binnen het venster, maar staan ook altijd pontificaal lelijk te wezen bovenop de inhoudsopgave. Wat precies de bedoeling is, want dan vallen ze lekker op.
#checkbox-voor-smal
Het element met id="checkbox-voor-smal". Dit is een <input type="checkbox">. In browservensters smaller dan 760 px wordt de inhoudsopgave pas getoond, als dit aankruisvakje is aangevinkt.
Het aankruisvakje zelf is verborgen, omdat het nou niet echt mooi is te noemen. Aankruisvakjes zijn ook uitermate moeilijk goed op te maken. Daarom vindt de bediening van de <input> plaats door middel van de bij de <input> horende <label>, die wel fatsoenlijk is op te maken.
position: fixed;
Vastzetten ten opzichte van het venster van de browser. Als inhoudsopgave of tekst worden gescrold, scrolt de <input> niet mee.
De bij de <input> horende <label> wordt iets hieronder bij #toon-menu op dezelfde manier vastgezet. Hierdoor staat deze <input> altijd onder de bij de <input> horende <label> en zie je de lelijkerd niet.
(Mogelijk is dit niet meer echt nodig en zou de <input> ook gewoon mogen scrollen. In ieder in het verleden gaf het echter soms problemen, als de <input> buiten het browservenster kwam te staan. Dit werkt in ieder geval, dus lekker zo laten.)
top: 0;
Bovenaan het browservenster neerzetten.
ul
Alle <ul>'s. Dat is er hier maar eentje: de inhoudsopgave staat erin.
text-align: center;
Tekst horizontaal centreren.
list-style: none;
De standaard balletjes en dergelijke bij een <ul> zijn hier niet welkom.
margin: 0; padding: 0;
Verschillende browsers hebben hiervoor verschillende standaardwaarden. Nu zijn ze overal hetzelfde.
li
Alle <li>'s. Elke link in de inhoudsopgave staat in een eigen <li>.
border: black solid 1px;
Zwart randje.
.li-skippy
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
li {line-height: 2em; border: black solid 1p;}
De elementen met class="li-skippy". In de inhoudsopgave zitten ook skip-links, waarmee gebruikers van de Tab-toets (en de meeste schermlezers) in één keer alle links naar een hoofdstuk kunnen passeren. Deze skip-links zitten in een li.li-skippy
.
border: none;
De skip-links zijn niet te zien, omdat de <a>'s in een <li> met class="li-skippy" bij .li-skippy .skippy links buiten het scherm zijn geparkeerd. Maar dat zijn de <a>'s, de <li>'s zelf staan nog gewoon in de inhoudsopgave.
Ook deze <li>'s krijgen de iets hierboven bij li voor alle <li>'s opgegeven border. Deze border is gewoon zichtbaar in de inhoudsopgave. Omdat deze <li>'s verder niets bevatten, zie je die border als een lijn van 2 px dik. Door de border bij deze <li>'s weg te halen, wordt dat voorkomen.
li a
Voor een deel van deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.skippy, .li-skippy .skippy {background: white; color: black; width: 12em; font-size: 2em; line-height: 2em; text-align: center; text-decoration: underline; border: red solid 3px; position: absolute; top: 20px; left: -20000px; z-index: 50;}
.li-skippy .skippy {width: 20em; font-weight: normal; line-height: 5em; position: fixed; top: 200px;}
Alle <a>'s binnen een <li>. Dit zijn de links in de inhoudsopgave.
Voor de skip-links in de inhoudsopgave is eerder al css opgegeven, de css hier geldt voor de gewone links naar de ankers in de tekst in <main>.
background: #fafaff;
Achtergrondkleurtje.
color: black;
Normaal genomen krijgt tekst in een <a> een kleurtje. Dat is hier niet mooi.
display: block;

Een <a> is van zichzelf een inline-element. Daardoor wordt de <a> niet breder dan nodig is om de erin zittende tekst en dergelijke weer te geven. Ook de iets hierboven opgegeven achtergrondkleur wordt niet breder dan de <a> en vult dus niet de volle breedte van de inhoudsopgave. De iets hieronder opgeven border rechts komt niet helemaal rechts in de inhoudsopgave te staan, maar gelijk rechts van de tekst.
Op de afbeelding zijn de <a>'s inline-elementen. Vooral de groene border rechts, die aangeeft dat de link al is bezocht, staat helemaal verkeerd.
Door de <a>'s in een blok-element te veranderen, worden ze automatisch even breed als hun ouder, de <li>. Hierdoor vult de achtergrondkleur de volle breedte van de inhoudsopgave en komt de groene border helemaal rechts te staan.
Er is nog een ander voordeel. Om een link te laten werken, moet je de link aanraken of -klikken. Bij een inline-element is de <a> niet groter dan de tekst en moet je heel precies mikken. Bij een blok-element is de <a> even breed als de <li>, zodat je niet zo precies hoeft te mikken.
line-height: 2em;
Regelhoogte. Tekst wordt automatisch halverwege de regelhoogte gezet, zodat de tekst automatisch verticaal is gecentreerd. Omdat verder geen hoogte is opgegeven voor de <a>, is dit ook de hoogte van de <a>.
Als eenheid wordt de relatieve eenheid em
gebruikt, omdat bij een absolute eenheid als px
de regelhoogte niet mee verandert met de lettergrootte.
text-decoration: none;
Normaal genomen wordt tekst in een <a> onderstreept. Hier is al duidelijk genoeg dat het links zijn en is het niet mooi.
border-right: solid 3px #fafaff;
Border rechts. Deze border heeft dezelfde kleur als de achtergrond van de <a>, zodat je hem niet ziet. Als de <a> is bezocht, wordt deze border groen. Door de border ook hier al neer te zetten, ook al zie je hem niet, wordt vast ruimte gereserveerd. Als je dat niet zou doen, wordt de <a> bij een bezochte link 3 px breder, of de tekst verspringt wat omdat de ruimte voor de tekst opeens 3 px minder is.
li a.hs
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
li a {background: #fafaff; color: black; display: block; text-decoration: none; border-right: solid 3px #fafaff;}
De <a>'s met class="hs" in een <li>. Dit zijn de links naar hoofdstukken.
background: #dbcbff;
Achtergrondkleur. Door de achtergrondkleur anders te maken dan bij een link naar een gewoon artikel, vallen de links naar een hoofdstuk meer op.
border-right-color: #dbcbff;
Bij li a heeft de border rechts dezelfde kleur gekregen als de achtergrond van de <a>, omdat deze border pas zichtbaar moet worden, als de link is bezocht. Hier gelijk boven is de achtergrondkleur verandert, dus moet ook de kleur van de border worden veranderd.
li a.par
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
li a {background: #fafaff; color: black; display: block; text-decoration: none; border-right: solid 3px #fafaff;}
De <a>'s met class="par" in een <li>. Dit zijn de links naar paragrafen.
background: #c2c2ff;
Achtergrondkleur. Door de achtergrondkleur anders te maken dan bij een link naar een gewoon artikel, vallen de links naar een paragraaf meer op.
border-right-color: #c2c2ff;
Bij li a heeft de border rechts dezelfde kleur gekregen als de achtergrond van de <a>, omdat deze border pas zichtbaar moet worden, als de link is bezocht. Hier gelijk boven is de achtergrondkleur verandert, dus moet ook de kleur van de border worden veranderd.
li a:hover, li a:focus
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.skippy, .li-skippy .skippy {background: white; color: black; width: 12em; font-size: 2em; line-height: 2em; text-align: center; text-decoration: underline; border: red solid 3px; position: absolute; top: 20px; left: -20000px; z-index: 50;}
.li-skippy .skippy {width: 20em; font-weight: normal; line-height: 5em; position: fixed; top: 200px;}
.skippy:focus {left: 30px;}
li a {background: #fafaff; color: black; display: block; text-decoration: none; border-right: solid 3px #fafaff;}
li a.hs {background: #dbcbff; border-right-color: #dbcbff;}
li a.par {background: #c2c2ff; border-right-color: #c2c2ff;}
De <a>'s in een <li>, maar alleen als erover wordt gehoverd, of als deze focus hebben. (Focus is vooral van belang voor gebruikers van de Tab-toets.)
background: #c7c7cc;
Achtergrondkleur veranderen, zodat duidelijk is over welke link wordt gehoverd, of welke link focus heeft.
font-weight: bold;
Sommige mensen hebben moeite kleuren te onderscheiden. Daarom wordt ook de tekst wat vetter gemaakt.
Als de gebruikte lettersoort een vette variant heeft, wordt die gebruikt. De meeste lettersoorten hebben wel een vette variant, soms zelfs meerdere. Een vette variant wordt speciaal ontworpen, het is iets anders dan 'alle lijntjes wat dikker maken'. Sommige letters kunnen er zelfs heel anders uitzien.
Als de lettersoort geen vette variant heeft, maakt de browser de letter vet. Dat wil zeggen dat de browser gewoon alle lijntjes wat dikker maakt. Dat kan mooi zijn, maar vaak is het foeilelijk. Het is heel iets anders dan een speciaal ontworpen font. Elke rechtgeaarde typograaf gruwt hiervan.
li a:visited
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.skippy, .li-skippy .skippy {background: white; color: black; width: 12em; font-size: 2em; line-height: 2em; text-align: center; text-decoration: underline; border: red solid 3px; position: absolute; top: 20px; left: -20000px; z-index: 50;}
.li-skippy .skippy {width: 20em; font-weight: normal; line-height: 5em; position: fixed; top: 200px;}
.skippy:focus {left: 30px;}
li a {background: #fafaff; color: black; display: block; text-decoration: none; border-right: solid 3px #fafaff;}
li a.hs {background: #dbcbff; border-right-color: #dbcbff;}
li a.par {background: #c2c2ff; border-right-color: #c2c2ff;}
li a:hover, li a:focus {background: #c7c7cc; font-weight: bold;}
De <a>'s in een <li>, maar alleen als de link al is bezocht.
Hier iets boven staat li a:hover, li a:focus
. Dat staat dus boven de selector hier: li a:visited
. Normaal genomen staat :visited
voor :hover
en :focus
. Als je een bezochte link bijvoorbeeld rood maakt en bij hoveren over de link moet die groen worden, verandert de link niet als :visited
onder :hover
staat.
Hier wordt bij :hover
en :focus
de achtergrondkleur veranderd, en de tekst wordt vetter. Bij :visited
wordt de kleur van de rechterborder verandert. Dat zijn twee verschillende dingen, die elkaar niet bijten. Door hier :visited
onder :hover
en :focus
te zetten, blijft de rechterborder bij een bezochte link altijd groen. Ook bij hoveren over of focus van de link is daardoor nog duidelijk dat de link al is bezocht. Bij meer dan tweehonderd links is dat wel handig.
border-right-color: green;
Rechterborder groen maken.
Bij li a is al een border aangebracht, maar die zie je niet, omdat de kleur van de border hetzelfde is als die van de achtergrond. Hier wordt de border zichtbaar, omdat de kleur wordt veranderd.
Door bij li a
al een border aan te brengen, wordt voorkomen dat een bezochte link 3 px breder wordt, of dat de tekst in de <a> verspringt, omdat er 3 px minder ruimte is.
Bij een bezochte link kunnen nog maar heel weinig dingen worden veranderd. Het bleek nogal eenvoudig om na te gaan, welke sites iemand had bezocht, als het uiterlijk van een bezochte link met css kon worden veranderd. Een van de weinige dingen die nog kan worden veranderd, is de kleur van een border.
main
Alle <main>'s. Er is maar één <main> met daarin de belangrijkste inhoud van de pagina. Dat is hier de tekst van de grondwet.
background: #f0f0ff;
Achtergrondkleurtje.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.
display: block;
Oudere browsers kennen <main> niet. Een onbekend element is standaard een inline-element. Daarom wordt hier specifiek opgegeven dat <main> een blok-element is.
padding: 5px;
Kleine afstand tussen inhoud en buitenkant van <main>.
h1
Alle <h1>'s. Dat is er maar eentje: de belangrijkste kop.
font-size: 1.2em;
Een <h1> heeft een wel heel enthousiaste lettergrootte. Die wordt hier iets kleiner gemaakt.
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: 35px 0 0;
Omdat voor links niets is opgegeven, krijgt links automatisch dezelfde waarde als rechts. Hier staat dus eigenlijk 35px 0 0 0
in de volgorde boven – rechts – onder – links.
Aan de onderkant de standaardmarge van de <h1> verwijderen.
In browservensters smaller dan 760 px staat bovenaan het venster een <label> in de vorm van een balk, waarmee de inhoudsopgave verborgen en getoond kan worden. Om te voorkomen dat de <h1> hier gedeeltelijk onder verdwijnt, wordt de <h1> iets lager neergezet.
.bron
Alle elementen met class="bron". Dat is er maar eentje: de bronvermelding van de tekst gelijk onder de <h1> bovenaan de pagina.
font-size: 0.7em;
Kleinere letter. Als eenheid wordt de relatieve eenheid em
gebruikt, omdat bij gebruik van een absolute eenheid zoals px
niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
h2
Voor een deel van deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
nav h2 {position: absolute; left: -20000px;}
Alle <h2>'s. Elke hoofdstuktitel staat in een <h2>. Voor schermlezers staat ook nog een <h2> bovenin de nav, maar die staat onzichtbaar links buiten het scherm.
font-size: 1.2em;
Standaardlettergrootte van de <h2> iets verkleinen. 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: -30px 0 0; padding-top: 30px;
Omdat bij de marge voor links geen waarde is opgegeven, wordt krijgt links automatisch dezelfde waarde als rechts. Hier staat dus eigenlijk margin: 30px 0 0 0;
in de volgorde boven – rechts – onder – links.
Aan de onderkant de standaardmarge van een <h2> verwijderen.
Aan de bovenkant wordt de <h2> met een negatieve marge 30 px naar boven gezet.
In de inhoudsopgave zit een link naar onder andere elke <h2>, elke hoofdstuktitel, in <main>. Als die link wordt gevolgd, wordt de <h2> bovenin het browservenster gezet. Maar daar ontstaat een probleem: aan die bovenkant staat al een <label> in de vorm van een balk, waarmee de inhoudsopgave getoond en verborgen kan worden. Als de <h2> bovenaan het venster wordt gezet, verdwijnt de <h2> onder die balk.
Omdat de <label> aan de bovenkant een fixed positie heeft, scrolt de balk niet mee met de rest van de pagina. Dit probleem doet zich dus op de hele pagina voor. Niet alleen bij het bovenste hoofdstuk, maar ook bij lagere hoofdstukken.
Om te voorkomen dat de <h2> onder de balk aan de bovenkant van het browser verdwijnt, wordt met padding-top: 30px;
een padding aan de bovenkant van de <h2> gegeven. Nu staat de tekst in de <h2> onder de balk aan de bovenkant.
Dit levert echter weer een ander probleem op: nu staat overal op de pagina een opening van 30 px boven elk hoofdstuktitel. Als dat nou alleen bij de hoofdstuktitels zo zou zijn, zou daar nog mee zijn te leven, hoewel het niet mooi is. Maar hetzelfde probleem speelt bij alle artikelen en paragrafen, want ook daarnaartoe staan links vanuit de inhoudsopgave.
Om deze opening aan de bovenkant weer te verwijderen, wordt aan de bovenkant van de <h2> een negatieve marge gegeven die even groot is als de padding aan de bovenkant: 30 px. Een negatieve marge verplaatst een element daadwerkelijk. Bij bijvoorbeeld een relatieve positie wordt het element ogenschijnlijk verplaatst, maar in werkelijkheid blijft het gewoon op z'n plaats staan. Het wordt alleen op een andere plaats getoond. Een marge echter verplaatst het element daadwerkelijk. En daarmee ook de op het element volgende elementen, zodat er geen lege ruimte onder de <h2> ontstaat.

Op de afbeelding is de zilverkleurige balk aan de bovenkant van het browservenster doorzichtig gemaakt. De <h2> heeft een rode outline gekregen. De outline loopt tot aan de bovenkant door, dus de <h2> staat echt bovenaan het venster. Door de padding aan de bovenkant van de <h2> staat de tekst in de <h2> echter netjes onder de menubalk.
Op deze manier kan worden gecorrigeerd voor een vaststaande header bovenaan het browservenster. Dit corrigeren hoeft alleen in vensters smaller dan 760 px, want in bredere vensters is de inhoudsopgave gewoon altijd zichtbaar. Voor bredere vensters worden daarom later de marges en paddings aangepast.
h3
Alle <h3>'s. Elk paragraafkopje staat in een <h3>, en de meeste artikelkopjes ook.
font-size: 1.1em;
Standaardlettergrootte van de <h3> iets verkleinen. 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: -30px 0 0; padding-top: 30px;
In de inhoudsopgave staat een link naar elke <h3>. Deze negatieve marge en padding aan de bovenkant zijn nodig, om te corrigeren voor de vaststaande balk bovenaan het browservenster. Dit werkt hetzelfde als de correctie voor de <h2>'s, waarvan de beschrijving bij margin: -30px 0 0; padding-top: 30px; staat.
h4
Alle <h4>'s. De meeste artikelkopjes staan in een <h3>. Artikelkopjes van artikelen die in een paragraaf staan, staan echter in een <h4>, omdat de <h3> dan wordt gebruikt voor de paragraaf.
margin: -30px 0 0; padding-top: 30px;
In de inhoudsopgave staat een link naar elke <h3>. Deze negatieve marge en padding aan de bovenkant zijn nodig, om te corrigeren voor de vaststaande balk bovenaan het browservenster. Dit werkt hetzelfde als de correctie voor de <h2>'s, waarvan de beschrijving bij margin: -30px 0 0; padding-top: 30px; staat.
p
Voor een deel van deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.bron {font-size: 0.7em;}
Alle <p>'s.
margin: 0;
Een <p> heeft standaard een marge aan boven- en onderkant. Die wordt hier weggehaald.
.lid
De elementen met class="lid". Sommige artikelen zijn opgesplitst in leden. Elke <p> met een lid heeft deze class.
text-indent: -1.2em;
De eerste regel van de <p> 1,2 em naar links zetten. Hierdoor verdwijnt een deel van de eerste regel in browservensters smaller dan 760 px links buiten het venster, en in bredere vensters onder de inhoudsopgave. Dat wordt gelijk hieronder gecorrigeerd.
Als eenheid wordt de relatieve eenheid em
gebruikt, zodat de grootte van de verplaatsing mee verandert met de lettergrootte.
margin-left: 1.2em;
Hier gelijk boven is de eerste regel van de <p> 1,2 em naar links gezet, waardoor een deel van die regel links buiten het scherm of onder de inhoudsopgave verdwijnt. Door hier een marge aan de linkerkant op te geven die even groot is als de verplaatsing hierboven, wordt dit weer gecorrigeerd. Maar de eerste regel staat nu wel 1,2 em meer naar links dan de rest van de tekst in de <p>, waardoor het cijfer van het lid links buiten de tekst van het lid staat.
Als eenheid wordt de relatieve eenheid em
gebruikt, zodat de grootte van de marge mee verandert met de lettergrootte.
.onderdeel
De elementen met class="onderdeel". Een onderdeel van een lid blijkt een 'onderdeel' te heten. Elk onderdeel zit in een <p> met class="onderdeel".
text-indent: -1.2em;
De eerste regel van de <p> 1,2 em naar links zetten. Hierdoor verdwijnt een deel van de eerste regel in browservensters smaller dan 760 px links buiten het venster, en in bredere vensters onder de inhoudsopgave. Dat wordt gelijk hieronder gecorrigeerd.
Als eenheid wordt de relatieve eenheid em
gebruikt, zodat de grootte van de verplaatsing mee verandert met de lettergrootte.
margin-left: 2.4em;
Hier gelijk boven is de eerste regel van de <p> 1,2 em naar links gezet, waardoor een deel van die regel links buiten het scherm of onder de inhoudsopgave verdwijnt. Door hier een marge aan de linkerkant op te geven, wordt dit weer gecorrigeerd.
Door de marge groter te maken dan de verplaatsing hierboven, springt het hele onderdeel in, maar de eerste regel staat nog steeds 1,2 em meer naar links dan de rest van de tekst in de <p>. Hierdoor staat de letter van het onderdeel nog steeds buiten de tekst van het onderdeel.
Als eenheid wordt de relatieve eenheid em
gebruikt, zodat de grootte van de marge mee verandert met de lettergrootte.
.lid::first-letter, .onderdeel::first-letter
De eerste letter van de elementen met class="lid" of class="onderdeel". Bij leden en onderdelen is de eerste letter een letter of cijfer, direct gevolgd door een punt. Als op het eerste teken een leesteken als een punt volgt, wordt die tot de eerste letter gerekend en valt dus ook binnen deze selector.
font-weight: bold;
Vet maken.
Als de gebruikte lettersoort een vette variant heeft, wordt die gebruikt. De meeste lettersoorten hebben wel een vette variant, soms zelfs meerdere. Een vette variant wordt speciaal ontworpen, het is iets anders dan 'alle lijntjes wat dikker maken'. Sommige letters kunnen er zelfs heel anders uitzien.
Als de lettersoort geen vette variant heeft, maakt de browser de letter vet. Dat wil zeggen dat de browser gewoon alle lijntjes wat dikker maakt. Dat kan mooi zijn, maar vaak is het foeilelijk. Het is heel iets anders dan een speciaal ontworpen font. Elke rechtgeaarde typograaf gruwt hiervan.
css voor vensters maximaal 759 px breed
@media screen and (max-width: 759px)
De css die hier tot nu toe staat, geldt voor alle browservensters.
De css die binnen deze media query staat, geldt alleen voor browservensters die maximaal 759 px breed zijn.
In sommige versies van Opera Mini en oudere versies van Android browser op Android zit een bug, waardoor de inhoudsopgave niet kan worden getoond. Omdat dit alleen in deze smallere vensters speelt, is er geen enkele reden bredere vensters op te zadelen met de css in deze media query.
En omdat deze media query toch aanwezig was, is de rest van de css voor het tonen en verbergen van de inhoudsopgave hier ook maar neergezet.
@media
: geeft aan dat het om css gaat die alleen van toepassing is, als aan bepaalde voorwaarden wordt voldaan. Al langer bestond de mogelijkheid om met behulp van zo'n @media-regel css voor bijvoorbeeld printers op te geven. css3 heeft dat uitgebreid tot bepaalde fysieke eigenschappen, zoals de breedte en hoogte van het venster van de browser.
screen
: deze regel geldt alleen voor schermweergave.
and
: er komt nog een voorwaarde, waaraan moet worden voldaan.
(max-width: 759px)
: het browservenster mag maximaal 759 px breed zijn. Is het venster breder, dan wordt de css die binnen deze media-regel staat genegeerd.
Gelijk na deze regel komt een {
te staan, en aan het einde van de css die binnen deze regel 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-regel (...)
footer {color: gold;}
}
Voor de eerste css binnen deze media-regel staat dus een extra {
, en aan het eind staat een extra }
.
css 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: het browservenster moet minimaal 760 px: breed zijn (min-width: 760px)
. In vensters van minimaal deze breedte is de inhoud altijd zichtbaar.
Als je nou 'n mobieltje hebt met een resolutie van – ik roep maar wat – 1024 x 768 px, dan geldt deze media query toch niet voor dat mobieltje. Terwijl dat toch echt meer dan 760 px breed is. Een vuig complot van gewetenloze multinationals? Voordat je je gaat beklagen bij Radar, zou ik eerst even verder lezen.
Steeds meer mobiele apparaten, maar ook steeds meer gewone beeldschermen, hebben een hogere resolutiedichtheid. Dat wil zeggen dat ze kleinere pixels hebben, die dichter bij elkaar staan. Daardoor zijn foto's, tekst, en dergelijke veel scherper weer te geven. Hoe kleiner de puntjes (de pixels) zijn, waaruit een afbeelding is opgebouwd, hoe duidelijker het wordt.
Er ontstaat alleen één probleem: als je de pixels twee keer zo klein maakt, wordt ook wat je ziet twee keer zo klein. En inmiddels zijn er al apparaten met pixels die meer dan vier keer zo klein zijn. Een lijntje van 1 px breed zou op die apparaten minder dan 'n kwart van de oorspronkelijke breedte krijgen en vrijwel onzichtbaar zijn. Een normale foto zou in een thumbnail veranderen. Kolommen zouden heel smal worden. Tekst zou onleesbaar klein worden. Allemaal fantastisch scherp, maar je hebt 'n vergrootglas nodig om 't te kunnen zien.
Om dit te voorkomen wordt een verschil gemaakt tussen css-pixels en schermpixels (in het Engels 'device-pixels'). De css-pixels zijn gebaseerd op de – tot voor kort – normale beeldschermen van de desktop. 1 css-pixel is op zo'n beeldscherm 1 pixel. Het aantal schermpixels is het werkelijk op het apparaat aanwezige aantal pixels (dat is het aantal pixels, waarvoor je hebt betaald).
Dat eerder genoemde mobieltje van 1024 x 768 px heeft wel degelijk het aantal pixels, waarvoor je hebt betaald. Maar die zitten dichter bij elkaar.Op een gewoon beeldscherm zitten 96 pixels per inch, wat wordt uitgedrukt met de eenheid 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. Je bent dus niet opgelicht, of in ieder geval niet wat betreft het aantal pixel.
Door deze truc is een lijn van 1 px breed op een normaal beeldscherm ook op het mobieltje nog steeds 1 px breed, alleen wordt die ene (css-)pixel opgebouwd uit twee schermpixels (feitelijk vier, want het verhaal geldt voor breedte én hoogte). De dikte van het lijntje is hetzelfde, maar het is veel fijner opgebouwd. Bij lijntjes is dat verschil bijvoorbeeld in bochten goed te zien.
Hetzelfde verhaal geldt voor hogere resoluties, Een tablet met een breedte van 4096 schermpixels en een 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 schermpixel.
(Overigens kun je met behulp van media query's ook testen op de resolutie met gebruik van het sleutelwoord 'resolution'. Apple gebruikt het niet-standaard 'device-pixel-ratio', maar het idee is hetzelfde. Dit kan bijvoorbeeld handig zijn om te bepalen, hoe groot een foto moet zijn.)
Kort samengevat: omdat niet het aantal schermpixels (waarvoor je hebt betaald), maar het aantal css-pixels (de door de ontwerper bedoelde afmeting) wordt doorgegeven, wordt voorkomen dat een hogeresolutiescherm onleesbaar klein wordt.
body
Voor dit element eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
body {background: #ff9; color: black; font-family: Arial Helvetica, sans-serif; margin: 0; padding: 0;}
Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.
font-size: 110%;
Iets groter dan standaard. 't Zal de leeftijd zijn, maar ik vind de standaardgrootte wat te klein.
Als eenheid wordt de relatieve eenheid %
gebruikt, omdat bij gebruik van een absolute eenheid zoals px
niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
#wrapper
Het element met id="wrapper". Een overkoepelende <div> waarin de <nav> met de inhoudsopgave en de <main> met de tekst staan.
width: 100%;
Breedte.
Een breedte in procenten is normaal genomen ten opzichte van de ouder van het element. Dat is hier <body>, een blok-element. Een blok-element wordt normaal genomen automatisch even breed als z'n ouder. De ouder van <body> is <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser. Hierdoor wordt div#wrapper
ook even breed als het venster, ongeacht de breedte van het venster.
max-width: 800px;
Maximumbreedte.
De <nav> met de inhoudsopgave heeft bij nav een breedte van 11 em gekregen. De rest van het de breedte van het browservenster is voor <main> met de tekst.
In bredere vensters zouden de regels in <main> heel breed en daardoor lastig leesbaar worden. Door het opgeven van een maximumbreedte wordt dit voorkomen.
margin: 0 auto;
Omdat voor onder en links geen waarden zijn opgegeven, krijgen deze 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. Oftewel: #wrapper
staat altijd gecentreerd ten opzichte van z'n ouder. Die ouder is het blok-element <body>. Een blok-element wordt normaal genomen automatisch even breed als z'n ouder. De ouder van <body> is <html> Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser. Hierdoor staat #wrapper
automatisch horizontaal gecentreerd in het venster, ongeacht de breedte van het venster.
Deze manier van horizontaal centreren van een blok-element werkt alleen, als het blok-element een breedte heeft.
Maar hier doet zich een eigenaardig verschijnsel voor. #wrapper
wordt iets hieronder absoluut gepositioneerd, en bij een absoluut gepositioneerd element werkt de truc om met auto
te centreren normaal genomen niet. Hier werkt die echter toch.
Iets hieronder wordt met right: 0;
en left: 0;
opgegeven dat #wrapper
van de linker- tot de rechterkant van het browservenster moet lopen. Iets hierboven is echter een maximumbreedte van 800 px opgegeven. In vensters met een breedte van maximaal 800 px werkt dit prima. Maar in bredere vensters wordt hier een onmogelijke opdracht gegeven.
Als het browservenster bijvoorbeeld 1000 px breed is en #wrapper
moet van left: 0;
tot right: 0;
lopen, én mag vanwege de max-width: 800px;
niet breder dan 800 px zijn, dan kan aan één van die drie eigenschappen onmogelijk worden voldaan.
De browser raakt hier dermate van in de war, dat right: 0;
en left: 0;
gewoon worden genegeerd en margin: 0 auto;
toch werkt. Oftewel: bij een absolute positie werkt margin: 0 auto;
niet, tenzij je ook left: 0;
en right: 0;
opgeeft.
(Deze weinig bekende truc werkt trouwens ook bij position: fixed;
. Je kunt de horizontale plaatsing nog beïnvloeden door bij right
of left
een andere waarde dan 0 in te vullen. En het is ook niet zo dat de browser in de war raakt. Dit staat gewoon in de specificatie. Alleen is het zo weerzinwekkend technisch opgeschreven dat naar verluidt zelfs Einstein het pas na 38 keer lezen begreep.)
position: absolute;
Om de <div> op de juiste positie neer te kunnen zetten. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een andere positie dan 'static' heeft. Als die er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.
top: 0; right: 0; bottom: 0; left: 0;
Omdat de <div> aan alle vier de kanten is vastgezet aan de buitenkant van het browservenster, vult de <div> het volledige venster.
div#wrapper
heeft slechts twee kinderen: <nav> met de inhoudsopgave, en <main> met de tekst.
<nav> is eerder bij nav met bottom: 0;
aan de onderkant van div#wrapper
vastgezet. Iets hieronder wordt <nav> bij nav met top: 0; aan de bovenkant van div#wrapper vastgezet.
<main> wordt iets hieronder bij main met top: 0;
en bottom: 0;
ook aan boven- en onderkant van div#wrapper
vastgezet.
De tekst in <nav> en <main> is echter veel te veel om binnen div#wrapper
te passen, want div#wrapper
is niet hoger dan het venster van de browsers. Normaal genomen zou daardoor de pagina toch gescrold kunnen worden, ondanks dat div#wrapper
is vastgezet aan het venster. Normaal genomen is dat ook het beste: de lay-out wordt misschien verstoord, maar er verdwijnt in ieder geval geen tekst en dergelijke.
Hier ligt dat echter anders. Eerder is bij nav overflow: auto;
opgegeven, en iets hieronder gebeurt dat bij main ook voor <main>. Daardoor kunnen <nav> en <main> zelf worden gescrold, zonder dat div#wrapper
of de hele pagina scrollen.
(right: 0;
en left: 0;
worden hier eigenlijk alleen gebruikt, om div#wrapper horizontaal te centreren. Hoe dat precies werkt, is iets hoger te vinden bij margin 0 auto;
.)
main
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: #f0f0ff; color: black; display: block; padding: 5px;}
Alle <main>'s. Er is maar één <main> met daarin de belangrijkste inhoud van de pagina. Dat is hier de tekst van de grondwet.
overflow: auto;
<main> wordt iets hieronder vastgezet aan boven- en onderkant van div#wrapper
, die bij #wrapper is vastgezet aan het venster van de browser. Daardoor kan <main> niet hoger worden dan het venster. Er staat echter veel meer tekst in <main>, dan binnen het venster past.
Normaal genomen wordt dat teveel toch getoond, omdat overflow
standaard op visible
staat. Normaal genomen is dat ook prima: de lay-out wordt misschien wat verstoord, maar er verdwijnt in ieder geval geen tekst en dergelijke.
Hier is dat echter niet nodig. Door deze regel kan de tekst binnen <main> worden gescrold, zonder dat dat invloed heeft op de rest van de pagina. Afhankelijk van browser en besturingssysteem kan rechts van <main> een verticale scrollbalk verschijnen.
-webkit-overflow-scrolling: touch;
Zoals gelijk hierboven beschreven, wordt de inhoud van <main> gescrold, los van de rest van de pagina. Zodra je in iOS binnen een element wilt scrollen, gebeurt dat echt ongelooflijk schokkerig. Zo schokkerig, dat scrollen feitelijk onmogelijk is. Deze regel lost dat op, nu scrolt de inhoudsopgave vloeiend.
Deze eigenschap kan grote problemen opleveren en moet grondig worden getest. Meer hierover is te vinden bij Bekende problemen (en oplossingen) onder het kopje Zoomen op iOS in vensters minstens 760 px breed.
border-right: black solid 1px;
Lijntje rechts van <main>.
position: absolute;
Om <main> op de juiste plaats neer te kunnen zetten. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een andere positie dan 'static' heeft. Dat is hier div#wrapper
.
top: 0; bottom: 0;
Aan boven- en onderkant van div#wapper
neerzetten. Omdat div#wrapper
bij #wrapper even hoog is gemaakt als het venster van de browser, is <main> ook even hoog als het venster.
left: 11rem;
<nav> met de inhoudsopgave is bij nav 11 rem breed gemaakt. Door <main> op 11 rem vanaf links neer te zetten, sluit het aan op <nav>. De hier gebruikte eenheid rem
werkt ongeveer hetzelfde als de eenheid em
, maar is gebaseerd op de lettergrootte van <html>. Hierdoor is de rem
op de hele pagina even groot. Meer uitleg over de rem
is te vinden bij nav onder width: 11rem;
.
h1
Voor dit element 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-size: 1.2em; margin: 35px 0 0;}
Alle <h1>'s. Dat is er maar eentje: de belangrijkste kop.
margin-top: 20px;
In bredere browservensters staat geen balk bovenaan het venster. Daarom kan de eerder opgegeven marge aan de bovenkant iets minder worden.
p
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
.bron {font-size: 0.7em;}
p {margin: 0;}
Alle <p>'s.
margin: 10px 0;
Omdat voor onder en links niets is opgegeven, krijgen onder en links automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 10px 0 10px 0
in de volgorde boven – rechts – onder – links.
In deze bredere browservensters is wat meer ruimte, daarom wordt hier aan boven- en onderkant een kleine marge teruggezet.
Als twee verticale marges elkaar raken, zoals hier het geval is bij twee boven elkaar staande <p>'s, overlappen de marges elkaar. Ook tussen twee <p>'s is de marge daardoor slechts 10 px en niet 20 px (marge van 10 px aan boven- en onderkant), zoals je misschien zou verwachten.
h2
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
nav h2 {position: absolute; left: -20000px;}
h2 {font-size: 1.2em; margin: -30px 0 0; padding-top: 30px;}
Alle <h2>'s. Elke hoofdstuktitel staat in een <h2>. Voor schermlezers staat ook nog een <h2> bovenin de <nav>, maar die staat onzichtbaar links buiten het scherm.
margin: 20px 0;
Omdat voor onder en links geen waarden zijn opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 20px 0 20px 0
in de volgorde boven – rechts – onder – links.
Browservensters smaller dan 760 px hebben bovenin het venster een balk staan. Daarom is voor die kleinere vensters een correctie nodig om ankers (links binnen de pagina) goed te laten werken: een negatieve marge en padding aan de bovenkant. Hoe dit precies werkt, is te vinden bij h2. Die correctie is in bredere vensters niet nodig.
Aan boven- en onderkant een marge van 20 px, zodat de hoofdstuktitel er wat uitspringt.
padding: 0;
Om de reden die gelijk hierboven wordt genoemd, is de eerder opgegeven negatieve padding aan de bovenkant niet meer nodig.
h3, h4
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
h3 {font-size: 1.1em; margin: -30px 0 0; padding-top: 30px;}
h4 {margin: -30px 0 0; padding-top: 30px;}
Alle <h3>'s en <h4>'s. Elk paragraaf- en artikelkopje staat in een <h3> of in een <h4>.
margin: 40px 0 20px;
Omdat voor links geen waarde is opgegeven, krijgt links automatisch dezelfde waarde als rechts. Hier staat dus eigenlijk 40px 0 20px 0
in de volgorde boven – rechts – onder – links.
Browservensters smaller dan 760 px hebben bovenin het venster een balk staan. Daarom is voor die kleinere vensters een correctie nodig om ankers (links binnen de pagina) goed te laten werken: een negatieve marge en padding aan de bovenkant. Hoe dit precies werkt, is te vinden bij h2. Die correctie is in bredere vensters niet nodig.
Bovenaan een wat grotere marge, onderaan een wat kleinere.
padding: 0;
Om de reden die gelijk hierboven wordt genoemd, is de eerder opgegeven negatieve padding aan de bovenkant niet meer nodig.
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
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)
Bij de uitleg van deze code zijn allerlei haakjes en dergelijke grotendeels weggelaten, want dat voert hier te ver. Als je je in dat soort dingen wilt verdiepen, kun je beter naar sites gaan die meer voor JavaScript zijn bedoeld.
Als je onderstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.
<script>
(function () {
"use strict";
var links, aantal, i,
pad = location.pathname + "#";
links = document.getElementsByTagName("a");
aantal = links.length;
for (i = 0; i < aantal; i++) {
if (links[i].href.indexOf(pad) > 0) {
links[i].addEventListener("click", geenHistory);
}
}
function geenHistory (e) {
location.replace(e.target.href);
}
}) ();
</script>
Als je bovenstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.
Met behulp van dit JavaScript wordt voorkomen dat alle bezochte artikelen in de geschiedenis van de browser worden opgeslagen. Hiermee wordt voorkomen dat je, bij gebruik van de Terug-toets, de Vooruit-toets of een toetscombinatie als alt+← of alt+→, eerst weer door alle bezochte artikelen gaat, voordat je 'n vorige of volgende pagina bereikt.
Dit script manipuleert het adres van de browser. Daarom zou het misbruikt kunnen worden om de bezoeker naar een bepaald adres te leiden. Browsers worden steeds strenger beveiligd tegen dit soort misbruik. Daarom werkt het script in veel (alle?) browsers alleen online of op een zelf geïnstalleerde server goed. Gewoon op de desktop is er een grote kans dat dit script niet werkt.
Deze beveiliging is volkomen terecht. Als je toevallig Halbe heet, zou je niet willen dat 'n script op de site van De Telegraaf het adres van de pagina kan veranderen in '/computer/halbe/erotische-fantasieën/ik-zag-poetins-kruisraket-stijgen.doc'. Om daar vervolgens 'n schermafdruk van te versturen naar de site van De Telegraaf.
Om dezelfde reden kan alleen een adres binnen hetzelfde domein (dezelfde site) worden opgegeven. Een script op 'www.css-voorbeelden.nl' kan alleen een adres opgeven dat begint met 'www.css-voorbeelden.nl'. Een adres dat met iets anders begint, wordt gewoon genegeerd. (En levert in de console – de duistere ingewanden van de browser – 'n foutmelding op.)
Ik heb eindeloos geprobeerd het adres te veranderen in allerlei bestanden die begonnen met 'ing.nl/overboekingen/betalingen/', maar dat leverde slechts één geslaagde overboeking op: naar mijn hoster vanwege buitensporig datagebruik.
Serieus: het zal duidelijk zijn, waarom aan dit soort scripts zulke strenge beperkingen worden opgelegd. Als je ergens iets leest over een beveiligingslek in een browser, gaat het vaak om dit soort dingen. Iemand heeft 'n gat gevonden, waardoor 'n script toch zoiets kan doen. Daarom is het ook zo ontzettend belangrijk je browser altijd zo snel mogelijk te updaten. (En een browser te gebruiken die nog wordt onderhouden.)
<script> en </script>
Dit is gewone html: het zijn de openings- en sluittag voor het script. In html5 is de toevoeging type="text/javascript"
niet meer nodig.
Als je het script op meer pagina's wilt gebruiken, kun je er heel simpel een extern script van maken. Je zet het hele script (behalve <script> en </script>, want dat is html en geen JavaScript) in een gewoon tekstbestand met de extensie '.js'. In de <script>-tag komt het pad naar en de naam van dat bestand te staan:
<script src="pad-naar-script/script.js"></script>
Normaal genomen wordt het verwerken van de html onderbroken, zodra de browser een script tegenkomt. Het script zou immers nodig kunnen zijn voor de opbouw van de pagina.
Daarom staat het script hier helemaal onderaan de html, gelijk boven </body>. Dit script is niet nodig voor de opbouw van de pagina. Door het onderaan te zetten, wordt voorkomen dat het vertragend werkt.
Een andere mogelijkheid is om het wel bovenaan in de <head> te zetten. Veel sitebouwers zetten scripts en dergelijke graag bij elkaar, voor de overzichtelijkheid. In dat geval kun je hetzelfde bereiken met:
<script src="pad-naar-script/script.js" async></script>
Door het toevoegen van het sleutelwoord async
weet de browser dat dit script niet nodig is voor de opbouw van de pagina. Het script wordt nu gedownload, terwijl de html gewoon verder wordt verwerkt. Zodra het script is gedownload, wordt het verwerkt, waarbij het verwerken van de html alsnog wordt onderbroken. Maar deze onderbreking is zo kort, dat je dat nauwelijks merkt.
(function () {
function
: het sleutelwoord waarmee het begin van een functie wordt aangegeven. Een functie is een stukje bij elkaar horende code. (Het haakje helemaal aan het begin wordt iets verderop beschreven.)
()
: achter een functie moeten twee haakjes staan. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie, maar bij deze functie gebeurt dat niet.
{
: geeft het begin van de code binnen de functie aan. Aan het eind van de functie, dat is in dit geval helemaal onderaan in de laatste regel van het script, staat een bijbehorende }
.
In die laatste regel staat in dit geval nog meer dan alleen de }
die het einde van de code aangeeft: }) ();
}
: dit is de eerder genoemde afsluitende }
, waarmee het einde van de code in de functie wordt aangegeven.
)
: dit afsluitende haakje is de tegenhanger van het haakje dat voor de functie staat. Samen zorgen ze ervoor dat de hele functie, met alles erop en eraan, tussen haakjes staat. De reden van deze haakjes wordt iets hieronder besproken.
()
: dit is weer gewoon een taalregel van JavaScript. In dit geval moeten er achter de })
nog twee haakjes staan. Een computer is gewoon niet zo slim, anders weet de ziel niet wat er moet gebeuren.
;
: met de puntkomma wordt in JavaScript een regel afgesloten. Het is te vergelijken met een gewone punt in een tekst.
We hebben hier een script, waarin alle code binnen een functie is geplaatst. Alle code staat tussen {
en }
, zodat de computer het begin en einde van de functie kan herkennen.
Een functie is een stukje bij elkaar horende code, dat je zo vaak als je wilt kunt uitvoeren. Als je de tafel van twaalf op het scherm wilt zetten, hoef je niet twaalf vermenigvuldigingen in JavaScript te schrijven, maar schrijf je 'n functie voor één vermenigvuldiging, die je vervolgens tien keer (op steeds iets andere wijze) uitvoert.
Een functie heeft echter één probleem: de code in de functie wordt pas uitgevoerd, als de functie wordt aangeroepen. Dat aanroepen kan op allerlei manieren gebeuren, bijvoorbeeld als de gebruiker 'n toets indrukt, als de pagina is geladen, als het 13:13 is op vrijdag de dertiende, noem maar op. Maar zonder te worden aangeroepen doet een functie helemaal niets.
In dit script is dat ook zo. Er zit een functie in die reageert op het klikken op of aanraken van een link. Om die functie goed te laten werken, moet de computer 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 )
. 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 ook de code niet in een alles omvattende functie zetten. Dan wordt de code gelijk uitgevoerd. Maar dat brengt belangrijke risico's met zich mee. In dit script worden namen voor variabelen gebruikt als 'links' en 'aantal'. Als nou een ander JavaScript toevallig dezelfde namen zou gebruiken, gaat het gruwelijk mis. Door het hele script in een functie te stoppen, voorkom je dat. Als je hier meer over wilt weten, kun je op internet zoeken naar 'name conflict' of 'name clash'.)
"use strict";
Deze regel zorgt ervoor dat bepaalde slordigheden in de code, die makkelijk tot grote problemen kunnen leiden, niet meer mogen. Een validator (die controleert op fouten in de code) is nu strenger en keurt meer dingen af.
Een klein aantal oudere browsers ondersteunt dit niet, maar die hebben er verder geen last van, omdat ze de regel gewoon negeren.
var links, aantal, i,
pad = location.pathname + "#";
In dit deel van de code worden een paar dingen voorbereid. Het écht uitvoerende deel van het script, waarin bijvoorbeeld een aanraking daadwerkelijk wordt herkend, volgt later.
Het is gebruikelijk dit soort voorbereidende zaken bovenin het script te zetten.
Deze regel valt in twee delen uiteen, die worden gescheiden door een komma. Het eerste deel begint met var
. Dit sleutelwoord var
wordt automatisch ook voor het tweede deel geplaatst, omdat dit tweede deel op een komma volgt. Door die komma weet het script dat het hier om twee bij elkaar horende delen van één regel gaat.
Na het tweede deel staat een puntkomma. Dit is het echte einde van deze regel code. In gewone tekst zou je hier een punt gebruiken.
Het is gebruikelijk zo'n tweede, derde, ... deel op een nieuwe regel te laten beginnen en iets in te laten springen. Zo zie je in één oogopslag dat het sleutelwoord var
voor alle twee de delen geldt, dat hier vier variabelen worden aangemaakt: drie in de eerste regel, en één in de tweede regel.
Pardon? Variwiewatwaar? Ha, leuk dat je het vraagt.
var links, aantal, i,
: met het sleutelwoord var
wordt aangegeven dat elk van de erop volgende woorden de naam van een 'variabele' is. Een variabele is een soort portemonnee: er kan van alles in zitten, en de inhoud kan veranderen.
Gelijk na var
volgen de namen van de variabele. Als er meerdere variabelen zijn, zoals hier het geval is, worden die gescheiden door een komma. Hier zijn de variabelen 'links', 'aantal' en 'i' (op 'pad' wordt later teruggekomen).
In 'links', 'aantal' en 'i' wordt dus iets opgeborgen. Omdat de variabele een naam heeft, kan de rest van het script de variabele aanroepen bij deze naam. Net zoals je iemand die 'Marie' heet kunt aanroepen met 'Marie', ongeacht of Marie aardig, onaardig, muzikaal of arrogant is, ongeacht de 'inhoud' van Marie.
Wat er precies in die variabelen wordt opgeslagen, kun je hier opgeven of elders in het script. In dit geval gebeurt dit elders.
Omdat de regel met een komma eindigt, geldt var
ook nog voor de erop volgende regel: pad = location.pathname + "#";
pad
: in deze regel wordt iets opgeslagen in de variabele 'pad'. Omdat het hier om iets heel simpels gaat, wordt dat gelijk hier gedaan. Meer ingewikkelde dingen worden later gedaan, omdat de code daardoor overzichtelijker blijft. (Hoewel dat grotendeels een kwestie van voorkeur is.)
=
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat moet worden opgeslagen.
location
: 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 informatie, die betrekking heeft op de pagina. De informatie in 'window' is weer opgesplitst in allerlei kleinere objecten. Een van die objecten is 'location'. Hierin zit alles dat met het adres van de pagina te maken heeft: protocol, domeinnaam, naam van de pagina, noem maar op.
(Eigenlijk zou je dus window.location.pathname
moeten gebruiken, maar omdat 'window' zo vaak voorkomt, mag je dat weglaten: de browser vult dat automatisch aan.)
pathname
: van het 'location' object wordt de informatie in het onderdeel 'pathname' gebruikt. Hierin zit het volledige pad naar en de naam van de pagina. Als je de pagina met het voorbeeld op de site bekijkt, is het volledige adres "https://www.css-voorbeelden.nl/tekst/ankers/tekst-029.html". Het pad hierin is "/tekst/ankers/tekst-029.html": het adres min het protocol en de naam van het domein. Eventuele toevoegingen na dit pad (zoals '#art-1') staan niet in dit pad.
Dit pad wordt in de variabele met de fantasievolle naam 'pad' opgeslagen. Je kunt nu overal in dit script de variabele 'pad' gebruiken, zodat je niet steeds overal 'tekst/ankers/tekst-029.html' hoeft in te typen.
Maar het belangrijkste voordeel van een variabele: als je dit script op pagina op een andere site dan www.css-voorbeelden.nl gebruikt, wordt het pad van die andere site gebruikt. Zonder dat je iets aan het script hoeft te veranderen.
+
: aan het pad, dat gelijk hierboven is gevonden, wordt nog iets toegevoegd.
"#"
: dit is, wat wordt toegevoegd. Het staat tussen aanhalingstekens, omdat de computer anders niet weet dat het 'n letterteken is. (Computers zijn (nog) niet zo slim. Ze kunnen wel ongelooflijk snel dom zijn, en dat líjkt slim. Zoiets als de tweets van Trump.)
Op de site zou dit alles bij elkaar opleveren: '/tekst/ankers/tekst-029.html#'. (Op een andere site zou het eerste deel, het pad, uiteraard iets anders zijn.) Deze string (in JavaScript heet een stuk tekst een 'string') geeft een mogelijkheid om links binnen de pagina te onderscheiden van links naar buiten de pagina. Elke link binnen de pagina móét dit stukje binnen z'n adres hebben staan. En het adres van een link naar een andere pagina of site, kan dit stukje tekst nooit bevatten.
Mogelijk zou alleen het pad zonder de "#" al voldoende zijn. Maar het zou kunnen dat iemand een of andere exotische link heeft gemaakt, waarin dat pad voorkomt, en die toch geen link binnen de pagina is. Of mogelijk wordt zoiets exotisch in de toekomst ooit bedacht. De combinatie pad + "#" is gereserveerd voor links binnen een pagina, dus hiermee sluit je elk (toekomstig) risico uit.
(In plaats van het sleutelwoord var
kan tegenwoordig beter let
worden gebruikt. Dit doet hetzelfde als var
, maar met enkele verbeteringen. Helaas werkt let
niet op iOS 9 en in UC browser en Android browser op Android 4. Daarom wordt hier nog var gebruikt. Overigens maakt dat in dit script weinig uit.
Hetzelfde geldt voor const
, dat mogelijk ook soms gebruikt had kunnen worden in plaats van var
.)
links = document.getElementsByTagName("a");
links
: in deze regel wordt iets opgeslagen in de al eerder bij var links, aantal, i, ... aangemaakte variabele 'links'. Dat had ook daar kunnen gebeuren, maar het is wat overzichtelijker daar alleen de heel simpele dingen af te handelen. Hoewel dat grotendeels een kwestie van voorkeur is.
Deze regel maakt een lijstje van alle <a>'s op de pagina. Om met dat lijstje te kunnen werken, moeten ze ergens in worden opgeborgen. Dat gebeurt in de variabele 'links'. Niet alleen het <a>-element zelf wordt opgeslagen, dat zou wat zinloos zijn. Er worden ook allerlei gegevens van <a> opgeslagen, zoals de hoogte, de breedte, de bestemming van de link, enzovoort. Er wordt een <a>-'object' opgeslagen: een hele serie gegevens.
=
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat moet worden opgeslagen.
document
: dit geeft aan, waaraan de code van de rest van deze regel gekoppeld moet worden. In document
is de hele pagina opgeslagen op een voor JavaScript toegankelijke manier.
getElementsByTagName
: zoek bepaalde elementen op aan de hand van de naam van de tag. Het maakt niet uit, hoeveel of hoe weinig van die elementen er zijn, ze worden allemaal opgezocht en in links
opgeslagen.
("a")
: de tag waarnaar wordt gezocht, tussen aanhalingstekens. De in de html gebruikte <
en >
worden weggelaten, alleen de naam van de tag wordt gebruikt.
De hele regel nog eens in gewone mensentaal: haal alle <a>'s op de pagina op en berg die op in de variabele links
.
Elk in links
opgeslagen <a>-object heeft een eigen volgnummer, zodat je elk <a>-object apart kunt opvragen, wijzigen, enzovoort. Omdat computers dol zijn op het getal '0', heeft het eerste <a>-object als volgnummer '0'. In dit voorbeeld zijn 211 <a>'s aanwezig, dus er zitten 211 <a>-objecten in links
. Het eerste object kan worden opgevraagd met links[0]
, het tweede met links[1]
, het derde met links[2]
en het 211e en laatste met links[210]
.
(Op de site zelf zitten meer dan 211 <a>'s in de pagina, want daar is ook de navigatie voor de site nog aanwezig. Maar in het voorbeeld in de download zitten precies 211 <a>'s.)
aantal = links.length;
aantal
: de volgende variabele, waarin wat wordt opgeslagen. In deze variabele wordt het aantal <a>'s opgeslagen. Dit is een redelijk simpele handeling en had ook al bij het aanmaken van de variabele bij var links, aantal, i, ... kunnen gebeuren, maar toen was variabele links
nog niet klaar, want die wordt pas gelijk hierboven ingelezen. En die variabele links
is hier nodig, om deze variabele te kunnen maken.
=
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat moet worden opgeslagen.
links
: dit is de variabele die bij links = document.getElementsByTagName("a"); is gevuld met alle <a>'s op de pagina.
length
: de lengte van links
. Er zitten 211 <a>'s in de pagina met het voorbeeld, en in links
zit voor elke <a> een apart object. De lengte van links
is dus 211.
Bij een bepaalde bewerking verderop in het script moet iets voor elke <a> worden gedaan. Tijdens die bewerking moet elke keer opnieuw worden gekeken, hoe lang links
is. Dat kan wel, maar het is efficiënter om dat hier één keer te doen, die lengte op te slaan in variabele aantal
en dan die variabele gebruiken.
Tot nu toe is alleen een aantal noodzakelijke gegevens opgevraagd. Vanaf nu gaat het script echt beginnen.
for (i = 0; i < aantal; i++) {
for
: doe iets met iets, zolang iets waar is. Nou, is dat lekker vaag of niet? Wat er waarmee moet gebeuren, komt later. Dat staat tussen de {}
aan het eind van de regel. (In de echte code staat de laatste }
lager, achter wat er waarmee moet gebeuren.)
Hier eerst het deel dat ervoor zorgt dat elk eerder gevonden <a>-object netjes aan de beurt komt.
(
: met dit haakje opent het deel dat ervoor zorgt, dat elk <a>-object aan de beurt komt.
Aan het eind van de regel staat de bijbehorende ), waardoor het script weet dat dit het einde van dit deel van de code is.
i = 0;
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat, moet worden opgeslagen. In dit geval is dat resultaat heel simpel: het is het getal 0.
De variabele heet hier 'i'. De variabele is eerder al aangemaakt bij var links, aantal, i, ..., maar wordt nu pas echt gebruikt. i
wordt gebruikt als een teller (waarover later meer), en bij dit soort tellers is het gebruikelijk ze de korte naam 'i' te geven. Dat soort gewoontes maakt het voor mensen een stuk makkelijker elkaars code te lezen en te begrijpen.
Omdat i
een variabele is, kan de waarde ervan veranderen, variëren. Wat later in de regel ook gaat gebeuren: elke keer als er een <a>-object is afgehandeld, wordt i
met 1 verhoogd. Dat gebeurt in het laatste deel van de regel.
De ;
geeft aan dat dit stukje code, waarin de variabele i
z'n beginwaarde krijgt, hier eindigt.
i++
: eerst het laatste deel van de regel, het middelste deel komt gelijk hieronder.
Elke keer als een in links
zittend <a>-object is afgehandeld, 1 optellen bij i
. Omdat programmeurs liederlijk lui zijn, wordt 'er 1 bij optellen' ingekort tot ++
.
Als i
0 is, betekent i++
: i
wordt 0 + 1 ('1' dus).
Als i
1 is, betekent i++
: i
wordt 1 + 1 ('2' dus).
Als i
2 is, betekent i++
: i
wordt 2 + 1 ('3' dus).
Als i
210 is, betekent i++
: i
wordt 210 + 1 ('211' dus).
En meer dan 211 wordt het niet, vanwege redenen die gelijk hieronder staan.
(Op een pagina met een ander aantal <a>'s dan 211, zal eerder of later worden gestopt met het verhogen van i
.)
i < aantal;
: het middelste deel van de regel. In aantal
is eerder het aantal <a>-objecten in links
opgeslagen. Omdat er in dit voorbeeld 211 <a>'s op de pagina staan, is de waarde van aantal
211.
i
bevat een getal. Voordat het eerste <a>-object is verwerkt, is dat getal 0, want dat is hierboven opgegeven.
Het teken <
betekent: kleiner dan.
De ;
aan het einde geeft aan, dat dit stukje code, de voorwaarde waaraan moet worden voldaan, hier eindigt.
In gewone mensentaal staat hier: zolang teller i
kleiner is dan aantal
.
Als niet meer aan deze voorwaarde wordt voldaan, als teller i
niet meer kleiner is dan aantal
, stop dan met het uitvoeren van de code die tussen de {}
van de for
-lus staat. Omdat aantal
even groot is als het aantal <a>-objecten in links
, geeft dit een mogelijkheid om elk <a>-object precies één keer te verwerken. En er, als ze allemaal verwerkt zijn, mee te stoppen.
)
: dit haakje hoort bij de (
gelijk achter for
. Tussen deze twee haakjes staat de code die ervoor zorgt dat elk <a>-object aan de beurt komt.
{
: het laatste teken op de regel. Hiermee geef je aan dat hierna de code volgt die uitgevoerd moet worden. Tot nu toe is alleen gezorgd dat er bij elk <a>-object íéts moet gebeuren, maar nog niet wát. Dat wát volgt na deze {
. Na de code die moet worden uitgevoerd staat nog een afsluitende }
. Hiermee geef je aan dat het uitvoerende deel van de code bij de for
-lus hier stopt.
Dat uitvoerende deel is op een nieuwe regel gezet, net zoals de afsluitende }
. Dat soort dingen zijn informele afspraken, omdat het de code voor mensen leesbaarder maakt. Wat de computer betreft zou je alles ook achter elkaar kunnen zetten op één onwijs lange regel. Alleen is niet alleen die regel dan onwijs, ook de gemiddelde programmeur zou heel snel bijzonder onwijs worden, als alles op één lange regel wordt gezet.
Elke keer als een <a>-object is behandeld (met het stukje code tussen de {}
, wat hieronder aan de beurt komt), wordt i
door middel van i++
met 1 verhoogd.
Aan het begin heeft i
de waarde 0. Na de eerste ronde heeft i
de waarde 1. Na de tweede ronde heeft i
de waarde 2. Na de derde ronde heeft i
de waarde 3. Na de 211e ronde heeft i
de waarde 211. Waarmee i
niet meer kleiner is dan aantal
, dan het aantal <a>-objecten.
Omdat niet meer aan de voorwaarde i < aantal
wordt voldaan, wordt gestopt met het behandelen van de <a>-objecten. En dat komt goed uit, want alle <a>-objecten zijn precies allemaal één keer aan de beurt gekomen. Niet meer, niet minder. Bij allemaal is de tussen de {}
staande code één keer toegepast.
De code tussen de haakjes in gewone taal: zet teller i
op 0 als de for
de eerste keer wordt uitgevoerd. Herhaal de for
zolang teller i
lager is dan het aantal <a>-objecten. Verhoog teller i
elke keer als de for
wordt uitgevoerd met 1.
(Deze for
-lus (en alles erin) zou vervangen kunnen door overzichtelijker code met dingen als map
en includes()
. Die werken echter niet in iets oudere browsers. Daarom wordt hier gewoon een for
gebruikt.
Omdat het hier om 'n heel klein script gaat, en omdat deze site niet op JavaScript-goeroes is gericht, is ook afgezien van dingen als een transpiler.)
if (links[i].href.indexOf(pad) > 0) {
Deze regel zit binnen een for-lus en wordt voor elke <a> in de pagina één keer uitgevoerd.
if
: de hierop volgende code wordt alleen uitgevoerd, als aan één of meer voorwaarden is voldaan. Die voorwaarden staan tussen de haakjes achter if
. Hier gaat het maar om één voorwaarde: links[i].href.indexOf(pad) > 0
.
links[i]
: in de variabele links
zijn bij links = document.getElementsByTagName("a"); alle <a>'s in de pagina ingelezen. Voor elke <a> is één zogenaamd object in links
opgeslagen. In dat object zit allerlei informatie over die betreffende <a>, zoals de breedte en hoogte van de link, de bestemming, enzovoort. Van een deel van die informatie wordt in deze regel gebruik gemaakt.
Achter links
staat nog iets: [i]
. De teksthaken geven alleen maar aan dat het hier om een soort teller gaat, die hebben verder geen functie. i
is weer een variabele, waarin het volgnummer van de <a> zit, die aan de beurt is. Elke keer als een <a> is bekeken, verhoogt de for-lus, waar deze regel in zit, i
met 1, net zolang tot alle <a>'s zijn behandeld.
De eerste keer staat hier dus eigenlijk links[0]
voor de eerste <a>, (een computer begint meestal met '0' te tellen, waar mensen met 1 beginnen), de tweede keer links[1]
voor de tweede <a>, enzovoort, tot alle <a>'s zijn bekeken.
href
: dit is zo'n stukje informatie dat in het hierboven genoemde object zit. In href
zit de volledige bestemming van de link, inclusief protocol, domein, enzovoort. Ook al heb je zelf in de html een kortere bestemming ingetypt, in href
zit toch het volledige adres.
In de html van het voorbeeld is de link naar artikel 1 <a href="#art-1">
. In de href
uit het object dat bij deze <a> hoort, staat echter: 'https://www.css-voorbeelden.nl/tekst/ankers/tekst-029.html#art-1'. Daar hoef je zelf niets voor te doen, dat regelt de browser.
indexOf(pad)
: dit is een in JavaScript ingebouwde functie. Een functie is een stukje bij elkaar horende code, dat je makkelijk kunt uitvoeren. Je roept de naam van de functie (hier 'indexOf()'), en het beestje begint te werken.
Je kunt zelf functies maken, maar JavaScript bevat ook al een groot aantal ingebouwde functies voor handelingen die vaak voorkomen. indexOf()
is zo'n ingebouwde functie.
De haakjes achter de naam geven aan dat het om een functie gaat. Tussen die haakjes staat vaak informatie die de code in de functie kan gebruiken. Dat is hier ook het geval: aan de functie wordt de variabele pad
doorgegeven. In die variabele pad
is bij pad = location.pathname + "#"; het pad naar en de naam van de pagina opgeslagen, plus het teken '#'. Op de site is de inhoud van pad
'/tekst/anker/tekst-029.html#'. (Op een andere site zal het deel voor de '#' er anders uitzien.)
Functie indexOf()
kan nu iets doen met de inhoud van pad
kijken of die inhoud in de href
van de <a> voorkomt:
links[i].href.indexOf(pad)
Dit moet je van links naar rechts lezen:
links[i]
: de <a> die aan de beurt is.
href
: het volledige adres van die <a>.
indexOf(pad)
: kijk of de inhoud van pad
in het adres in die href
zit.
Als de inhoud van pad
in het adres van de link zit, kan het niet anders, dan dat het om een link binnen de pagina gaat.
indexOf()
laat met behulp van een getal weten, of de inhoud van pad
wel of niet in het adres in href
zit. Als (op de site) '/tekst/ankers/tekst-029.html#' in de href
zit, wordt het volgnummer van de letter waar '/tekst/ankers/tekst-029.html#' begint in het adres in href
geretourneerd door indexOf()
. Als de inhoud van pad
niet in het adres van href
zit, wordt -1 geretourneerd door indexOf()
.
>
: met het hierboven door indexOf()
geretourneerde getal, kan iets worden gedaan. In dit geval wordt met behulp van het groterdanteken >
gekeken, of dat getal groter is dan een ander getal, dat gelijk op dit teken volgt.
0
: als de inhoud van pad
niet in het adres van href
zat, retourneert indexOf()
het getal -1. Als het geretourneerde getal groter is dan 0, móét de inhoud van pad
dus ergens in het adres van href
zitten. Soms is het handig om te weten, waar iets precies zit, maar dat is hier niet van belang. Het gaat er hier alleen maar om, óf de inhoud van pad
in het adres van href
zit.
{
: de code die eventueel moet worden uitgevoerd, staat tussen twee accolades {}
. Het gaat hier maar om één regel code, maar dat maakt niets uit. Aan het eind van de bij de if
horende code staat de bijbehorende }
.
In gewone mensentaal staat hier: als in de bestemming van de <a> die wordt bekeken het pad naar de pagina (plus het teken '#') staat, voer dan de code tussen de {}
bij de if
uit, want dan is aan de voorwaarde van de if
voldaan.
Omdat alleen aan die voorwaarde is voldaan, als het om een interne link in de pagina gaat, wordt de bij de if
horende code dus alleen uitgevoerd voor links binnen de pagina. Alle andere links blijven werken, zoals ze altijd werken. (In dit geval houdt dat in dat alle andere links gewoon in de geschiedenis van de browser worden opgeslagen.)
links[i].addEventListener("click", geenHistory);
Dit deel van het script wordt alleen uitgevoerd, als aan deze eerder gestelde voorwaarde is voldaan:
– de bestemming van de <a> die wordt bekeken moet '/tekst/ankers/tekst-029.html#' bevatten. (Dit is het pad op de site met het voorbeeld, op een andere site zal het deel voor de '#' er anders uitzien.)
links[i]
: in de variabele links
zijn bij links = document.getElementsByTagName("a"); alle <a>'s op de pagina opgeslagen. (Feitelijk is voor elke <a> een object opgeslagen, waarin allerlei informatie over de <a> zit, zoals de bestemming van de link. Van die informatie wordt later nog gebruik gemaakt.)
De teksthaken []
geven aan dat hierin een teller zit. Die teller is hier de variabele i
. In de for-lus, waarbinnen deze regel staat, heeft i
het volgnummer gekregen van de <a> die aan de beurt is.
addEventListener
: er wordt een zogenaamde 'eventlistener' gekoppeld aan het voor de punt staande deel. Dat is hier links[i]
, de <a> die aan de beurt is.
Een eventlistener luistert naar een gebeurtenis. Die gebeurtenis, de 'event', kan van alles zijn: het indrukken van een toets, klikken, scrollen, de video is afgespeeld, van alles. Tussen de haakjes van addEventListener()
staat, naar welke soort gebeurtenis moet worden geluisterd, en wat er moet gebeuren, als die gebeurtenis zich voordoet. Zeg maar 'n soort rampenplan: áls gebeurtenis is 'doodsmak', dán handeling 'bel 112'.
"click"
: tussen aanhalingstekens, zodat het script weet dat dit een letterlijke naam is (dit is gewoon een van de taalkundige regels van JavaScript). Dit is de naam van de gebeurtenis, waarnaar wordt geluisterd, waarop wordt gewacht: 'click'. Er wordt geluisterd of op de <a> wordt geklikt, of dat de <a> wordt aangeraakt. (Toen dit werd bedacht, kon je alleen klikken, dus de naam 'click' loopt wat achter.) Als de <a> door gebruik van de Tab-toets focus heeft gekregen, geldt het indrukken van Enter ook als een klik.
geenHistory
: deze naam staat niet tussen aanhalingstekens, omdat het hier niet om een letterlijke naam of zo gaat. De naam verwijst naar een 'functie', iets wat moet gebeuren. Die functie staat iets hieronder bij function geenHistory (e) { en voorkomt dat de <a>, als deze wordt gevolgd, wordt opgeslagen in de geschiedenis van de browser. Hierdoor wordt de <a> genegeerd bij gebruik van de Terug- of Vooruit-toets van de browser, en bij gebruik van toetscombinaties als alt+←.
(Probeer op dit moment vooral niet de logica van wel of geen aanhalingstekens te begrijpen. Het makkelijkste is om dat soort dingen maar gewoon te accepteren. Nederlands heeft ook zo z'n eigenaardigheden...)
;
: aan het eind van elke regel staat een puntkomma. Daarmee geef je aan dat de regel is afgelopen. In een gewoon boek zou je hier een punt gebruiken, om aan te geven dat een nieuwe zin begint.
De hele regel nog eens in gewone mensentaal: als een <a> wordt gevolgd, voer dan functie 'geenHistory ()' uit.
Eerder is bij if (links[i].href.indexOf(pad) > 0) { een voorwaarde voor het uitvoeren van deze code opgegeven: in het adres moet '/tekst/ankers/tekst-029.html#' voorkomen. Hierdoor wordt deze regel alleen uitgevoerd voor links binnen de pagina zelf. Alleen bij links binnen de pagina, wordt functie geenHistory ()
aangeroepen.
function geenHistory (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 link wordt aangeklikt of -geraakt. (Of, als de link focus heeft, door het indrukken van Enter.) Het luisteren naar een aanraking of klik wordt geregeld bij links[i].addEventListener("click", geenHistory);
De code in deze functie voorkomt dat de gevolgde link in de geschiedenis van de browser wordt opgeslagen.
function
: het sleutelwoord waarmee het begin van een functie wordt aangegeven.
geenHistory
: 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.)
(e)
: die haakjes horen nou eenmaal zo na de naam van een functie. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie. 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 klikken op of aanraken van een <a>. In e
zit bijvoorbeeld de hoogte en breedte van de <a>. En of toevallig ook Shift is ingedrukt. En nog 'n waanzinnige hoop andere informatie, waarvan het overgrote deel hier verder niet wordt gebruikt.
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 volgen van een <a>. 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 }
.
location.replace(e.target.href);
Deze regel is onderdeel van function geenHistory (e)
In deze ene regel gebeurt eigenlijk alles. De rest van het script was alleen voorbereiden, de juiste <a>'s eruit filteren, en dergelijke. Maar Hier Gebeurt Het. Dus.
Als een link wordt gevolgd, wordt deze normaal genomen opgeslagen in de geschiedenis van de browser. Met de Terug- en Vooruit-toets van de browser, en met toetscombinaties als Alt+← en Alt+→, kun je door die geschiedenis bladeren. Op die manier kun je snel eerder bezochte pagina's terugvinden.
Op deze pagina zijn 211 <a>'s aanwezig, waarvan er 210 een link vanuit de inhoudsopgave naar de tekst in <main> zijn. Het is tamelijk zinloos om al die links binnen de pagina in de geschiedenis op te slaan. Je zou dan, als je elke link in de inhoudsopgave hebt gevolgd, 210 keer de Terug-toets moeten indrukken, voordat je bij 'n vorige pagina aankomt.
Deze regel zorgt ervoor dat de link wel wordt gevolgd, maar dat deze niet in de geschiedenis terecht komt. Je kunt er nog wel gewoon 'n favoriet (of bookmark, of hoe het beestje ook heet) van maken. Ook zit het adres nog gewoon in de lijst met bezochte adressen.
location
: 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 informatie, die betrekking heeft op de pagina. De informatie in 'window' is weer opgesplitst in allerlei kleinere objecten. Een van die objecten is 'location'. Hierin zit alles dat met het adres van de pagina te maken heeft: protocol, domeinnaam, naam van de pagina, noem maar op.
(Eigenlijk zou je dus window.location.pathname
moeten gebruiken, maar omdat 'window' zo vaak voorkomt, mag je dat weglaten: de browser vult dat automatisch aan.)
De informatie die in location
zit, kan worden gewijzigd. Als dat gebeurt, verschijnt er een nieuw adres in de adresbalk van de browser, en de browser zal naar het nieuwe adres gaan.
Vanwege de veiligheid kan een adres alleen maar binnen dezelfde site worden veranderd. Vanwege diezelfde veiligheid zijn er ook beperkingen, als je dit script op de desktop uitvoert. Testen kan om die reden alleen online, of als je zelf 'n server installeert. Een iets uitgebreider verhaal hierover is te vinden bij Dit script manipuleert...
replace
: dit is een in JavaScript ingebouwde functie, een stukje bij elkaar horende code. Dat het een functie is, kun je weer zien aan de ()
achter de functie. De code in deze functie wordt uitgevoerd: vervang ('replace') het adres met het adres dat tussen de haakjes achter replace
staat.
Je kunt het adres op meerdere manieren veranderen. In dit geval is het voordeel van replace()
dat het nieuwe adres niet in de geschiedenis van de browser wordt opgeslagen. Je kunt er nog wel gewoon 'n favoriet (of bookmark, of hoe het beestje ook heet) van maken. Ook zit het adres nog gewoon in de lijst met bezochte adressen.
(e.target.href)
: dit is het nieuwe adres, alleen is het zo op het oog niet echt herkenbaar als een adres. Het adres zit verstopt in een variabele.
e
: dit is de e
die tussen de haakjes bij function geenHistory (e) stond. e
is een object met een hele berg aan informatie over de link, die is aangeraakt of -geklikt. Deze informatie is beschikbaar voor de code binnen de functie en kan hier dus worden gebruikt.
Omdat een browser niet zo slim is, moet je hem wel even vertellen dat hij in e
moet zoeken, vandaar dat e
aan het begin staat.
target
: dit is de specifieke <a>, en alle bij die <a> horende informatie, die is aangeraakt of -geklikt. In e
zit nog meer informatie, zoals waar precies op het scherm is geklikt. Maar in target
zit de informatie die bij de <a> hoort.
href
: in href
zit het adres van de <a>. Bij <a href="#art-1">
(de link uit de inhoudsopgave naar artikel 1) is dat bijvoorbeeld 'https://www.css-voorbeelden.nl/tekst/ankers/tekst-029.html#art-1'. In de html staat als doel in de href
alleen '#art-1", maar de browser maakt daar automatisch een volledig adres van. (Dit adres hoort natuurlijk bij de site met dit voorbeeld. Op een andere site zul je 'n ander adres krijgen.)
e.target.href
: bij elkaar: het doel van de <a>, aangevuld tot het volledige adres.
De hele regel in normale mensentaal: vervang het adres van de pagina door het adres van de link, waarop is geklikt (of die is aangeraakt, of op 'n andere manier is gevolgd). Als gevolg hiervan zal de browser naar het nieuwe adres gaan: het doel van de <a> in de inhoudsopgave. Dit nieuwe adres wordt ook zichtbaar in de adresbalk bovenin de browser. (Niet alle browsers tonen het volledige adres.)
Hoewel dit adres niet in de geschiedenis van de browser wordt opgeslagen, kan er gewoon een favoriet of bookmark (of hoe het beestje verder ook heet) van worden gemaakt. Ook staat het adres gewoon in de lijst met bezochte pagina's.