Uitleg tijdelijk afbeelding laten overvloeien in vervangende afbeelding
Laatst aangepast: .
Korte omschrijving
Als je de knop indrukt door deze aan te raken, aan te klikken of met het toetsenbord te bedienen, wordt de originele afbeelding langzaam vervangen door een andere afbeelding. Door de knop nogmaals in te drukken, komt de originele afbeelding weer terug.
BELANGRIJK
Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.
Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.
Als je dit lastig vindt, kun je bovenaan de pagina de hele handel downloaden. In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.
Als je deze handleiding graag uitprint (zonde van het bos), gebruik dan de pdf in de download. Deze pagina is niet geoptimaliseerd voor printen, de pdf kan wel makkelijk worden geprint.
Alles op deze site kan vrij worden gebruikt, met drie beperkingen:
* Je gebruikt het materiaal op deze site volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte info zitten. Voor eventuele schade die door gebruik van materiaal van deze site ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.
* Deze uitleg wordt min of meer regelmatig bijgewerkt. Het is daarom niet toegestaan deze uitleg op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat de uitleg afkomstig is van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.
* Het kan zijn dat materiaal is gebruikt dat van anderen afkomstig is. Dat materiaal kan onder een bepaalde licentie vallen, waardoor het mogelijk niet onbeperkt gebruikt mag worden. Als dat zo is, wordt dat vermeld onder Inhoud van de download en licenties.
Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.
Alle code is geschreven in een afwijkende
lettersoort en -kleur. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles vanwege de leesbaarheid in een gewone letter.)
Opmerkingen
- De foto's zijn gemaakt in het Vondelpark in Amsterdam op Koninginnedag 2009. Als je jezelf herkent en de originele foto wilt hebben, stuur dan even 'n mailtje naar info@css-voorbeelden.nl.
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
Deze versie werkt fundamenteel anders dan vorige versies.
In vorige versies werden 75 <span>'s gebruikt, die allemaal 0 px breed en hoog waren. Elke <span> had als achtergrond-afbeelding de vervangende afbeelding. Omdat de <span>'s geen breedte en hoogte hadden, zag je de vervangende afbeelding niet. Bij hoveren over een <span> werd deze even breed en hoog gemaakt als de vervangende afbeelding, waardoor deze zichtbaar werd. Van boven naar beneden werd elke <span> iets minder doorzichtig. Als je met de muis van boven naar beneden over de <span>'s ging, verscheen hierdoor de vervangende afbeelding geleidelijk.
Dit werkt dus voor geen meter op touchscreens. Je zou met behulp van bloed, zweet, JavaScript en tranen iets soortgelijks kunnen maken, maar deze site is meer gericht op css. En met css krijg je dit dus op bovenstaande manier niet werkend.
Nog los van de problemen met hoveren op een touchscreen, is een vinger veel grover dan een muis. Als je een vinger als muis gebruikt, krijg je nooit een vloeiende overgang tussen de twee afbeeldingen. Je zou je bezoekers kunnen vragen hun wijsvinger bij te punten met een puntenslijper, maar dat ligt mogelijk wat gevoelig. Letterlijk en figuurlijk.
css3 geeft nieuwe mogelijkheden, die eerder stomweg niet bestonden.
De originele afbeelding en de vervangende afbeelding zijn beide gewone afbeeldingen. De vervangende afbeelding staat absoluut gepositioneerd boven de originele afbeelding, maar is volledig doorzichtig gemaakt. Je ziet dus bij openen van de pagina de originele afbeelding, hoewel die eigenlijk onder de vervangende afbeelding zit.
(Als je de originele afbeelding opent in een nieuw tabblad, kun je dat ook zien: niet de originele afbeelding wordt getoond, maar de vervangende. Want die is dan niet meer onzichtbaar. Dit heeft als bijwerking dat je de originele afbeelding niet kunt kopiëren, tenzij je css uitzet.)
De knop boven de afbeelding is eigenlijk een aankruisvakje. Als je dat aankruisvakje aanvinkt, wordt de vervangende afbeelding langzaam steeds minder doorzichtig, waardoor deze geleidelijk aan zichtbaar wordt. En de originele afbeelding verbergt. Omdat een aankruisvakje hier foeilelijk is, is dat verborgen onder de bij het aankruisvakje horende <label>, die eruit ziet als 'n soort knop.
Het terugzetten naar de originele afbeelding gebeurt zonder vertraging, maar als je bij #vervang
een waarde opgeeft voor transition-delay
kun je ook dat met een vertraging doen.
Omdat de knop eigenlijk een gewoon aankruisvakje is, kan deze ook door gebruikers van de Tab-toets worden bediend. (Met de Spatiebalk kun je het aankruisvakje aan- en uitvinken). Omdat dit niet gelijk duidelijk zal zijn, verschijnt bij gebruik van de Tab-toets gelijk voor het aankruisvakje wordt bereikt een kleine uitleg. Deze staat normaal genomen buiten het browservenster en is alleen zichtbaar, als je de Tab-toets gebruikt.
Ook schermlezers lezen deze korte uitleg voor, want dat die buiten het browservenster staat, maakt voor een schermlezer niets uit.
Schermlezers hebben wel een eigen probleem. Beide afbeeldingen zijn altijd aanwezig, al zie je er steeds maar één. Van beide afbeeldingen wordt dan ook altijd de alt-tekst gelezen, ongeacht welke afbeelding je ziet. Of de vervangende afbeelding zichtbaar of onzichtbaar is, maakt niets uit: een schermlezer kijkt alleen naar de alt-tekst. En die is gewoon aanwezig, van beide afbeeldingen.
Dit is nogal verwarrend. Daarom wordt voor schermlezers een beetje JavaScript gebruikt. Afhankelijk van of het aankruisvakje is aangevinkt of niet, wordt met behulp van aria-hidden één van beide afbeeldingen inclusief bijbehorende alt-tekst voor schermlezers verborgen. Nu wordt alleen de alt-tekst van de afbeelding die zichtbaar is voorgelezen.
Voorwaarden van het JavaScript waaraan html en css moeten voldoen
Er is steeds maar één afbeelding zichtbaar, de originele of de vervangende. Maar schermlezers lezen altijd beide alt-teksten voor, wat verwarrend is. Om dat te voorkomen, wordt een beetje JavaScript gebruikt. zonder dit script werkt alles nog gewoon, maar schermlezers lezen dan dus altijd beide alt-teksten voor.
Om dit script goed te laten werken, moet de html aan een aantal voorwaarden voldoen.
Id's
- De <input type="checkbox"< moet een id="toon" hebben. Als je een andere id wilt gebruiken in de html, moet je die ook in het script en in de css wijzigen.
- De originele <img> moet een id="origineel" hebben. Als je een andere id wilt gebruiken in de html, moet je die ook in het script en in de css wijzigen.
- De vervangende <img> moet een id="vervang" hebben. Als je een andere id wilt gebruiken in de html, moet je die ook in het script en in de css wijzigen.
Het script gebruikt deze id's om de bijbehorende elementen te kunnen vinden. Als het aankruisvakje wordt aan- of uitgevinkt, wordt door het script bij de beide afbeeldingen de waarde van aria-hidden
veranderd van true
in false
, en van false
in true
. (Als je die verandering wilt bekijken, moet je niet in de gewone code, maar in de Gegenereerde code kijken.)
Semantische elementen en WAI-ARIA
Deze twee onderwerpen zijn samengevoegd, omdat ze veel met elkaar te maken hebben.
Semantische elementen
De meeste elementen die in html worden gebruikt, hebben een semantische betekenis. Dat wil zeggen dat je aan de gebruikte tag al (enigszins) kunt zien, wat voor soort inhoud er in het element staat. In een <h1> staat een belangrijke kop. In een <h2> staat een iets minder belangrijke kop. In een <p> staat een alinea. In een <table> staat een tabel (en geen lay-out, als het goed is!). Enzovoort.
Door het op de goede manier gebruiken van semantische elementen, kunnen zoekmachines, schermlezers, enzovoort de structuur van een pagina begrijpen. De spider van een zoekmachine is redelijk te vergelijken met een blinde. Het is dus ook in je eigen belang om semantische elementen zo goed mogelijk te gebruiken. Een site die toegankelijk is voor mensen met een handicap, is in de regel ook goed te verwerken door een zoekmachine en maakt dus een grotere kans gevonden en bezocht te worden.
Als het goed is, wordt het uiterlijk van de pagina bepaald met behulp van css. Het uiterlijk staat hierdoor (vrijwel) los van de semantische inhoud van de pagina. Met behulp van css kun je een <h1> heel klein weergeven en een <h6> heel groot, terwijl schermlezers, zoekmachines, en dergelijke nog steeds weten dat de <h1> een belangrijke kop is.
Slechts enkele elementen, zoals <div> en <span>, hebben geen semantische betekenis. Daardoor zijn deze elementen uitstekend geschikt om met behulp van css het uiterlijk van de pagina aan te passen: de semantische betekenis verandert niet, maar het uiterlijk wel. Voor een schermlezer of zoekmachine verandert er (vrijwel) niets, voor de gemiddelde bezoeker krijgt het door de css een heel ander uiterlijk.
(De derde laag, naast html voor de inhoud en css voor het uiterlijk, is JavaScript. Die zorgt voor de interactie tussen site en bezoeker. De min of meer strikte scheiding tussen css en html aan de ene kant en JavaScript aan de andere kant is met de komst van css3 en html5 veel vager geworden. Je kunt nu bijvoorbeeld ook met css dingen langzaam verplaatsen en met html deels de invoer in formulieren controleren.)
Html5 heeft een aantal nieuwe elementen, die speciaal zijn bedoeld om de opbouw van een pagina aan te geven. In dit voorbeeld wordt hiervan alleen <main> gebruikt. <main> gedraagt zich als een gewone <div>, maar dan een <div> met een semantische betekenis. Hierdoor kunnen schermlezers, zoekmachines, en dergelijke beter zien, hoe de pagina is samengesteld. De meeste schermlezers kunnen dit soort elementen ook gebruiken om snel over de pagina te navigeren.
<main>
Hierbinnen staat de belangrijkste inhoud van de pagina (in dit voorbeeld zijn dat de originele en vervangende afbeelding met alles erop en eraan).
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.
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, zodat dit niet wordt voorgelezen. Op de normale weergave op het scherm heeft dit verder geen enkele invloed.
Bij een afbeelding leest een schermlezer de bij de afbeelding horende alt-tekst voor. Op het scherm is altijd maar één afbeelding te zien, maar in werkelijkheid zijn beide afbeelding altijd aanwezig, inclusief beide alt-teksten. Een schermlezer zal daarom altijd beide alt-teksten voorlezen, ongeacht welke afbeelding zichtbaar is.
Dit is natuurlijk heel verwarrend. Bovendien is niet elke gebruiker van een schermlezer helemaal blind, en dan is het mogelijk nóg verwarrender: je ziet één afbeelding, maar hoort twee alt-teksten.
Daarom wordt met behulp van aria-hidden
steeds één van beide afbeeldingen verborgen voor schermlezers, inclusief de bijbehorende alt-tekst.
Als de pagina wordt geopend, ziet de html voor de afbeeldingen er als volgt uit:
<img id="origineel" aria-hidden="false" src="053-pics/levend-standbeeld.jpg" alt="Originele (...) Amsterdam">
<img id="vervang" aria-hidden="true" src="053-pics/gitaristen.jpg" alt="Vervangende (...) Amsterdam">
Bij opening van de pagina is img#origineel
, de originele afbeelding, zichtbaar. Deze heeft het attribuut aria-hidden="false"
: niet verbergen voor schermlezers. (Eigenlijk kun je dit hier weglaten, want dit is standaard zo. Maar om de bedoeling van deze constructie duidelijker te maken, wordt het toch gebruikt.)
Vervangende afbeelding img#vervang
is bij openen van de pagina niet zichtbaar, en daar staat het attribuut aria-hidden="true"
: verberg voor schermlezers. Het attribuut geldt voor alles, wat binnen de <img>-tag zit, dus ook de alt-tekst van de vervangende afbeelding wordt hierdoor verborgen.
Met behulp van een paar regels JavaScript wordt gekeken, of het aankruisvakje wordt aan- of uitgevinkt. Als het wordt aangevinkt, wordt de vervangende afbeelding getoond. false
en true
bij aria-hidden
wordt dan omgedraaid: de originele afbeelding krijgt nu aria-hidden="true"
, en de vervangende afbeelding krijgt aria-hidden="false"
.
Op het scherm is de vervangende afbeelding zichtbaar, en de bijbehorende alt-tekst is nu niet meer verborgen voor schermlezers. Tegelijkertijd wordt de alt-tekst van de originele afbeelding juist wel verborgen.
Als het aankruisvakje weer wordt uitgevinkt, gebeurt het omgekeerde.
(De reden dat display: none;
en dergelijke niet gebruikt kan worden, om één van beide afbeeldingen te verbergen, staat bij opacity: 0;.)
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.
tabindex="0"
Volgens de specificatie van html 4.01 moest een tabindex="0"
pas worden bezocht, nadat tabindexen met een positief nummer waren bezocht. Sommige browsers hielden zich hier echter niet aan: een tabindex="0"
werd gewoon tussen de positieve tabindexen gezet.
In html5 is de situatie nog fijner. Nu staat er alleen dat, wat betreft de volgorde, de browser mag doen wat hij wil. Oftewel: doe maar raak. Maar hoe dan ook: als je tabindex="0"
gebruikt, kan een element focus krijgen met behulp van de Tab-toets. Ook als dat element normaal genomen geen focus kan krijgen.
(In de praktijk blijkt trouwens dat alle browsers de volgorde van de html aanhouden bij tabindex="0"
, nadat eerst alle tabindexen met een positief nummer zijn bezocht.)
Het aankruisvakje dat onder de knop zit verstopt, kan worden bediend met de Spatiebalk. Gebruiker van de Tab-toets zullen weten, hoe je een aankruisvakje aan- of uitvinkt, maar dit aankruisvakje is niet herkenbaar als aankruisvakje. Daarom is een korte uitleg voor gebruikers van de Tab-toets toegevoegd:
<p id="uitleg" tabindex="0">Gelijk op deze tekst volgt een aankruisvakje, vermomd als knop. Als je dit aanvinkt (met Spatiebalk of op soortgelijke wijze), wordt de daaronder staande afbeelding vervangen door een andere.</p>
Deze tekst is links buiten het browservenster neergezet, zodat deze onzichtbaar is. Omdat de gemiddelde gebruiker van de Tab-toets niet helderziend is, schiet dat niet echt op. Daarom is aan de <p> met de uitleg het attribuut tabindex="0"
toegevoegd. Normaal genomen reageert een <p> niet op de Tab-toets, maar door deze toevoeging kan de <p> de focus krijgen. Bij #uitleg:focus wordt p#uitleg
dan binnen het browservenster gezet, zodat de uitleg zichtbaar wordt.
Bij nogmaals indrukken van de Tab-toets verliest p#uitleg
de focus weer, waardoor de uitleg weer buiten het browservenster wordt neergezet.
tabindex="..."
Op de plaats van de puntjes moet een positief getal worden ingevuld: het volgnummer. Een element met een positieve tabindex
wordt altijd bezocht bij gebruik van de Tab-toets, ook als dit element normaal genomen zou worden genegeerd. Elementen met een tabindex
met een positief volgnummer worden altijd als eerste bezocht, voor elementen als een link of tekstveld zonder tabindex
, en ook voor elementen met tabindex="0"
.
Muis, toetsenbord, touchpad en touchscreen
Vroeger, toen het leven nog mooi was en alles beter, waren er alleen monitors. Omdat kinderen daar niet af konden blijven met hun tengels, besloten fabrikanten dan maar touchscreens te gaan maken, omdat je die mag aanraken. Het bleek makkelijker te zijn om volwassenen ook te leren hoe je 'n scherm vies maakt, dan om kinderen te leren met hun vingers van de monitor af te blijven.
Zo ontstonden touchscreens en kreeg het begrip ellende een geheel nieuwe lading. In de perfecte wereld van vroeger, waarin alleen desktops bestonden, werkten dingen als hoveren, klikken en slepen gewoon. Zonder dat je eerst 'n cursus hogere magie op Zweinstein hoefde te volgen. Zelfs in JavaScript was het nog wel te behappen, ook voor mensen zoals ik die toevallig niet Einstein heten.
Op dit moment kun je computerschermen ruwweg in twee soorten indelen: schermen die worden aangeraakt, en schermen die worden bediend met hulpmiddelen als een toetsenbord, muis of touchpad. Omdat ook computerschermen zich kennelijk vermengen, bestaan er inmiddels ook schermen die zowel van aanraken als van muizen houden.
Hieronder staat een lijstje met dingen die zijn aangepast voor de verschillende soorten schermen, zodat dit voorbeeld overal werkt. Een touchpad werkt ongeveer hetzelfde als een muis. Als hieronder iets over een muis staat, geldt dat ook voor een touchpad.
:hover
Omdat :hover
mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :hover
tonen.
Je hovert over een element, als je met behulp van muis of touchpad de cursor boven dat element brengt. Hoveren kan over álle elementen. Het wordt veel gebruikt om iets van uiterlijk te laten veranderen, een pop-up te laten verschijnen, en dergelijke.
Op een touchscreen wordt hoveren vaak hetzelfde afgehandeld als een aanraking.
:hover
wordt in dit voorbeeld niet gebruikt.
:focus
Omdat :focus
mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :focus
tonen.
De meeste mensen gaan met een muis naar een link, invoerveld, en dergelijke. Waarna ze vervolgens klikken om de link te volgen, tekst in te voeren, of wat ze ook maar willen doen. (Dit geldt uiteraard niet voor touchscreens.)
Er is echter 'n tweede manier om naar links, invoervelden, en dergelijke te gaan: met behulp van de Tab-toets kun je naar links, invoervelden, en dergelijke 'springen'. (Over het gebruik van de Tab-toets staat meer bij Tabindex en Tab-toets.)
Waar je staat, wordt door alle browsers aangegeven met een of ander kadertje. De link en dergelijke met het kadertje eromheen 'heeft focus'. Dat wil zeggen dat je die link volgt, als je op de Enter-toets drukt, of dat je in dat veld tekst kunt gaan invoeren, enzovoort.
Het kadertje dat de focus aangeeft, moet nooit zonder meer worden weggehaald. Gebruikers van de Tab-toets hebben dan geen idee meer, waar ze zijn. In dit voorbeeld gebeurt dat echter onbedoeld wel.
Als een aankruisvakje <input type="checkbox"> de focus heeft, komt het kadertje rondom het aankruisvakje te staan. Dat aankruisvakje wordt hier echter verborgen onder de bijbehorende <label>, en die krijgt bij focus geen kadertje. Logisch, want een <label> kan allerlei afmetingen hebben en op allerlei verschillende plaatsen worden neergezet.
Daarom krijgt hier, als het aankruisvakje de focus heeft, de bijbehorende <label> bij #toon:focus + label een brede blauwe rand. Voor zover de browser dat ondersteunt, gebeurt dat alleen als de Tab-toets wordt gebruikt, en niet bij aanraken of aanklikken van de <label>. Dat is ook niet nodig, want bij gebruik van een muis of bij een aanraking, weet je uiteraard, wat je hebt aangeraakt of aangeklikt.
:active
Omdat :active
mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :active
tonen.
Een element is actief, als de muis wordt ingedrukt boven dat element. Op sommige touchscreens is het element actief, als het wordt aangeraakt.
:active
wordt niet gebruikt in dit voorbeeld.
Gegenereerde code
Het onderstaande geldt alleen voor desktopbrowsers. In browsers op mobiele systemen is het vaak ook mogelijk gegenereerde code te bekijken, maar dat is veel ingewikkelder. Bovendien verandert de manier, waarop dat kan, nogal snel.
Als je html schrijft, kan dat (hopelijk) in de browser worden weergegeven. Vanuit de browser kun je die html bekijken, precies zoals je hem hebt ingevoerd. Alsof je het in een editor ziet. In Firefox bijvoorbeeld kan dat door in het menu te kiezen voor Extra → Webontwikkelaar → Paginabron. (Of door de veel snellere sneltoets Ctrl+U.) Elke browser heeft dit soort mogelijkheden.
Wat je dan te zien krijgt, is exact de code, zoals jij die hebt ingetypt. Inclusief alle fouten, hoofd- en kleine letters, noem maar op. Als je zo slordig bent om een <p> niet af te sluiten, zit er niet plotsklaps een afsluitende </p> in de code. Als er css wordt gebruikt, html wordt ingevoegd via JavaScript, noem maar op, zie je daar niets van, want dat heb jij niet ingetypt.
Daar heb je dus eigenlijk vrij weinig aan, want die code kende je al. Die heb je zelf fluitend of met bloed, zweet en tranen zitten intypen.
Wat de browser daadwerkelijk gebruikt, is iets totaal anders: de gegenereerde code. En die is veel interessanter, want die code blijkt (fors) af te wijken, van wat jij heb ingetypt. De browser gebruikt een tijdelijke kopie van de door jou geschreven code, die zo is aangepast dat er voor de browser mee is te werken.
Elke browser heeft inmiddels mogelijkheden om de gegenereerde code te bekijken. In Firefox bijvoorbeeld in het menu Extra → Webontwikkelaar → Webontwikkelaarshulpmiddelen. In Google Chrome in het menu onder Meer hulpprogramma's → Hulpprogramma's voor ontwikkelaars. In Edge open je dit door op F12 te drukken, en het kan vast ook via het menu.
Houdt er wel rekening mee dat elke browser de door jou ingetypte code iets zal aanpassen. In Firefox bijvoorbeeld wordt een <P> veranderd in een <p>. Als er 'n </p> mist, is die opeens wel aanwezig in de gegenereerde code. Wat elke browser precies aanpast, zal iets verschillen en kan ook nog veranderen. In het verleden veranderde Internet Explorer bijvoorbeeld een <p> juist in een <P>, nu is dat niet meer zo.
Als je met behulp van JavaScript elementen invoegt (zoals in dit voorbeeld gebeurt), zie je die alleen in deze gegenereerde code.
De code aanpassen aan je eigen ontwerp
- Als je dit voorbeeld gaat aanpassen voor je eigen site, houd het dan in eerste instantie zo eenvoudig mogelijk. Ga vooral geen details invullen.
-
Gebruik geen FrontPage, Publisher of Word (alle drie van Microsoft). Publisher en Word zijn niet bedoeld om websites mee te maken. FrontPage is zwaar verouderd en wordt al jaren niet meer onderhouden door Microsoft.
Ook OpenOffice en LibreOffice leveren een uiterst beroerd soort html af. Tekstverwerkers met al hun toeters en bellen zijn gewoon niet geschikt om websites mee te bouwen.
Je kunt beter een goed (gratis) programma gebruiken. Links naar dat soort programma's vind je op de pagina met links onder Gereedschap → wysiwyg-editor.
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 in de ontwikkelgereedschappen mogelijkheden voor het simuleren van weergave op een kleiner scherm ingebouwd. Ook dit blijft een simulatie, maar geeft vaak wel een beter beeld dan zoomen.
-
Als je 'n site maakt in Firefox, Opera, Safari, Google Chrome 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.
- 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.
e kunt de blokken tijdens het aanpassen opvullen met bijvoorbeeld <br>1<br>2<br>3 enzovoort, tot ze de juiste hoogte hebben. Het is handig om aan het einde even iets toe te voegen als 'laatste', zodat je zeker weet dat er niet ongemerkt drie regels onderaan naar 't virtuele walhalla zijn verhuisd.
Om de breedte te vullen, kun je het best 'n kort woord als 'huis' duizend keer of zo herhalen. Ook hier is het handig om aan 't eind (en hier ook aan 't begin) 'n herkenningsteken te maken, zodat je zeker weet dat je de hele tekst ziet.
- Zolang je in grotere dingen zoals 'n lay-out aan 't wijzigen bent, kan het helpen de verschillende delen een achtergrondkleur 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 eigenschappen verandert in de css, verander er dan maar één, hooguit twee tegelijk. Als je er zeventien tegelijk verandert, is de kans groot dat je niet meer weet, wat je hebt gedaan. En dat je 't dus niet meer terug kunt draaien.
-
margin
,padding
enborder
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 px aan beide kanten), en 4 px hoger. Zoiets kan je hele lay-out verstoren, omdat iets net te breed of te hoog wordt. Je moet dan elders iets 4 px kleiner maken. Dat zal vaak zo zijn: als je één maat verandert, zul je vaak ook 'n andere moeten aanpassen.Css geeft de mogelijkheid om met behulp van
box-sizing
de padding en border bínnen de breedte en hoogte van de inhoud te zetten, als je dat handiger vindt.Met nieuwere css-eigenschappen als grid en flexbox, die speciaal zijn gemaakt om een lay-out mee te maken, spelen dit soort problemen veel minder. In alle browsers waarop hier nog wordt getest, werken flexbox en grid prima. Maar als je oudere browsers moet ondersteunen, kan dat wel problemen opleveren en moet je ook in die oudere browsers testen.
-
In plaats van een absolute eenheid als
px
kun je ook een relatieve eenheid gebruiken, met nameem
enrem
. Voordeel vanem
enrem
is dat een lettergrootte, regelhoogte, en dergelijke inem
enrem
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
enrem
vrijwel altijd beter dan absolute eenheden alspx
.(De minder bekende
rem
is ongeveer hetzelfde als deem
. Alleen is de lettergrootte bijrem
gebaseerd op de lettergrootte van het <html>-element, waardoor derem
overal op de pagina precies even groot is. Bij deem
kan de lettergrootte worden beïnvloed door de voorouders van het element, bij derem
niet.)Zoomen kan trouwens altijd, ongeacht welke eenheid je gebruikt.
-
Valideren, valideren, valideren en dan voor 't slapen gaan nog 'ns valideren.
Valiwie???
Valideren is het controleren van je html en css op 'n hele serie fouten. Computers zijn daar vaak veel beter in dan mensen. Als je 300 keer <h2> hebt gebruikt en 299 keer </h2> vindt 'n computer die ene missende </h2> zonder enig probleem. Jij ook wel, maar daarna ben je misschien wel aan vakantie toe.
Valideren kan helpen om gekmakende fouten te vinden. Valide code garandeert ook dat de weergave in verschillende browsers (vrijwel) hetzelfde is. En valide code is over twintig jaar ook nog te bekijken.
Valideren moet trouwens ook niet worden overdreven. Het is een hulpmiddel om echte fouten te vinden, meer niet. Het gaat erom dat je site goed werkt, niet dat je het braafste kind van de klas bent. Als de code niet valideert, maar daar is een goede reden voor, is daar niets op tegen. Zeker met nieuwere html en css wil de validator nog wel eens achterlopen, terwijl dat al prima is te gebruiken.
Op deze site is alle css en html gevalideerd. Als de code niet helemaal valide is (wat regelmatig voorkomt), staat daar onder Bekende problemen (en oplossingen) de reden van.
Je kunt je css en html valideren als 't online staat, maar ook als het nog in je computer staat.
Html kun je valideren op: validator.w3.org/nu.
Css kun je valideren op: jigsaw.w3.org/css-validator.
Toegankelijkheid en zoekmachines
De tekst in dit hoofdstukje is een algemene tekst, die voor elke pagina geldt. Eventueel specifiek voor dit voorbeeld geldende problemen en eventuele aanpassingen om die problemen te voorkomen staan bij Bekende problemen (en oplossingen).
Toegankelijkheid (in het Engels 'accessibility') is belangrijk voor bijvoorbeeld blinden die een schermlezer gebruiken, of voor motorisch gehandicapte mensen die moeite hebben met het bedienen van een muis. Een spider van een zoekmachine (dat is het programmaatje dat de site indexeert voor de zoekmachine) is te vergelijken met een blinde. Als je je site goed toegankelijk maakt voor gehandicapten, is dat gelijk goed voor een hogere plaats in een zoekmachine. Dus als je 't niet uit sociale motieven wilt doen, kun je 't uit egoïstische motieven doen.
(Op die plaats in de zoekmachine heb je maar beperkt invloed. De toegankelijkheid van je site is maar één van de factoren, maar zeker niet onbelangrijk.)
Als je bij het maken van je site al rekening houdt met toegankelijkheid, is dat nauwelijks extra werk. 't Is ongeveer te vergelijken met inbraakbescherming: doe dat bij 'n nieuw huis en 't is nauwelijks extra werk, doe 't bij 'n bestaand huis en 't is al snel 'n enorme klus.
Enkele tips die helpen bij toegankelijkheid:
-
Gebruik altijd een alt-beschrijving bij een afbeelding. De alt-tekst wordt gebruikt, 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. - Als uit de tekst in een link niet duidelijk wordt, 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.
Hierdoor zijn accesskeys (vrijwel) niet te gebruiken. Misschien kunnen ze nog enig nut hebben op sites, die gericht zijn op 'n specifieke groep gebruikers. Maar voor algemene sites is het advies: normaal genomen niet gebruiken.
-
Met behulp van de Tab-toets (of op 'n soortgelijke manier) kun je 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. (Meer over de Tab-toets is te vinden bij Tabindex en Tab-toets.) - Als, zoals hierboven beschreven, een gebruiker van de Tab-toets bij een link, invoerveld, en dergelijke is aangekomen, heeft dit element 'focus'. Dit wordt aangegeven door de link, invoerveld, en dergelijke extra te markeren met een kadertje. Dat kadertje mag je alleen weghalen, als op een andere manier wordt duidelijk gemaakt, welk element focus heeft. Een gebruiker van de Tab-toets kan anders niet zien, waar zij of hij zit, en welk element gaat reageren op bijvoorbeeld een Enter. (Meer over focus is te vinden bij focus.)
- In het verleden werd vaak aangeraden de volgorde van de code aan te passen. Een menu bijvoorbeeld kon in de html onderaan worden gezet, terwijl het op het scherm met behulp van css bovenaan werd gezet. Inmiddels zijn schermlezers en dergelijke zo sterk verbeterd dat dit niet meer wordt aangeraden. De volgorde in de html kan tegenwoordig beter hetzelfde zijn als die op het scherm, omdat het anders juist verwarrend kan werken.
-
Een zogenaamde skip-link is vaak nog wel 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.
(Alleen in de schermlezer TalkBack op oudere versies van Android werkt zo'n buiten het scherm geplaatste link niet. TalkBack leest zo'n link wel voor, maar de link kan niet worden gevolgd, als deze buiten het scherm staat. Met ingang van versie 8.1 van Android is dit eindelijk opgelost en werkt een skip-link ook fatsoenlijk in TalkBack.)
Een skip-link staat bovenaan de pagina, nog boven menu, header, en dergelijke, en linkt naar de eigenlijke inhoud van de pagina. Hierdoor kunnen mensen met één toetsaanslag naar de eigenlijke inhoud van de pagina gaan.
Een skip-link is vooral nuttig voor gebruikers van de Tab-toets. Zodra de normaal genomen onzichtbare link door het indrukken van de Tab-toets focus krijgt, kun je 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. Dan wordt de pagina niet pas in de browser, maar al op de server samengesteld. Hierdoor zien zoekmachines, schermlezers, en dergelijke één pagina, net zoals wanneer je maar één pagina met html zou hebben geschreven.
(Je kunt ook invoegen met behulp van SSI. Maar tegenwoordig kun je beter PHP dan SSI gebruiken, omdat SSI min of meer aan het uitsterven is en PHP veel meer mogelijkheden heeft. 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.Op deze site wordt de lijst op woordenlijst.org gebruikt om te bepalen, of een woord inmiddels 'Nederlands' is. Als het woord in deze lijst voorkomt, wordt geen
lang
-attribuut gebruikt, ook niet als het woord oorspronkelijk uit een andere taal komt. - Gebruik de tag <abbr> bij afkortingen. Doe dat de eerste keer op een pagina samen met de title-eigenschap:
<abbr title="ten opzichte van">t.o.v.</abbr>
. Daarna kun je op dezelfde pagina volstaan met<abbr>t.o.v.</abbr>
. Doe je dit niet, dan is er 'n grote kans dat 'n schermlezer 't.o.v.' uit gaat spreken als 'tof', en 'n zoekmachine kan er ook geen chocola van maken. - Geef een verandering niet alleen door kleur aan. Een grote groep mensen heeft moeite met het onderscheiden van kleuren en/of het herkennen van kleuren. Verander bijvoorbeeld een ronde rode knop niet in een ronde groene knop, maar in een vierkante groene knop. Door ook de vorm te veranderen, is het herkennen van de verandering niet alleen van een kleur afhankelijk.
- Zorg voor voldoende contrast tussen achtergrond- en voorgrondkleur, tussen
background-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. Op de pagina met links staat onder het kopje Toegankelijkheid → Contrast en kleurenblindheid een hele serie sites, waar je kunt controleren of het contrast groot genoeg is. -
De spider van 'n zoekmachine, schermlezers, en dergelijke kunnen geen plaatjes 'lezen'. Het is soms verbazingwekkend om te zien hoe veel, of eigenlijk: hoe weinig tekst er overblijft op een pagina, als de plaatjes worden weggehaald.
Op Linux kun je met Lynx kijken, hoe je pagina eruitziet zonder plaatjes en dergelijke, als echt alleen de tekst overblijft. Een installatie-programma voor Lynx op Windows is te vinden op invisible-island.net/lynx.
Ook kun je in Windows het gratis programma WebbIE installeren. WebbIE laat de pagina zien, zoals een tekstbrowser en dergelijke hem ziet. WebbIE is te downloaden vanaf www.webbie.org.uk.
Ten slotte kun je je pagina nog online op toegankelijkheid laten controleren op 'n behoorlijk aantal sites, zoals:
lowvision.support: laat zien hoe een kleurenblinde de site ziet. Engelstalig.
wave.webaim.org: deze laat grafisch zien, hoe de toegankelijkheid is. Engelstalig. Deze tester is ook als extensie in Firefox en Google Chrome te installeren.
Op de pagina met links kun je onder Toegankelijkheid links naar meer tests en dergelijke vinden.
Getest in
Laatst gecontroleerd op 6 december 2021.
Onder dit kopje staat alleen maar, hoe en waarin is getest. Alle eventuele problemen, ook die met betrekking tot zoomen, lettergroottes, toegankelijkheid, uit staan van JavaScript en/of css, enzovoort staan iets hieronder bij Bekende problemen (en oplossingen). Het is belangrijk dat deel te lezen, want uit een test kan ook prima blijken dat iets totaal niet werkt!
Dit voorbeeld is getest op de volgende systemen:
Desktopcomputers
Windows 7 (1280 x 1024 px, resolution 96 ppi):
Firefox, Google Chrome en Edge, in grotere en kleinere browservensters.
OS X 10.14.6 ('Mojave') (1680 x 1050 px, resolution: 96 ppi, device-pixel-ratio: 1):
Firefox, Safari, Google Chrome en Microsoft Edge, in grotere en kleinere browservensters.
Linux (Kubuntu 20.04 LTS, 'Focal Fossa') (2560 x 1080 px, resolution: 96 ppi):
Firefox en Google Chrome, in grotere en kleinere browservensters.
Laptops
Windows 8.1 (1366 x 768 px, resolution: 135 ppi):
Bureaublad-versie: Firefox, Google Chrome en Edge, in grotere en kleinere browservensters.
Windows 10 (1600 x 900 px, resolution: 106 ppi):
Firefox, Google Chrome en Edge, in grotere en kleinere browservensters.
Tablets
iPad met iOS 12.5.5 (2048 x 1536 px, device-pixel-ratio: 2:
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).
iPad met iOS 13.3 (gesimuleerd in Xcode):
Safari (portret en landschap).
iPad met iPadOS 15.1 (2160 x 1620 px, 264 ppi):
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).
Android 6.0 ('Marshmallow') (1920 x 1200 px, resolution: 224 ppi):
Samsung Internet, Firefox en Chrome (alle portret en landschap).
Android 8.1 ('Oreo') (1920 x 1200 px, resolution: 218 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Android 11 (2000 x 1200 px, resolution: 225 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Smartphones
iPhone 7 met iOS 12.4 (gesimuleerd in Xcode):
Safari (portret en landschap).
iPhone 8 met iOS 13.3 (gesimuleerd in Xcode):
Safari (portret en landschap).
iPhone met iOS 15.1 (1334 x 750 px, 326 ppi):
Safari, Chrome, Firefox en Microsoft Edge (alle portret en landschap).
Android 7.0 ('Nougat') (1280 x 720 px, resolution: 294 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Android 9.0 ('Pie') (1920 x 1080 px, resolution: 424 ppi):
Samsung Internet, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Er is op de aan het begin van dit hoofdstukje genoemde controledatum getest in de meest recente versie van de browser, die op het betreffende besturingssysteem kon draaien. Het aantal geteste browsers en systemen is al tamelijk fors, en als ook nog rekening gehouden moet worden met (zwaar) verouderde browsers, is het gewoon niet meer te doen. Surfen met een verouderde browser is trouwens vragen om ellende, want updates van browsers hebben heel vaak met beveiligingsproblemen te maken.
In- en uitzoomen en - voor zover de browser dat kan - een kleinere en grotere letter zijn ook getest. Er is ingezoomd en vergroot tot zover de browser kan, maar niet verder dan 200%.
Er is getest met behulp van muis en toetsenbord, behalve op iOS, iPadOs en Android, waar een touchscreen is gebruikt. Op Windows 8.1 en 10 is getest met touchscreen, touchpad, toetsenbord, muis, en - waar dat zinvol was - op een combinatie daarvan.
Als in een voorbeeld JavaScript is gebruikt, is ook getest of het werkt zonder JavaScript. Dat is alleen gedaan in de browsers, waarin in de instellingen JavaScript kan worden uitgeschakeld.
Ook is getest zonder css en - als afbeeldingen worden gebruikt - zonder afbeeldingen.
Schermlezers en dergelijke
Naast deze 'gewone' browsers is ook getest in Lynx, WebbIE, NVDA, TalkBack, VoiceOver en Verteller.
Lynx is een browser die alleen tekst laat zien en geen css gebruikt. Er is getest op Linux.
WebbIE. is een browser die gericht is op mensen met een handicap. Er is getest op Windows7.
NVDA is een schermlezer, zoals die door blinden wordt gebruikt. Er is getest op Windows 7 en Windows 10 in combinatie met Firefox.
TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome op Android 6.0, 7.0, 8.1, 9 en 11
VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS 12.5.5 en 15.1, iPadOS 15.1 en OS X 10.14.6.
Verteller (Narrator) is een in Windows 10 ingebouwde schermlezer. Er is getest in combinatie met Edge.
(Voor de bovenstaande programma's zijn links naar sites met uitleg en dergelijke te vinden op de pagina met links onder Toegankelijkheid → Schermlezers, tekstbrowsers, en dergelijke.)
Als het voorbeeld in deze programma's toegankelijk is, zou het in principe toegankelijk moeten zijn in alle aangepaste browsers en dergelijke. En dus ook voor zoekmachines, want een zoekmachine is redelijk vergelijkbaar met een blinde.
Eventuele problemen in schermlezers (en eventuele aanpassingen om die te voorkomen) staan iets hieronder bij Bekende problemen (en oplossingen).
Alleen op de hierboven genoemde systemen en browsers is getest. Er is dus niet getest op bijvoorbeeld 'n Blackberry. Er is een kans dat dit voorbeeld niet (volledig) werkt op niet-geteste systemen en apparaten. Om het wel (volledig) werkend te krijgen, zul je soms (kleine) wijzigingen en/of (kleine) aanvullingen moeten aanbrengen, bijvoorbeeld met JavaScript.
Er is ook geen enkele garantie dat iets werkt in een andere tablet of smartphone dan hierboven genoemd, omdat fabrikanten in principe de software kunnen veranderen. Dit is anders dan op de desktop, waar browsers altijd (vrijwel) hetzelfde werken, zelfs op verschillende besturingssystemen. Iets wat in Samsung Internet op Android werkt, zal in de regel overal werken in die browser, maar een garantie is er niet. De enige garantie is het daadwerkelijk testen op een fysiek apparaat. En aangezien er duizenden mobiele apparaten zijn, is daar geen beginnen aan.
De html is gevalideerd met de html-validator, de css met de css-validator van w3c. Als om een of andere reden niet volledig gevalideerd kon worden, wordt dat bij Bekende problemen (en oplossingen) vermeld.
Nieuwe browsers worden pas getest, als ze uit het bèta-stadium zijn. Anders is er 'n redelijke kans dat je tegen 'n bug zit te vechten, die voor de uiteindelijke versie nog gerepareerd wordt. Dit voorbeeld is alleen getest in de hierboven met name genoemde browsers. Vragen over niet-geteste browsers kunnen niet worden beantwoord, en het melden van fouten in niet-geteste browsers heeft ook geen enkel nut. (Melden van fouten, problemen, enzovoort in wel geteste browsers: graag! Dat kan op het forum.)
Bekende problemen (en oplossingen)
Waarop en hoe is getest, kun je gelijk hierboven vinden bij Getest in.
Als je hieronder geen oplossing vindt voor een probleem dat met dit voorbeeld te maken heeft, kun je op het forum proberen een oplossing te vinden voor je probleem. Om forumspam te voorkomen, moet je je helaas wel registreren, voordat je op het forum een probleem kunt aankaarten.
Bij toegankelijkheid is er vaak geen goed onderscheid te maken tussen oplossing en probleem. Zonder (heel simpele) aanpassingen heb je vaak 'n probleem, en omgekeerd. Daarom staan wat betreft toegankelijkheid aanpassingen en problemen hier bij elkaar in dit hoofdstukje.
Voor zover van toepassing wordt eerst het ontbreken van JavaScript, css en/of afbeeldingen besproken. Vervolgens problemen en aanpassingen met betrekking tot toegankelijkheid voor specifieke groepen bezoekers, zoals zoomen en andere lettergrootte, Tab-toets, tekstbrowsers en schermlezers. Als laatste volgen de overige problemen in één of meer specifieke browsers.
Als in een onderdeel geen problemen aanwezig zijn, staat in een smal groen kadertje 'Geen problemen'. Bij een onderwerp over toegankelijkheid zijn er soms geen problemen, maar alleen aanpassingen. Ook in dat geval staat bovenaan in een smal groen kadertje 'Geen problemen'. Daaronder staan dan de aanpassingen.
Als in een onderdeel één of meer problemen worden besproken, staat van elk probleem in een breed rood kadertje een korte samenvatting daarvan.
Als bij het probleem een oplossing wordt gegeven, staat de samenvatting in een rode stippellijn. Bij een onderwerp over toegankelijkheid zijn er soms, naast de opgeloste problemen, ook aanpassingen. In dat geval staan staan die aanpassingen boven de kadertjes met opgeloste problemen.
Als bij het probleem geen oplossing is gevonden, staat de samenvatting in een rode ononderbroken lijn. Bij een onderwerp over toegankelijkheid zijn er soms, naast de problemen, ook aanpassingen. In dat geval staan staan die aanpassingen boven de kadertjes met problemen.
Zonder JavaScript
Probleem: zonder JavaScript lezen schermlezers altijd de alt-teksten van beide afbeeldingen voor.
Met behulp van JavaScript wordt de niet getoonde afbeelding met de daarbij horende alt-tekst voor schermlezers verborgen, door het toevoegen van aria-hidden="false"
, zoals beschreven bij aria-hidden.
Zonder JavaScript werkt dit niet en kan de niet-getoonde afbeelding niet worden verborgen. En de alt-tekst bij die afbeelding dus ook niet. Hierdoor worden beide alt-teksten voorgelezen, ongeacht welke afbeelding wordt getoond.
Niet het einde van de wereld, maar wel enigszins verwarrend.
Zonder css
Geen problemen.
Beide afbeeldingen en de gewone tekst worden volledig getoond. De tekst in de <label> is 'Toon vervangingToon origineel', want zonder css kan die tekst niet worden aangepast.</label>
Zonder afbeeldingen
Geen problemen.
Uiteraard worden de afbeeldingen niet getoond. In plaats daarvan verschijnt de alt-tekst.
Omdat de vervangende afbeelding absoluut is gepositioneerd, komt deze over de originele afbeelding heen te staan. Hetzelfde geldt voor de alt-tekst. Dat is op de bovenste afbeelding te zien: beide alt-teksten staan door elkaar heen en zijn niet te lezen.
Door de vervangende afbeelding een witte achtergrond te geven, krijgt ook de alt-tekst die witte achtergrond en is de alt-tekst wel goed te lezen, zoals op de onderste afbeelding is te zien. Ongeveer zoals je vuil onder het vloerkleed veegt: het is er nog wel, maar je ziet het niet meer.
Zonder css én zonder afbeeldingen
Geen problemen.
Alle tekst wordt getoond, beide alt-teksten en als de tekst in de <label> is 'Toon vervangingToon origineel'. Kortom: er verdwijnt niets (behalve uiteraard de afbeeldingen), maar het is wel een zootje.
Gebruikers Tab-toets
Geen problemen.
Een aankruisvakje <input="checkbox"> kan gewoon met de Tab-toets worden bezocht. Omdat niet duidelijk is dat het om een aankruisvakje gaat, wordt bij gebruik van de Tab-toets eerst een kleine uitleg getoond, zoals beschreven bij tabindex="0".
Tekstbrowsers
Probleem: WebbIE toont de vervangende afbeelding niet.
Lynx levert geen problemen op: alle tekst en beide alt-teksten worden getoond, en als <label> 'Toon vervangingToon origineel'. Dit kun je natuurlijk problemen noemen, maar mensen die Lynx gebruiken kiezen nou eenmaal voor snelheid boven mooi en zullen dit soort dingen gewend zijn.
WebbIE toont ook alle tekst en als <label> ook weer 'Toon vervangingToon origineel'. De originele afbeelding wordt getoond.
Het aankruisvakje werkt gewoon, maar de vervangende afbeelding wordt toch niet getoond, hoewel dit wel zou moeten gebeuren. Hier is weinig aan te doen, want het is een probleem binnen WebbIE.
Schermlezers
Probleem: omdat beide afbeeldingen altijd aanwezig zijn, lezen schermlezers altijd beide alt-teksten voor.
Omdat beide afbeeldingen altijd aanwezig zijn, ook al zie je er maar één, zijn ook beide alt-teksten altijd aanwezig. Daardoor zullen schermlezers altijd beide alt-teksten voorlezen, ongeacht welke afbeelding wordt getoond.
Voor schermlezers wordt daarom de niet-getoonde afbeelding met de bijbehorende alt-tekst verborgen met behulp van aria-hidden en wat JavaScript, zodat niet beide alt-teksten worden voorgelezen.
Als JavaScript uitstaat kan dit uiteraard niet en worden wel beide alt-teksten voorgelezen, ongeacht welke afbeelding wordt getoond.
(De reden dat display: none;
en dergelijke niet gebruikt kan worden, om één van beide afbeeldingen te verbergen, staat bij opacity: 0;.)
Zoomen en andere lettergrootte
Geen problemen.
Overige problemen
Probleem: de originele afbeelding is niet te kopiëren en dergelijke.
Als je de originele afbeelding probeert te kopiëren, op te slaan, te openen in een nieuwe tab, enzovoort, dan krijg je als resultaat de vervangende afbeelding. Logisch, want die staat over de originele afbeelding heen, ook al is die doorzichtig.
Door het uitzetten van css is de originele afbeelding wel te downloaden. Om die reden is dit ongeschikt als bescherming tegen kopiëren: veel te simpel te omzeilen.
Probleem: @supports not selector(:focus-visible)
valideert niet.
Tot voor kort kon @supports
alleen kijken of een eigenschap werd ondersteund, niet of een selector werd ondersteund. Officieel zit dit nog in een experimentele fase, maar het werkt in alle nieuwere browsers al prima. De css-validator van w3c rekent het echter nog fout.
Omdat het gewoon werkt, kan deze foutmelding worden genegeerd.
Wijzigingen
Alleen grotere wijzigingen worden hier vermeld, geen dingen als een link die is geüpdatet.
:
Nieuw opgenomen.
26 maart 2009:
-
Tekst aangepast aan de nieuw verschenen Internet Explorer 8.
-
meta-tag toegevoegd zodat het wordt weergegeven zoals in Internet Explorer 7 het geval was.
12 april 2009:
Hierboven vermelde meta-tag weer weggehaald. Ook Internet Explorer 8 gebruikt nog steeds niet de standaard voor doorzichtigheid, maar 'n door Microsoft zelf bedachte methode. Nu werkt dit voorbeeld ook in de standaardmodus van Internet Explorer 8.
Overigens opmerkelijk dat Microsoft dit de 'super standards mode' noemt, terwijl zoiets simpels als opacity
nog niet eens volgens de standaard werkt. En dan heb ik het maar helemaal niet over svg, css en html5, waarin deze 'super standards'-browser jaren en jaren achterloopt op álle concurrenten.
30 december 2009:
Afbeeldingen van lp's vervangen door eigengemaakte foto's van Koninginnedag 2009 in het Vondelpark in Amsterdam. Dit in verband met copyright. Ook op deze afbeeldingen bleek dat te zitten. Tja.
12 december 2011:
Tekst aangepast aan de inmiddels verschenen Internet Explorer 9. De code is niet gewijzigd.
7 december 2021:
- Alles voor Internet Explorer verwijderd.
- xhtml omgezet naar html.
- Slepen met de muis om de afbeelding te vervangen veranderd in een knop.
- Werkt nu ook op touchscreens.
- Aantal nieuwe hoofdstukken, vooral over toegankelijkheid.
- Tig kleinere wijzigingen in de tekst.
Inhoud van de download en licenties
De inhoud van deze download kan vrij worden gebruikt, met drie beperkingen:
* Sommige onderdelen die van 'n andere site of zo afkomstig zijn, vallen mogelijk onder een of andere licentie. Dat is hieronder bij het betreffende onderdeel te vinden.
* Je gebruikt het materiaal uit deze download volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte code en dergelijke zitten. Voor eventuele schade die door gebruik van materiaal uit deze download ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.
* Dit voorbeeld (en de bijbehorende uitleg en dergelijke) wordt min of meer regelmatig bijgewerkt. Het is daarom niet toegestaan dit voorbeeld (en de bijbehorende uitleg en dergelijke) op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat voorbeeld, uitleg, en dergelijke afkomstig zijn van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.
Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.
afbeelding-053-dl.html: de pagina met het voorbeeld.
afbeelding-053.pdf: deze uitleg (aangepast aan de inhoud van de download).
afbeelding-053-inhoud-download-en-licenties.txt: een kopie van de tekst onder dit kopje (Inhoud van de download en licenties).
053-css-dl:
afbeelding-053-dl.css: stylesheet voor afbeelding-053-dl.html.
053-pics:
origineel.jpg: de originele afbeelding.
vervang.jpg: de vervangende afbeelding.
De foto's zijn gemaakt in het Vondelpark in Amsterdam op Koninginnedag 2009. Als je jezelf herkent en de originele foto wilt hebben, stuur dan even 'n mailtje naar info@css-voorbeelden.nl.
HTML
De code is geschreven in een afwijkende
lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)
In de html hieronder wordt alleen de html besproken, waarover iets meer is te vertellen. Een <h1> bijvoorbeeld wordt in de regel niet genoemd, omdat daarover weinig interessants valt te melden. (Als bijvoorbeeld het uiterlijk van de <h1> wordt aangepast met behulp van css, staat dat verderop bij de bespreking van de css.)
Zaken als een doctype
en charset
hebben soms wat voor veel mensen onbekende effecten, dus daarover wordt hieronder wel een en ander geschreven.
<!doctype html>
Een document moet met een doctype beginnen om weergaveverschillen tussen browsers te voorkomen. Zonder doctype is de kans op verschillende (en soms volkomen verkeerde) weergave tussen verschillende browsers heel erg groot.
Geldige doctypes vind je op www.w3.org/QA/2002/04/valid-dtd-list.
Gebruik het volledige doctype, inclusief de eventuele url, anders werkt het niet goed.
Het hier gebruikte doctype is dat van html5. Dit kan zonder enig probleem worden gebruikt: het werkt zelfs in Internet Explorer 6.
<html lang="nl">
De toevoeging lang="nl"
bij <html> geeft aan dat de pagina in het Nederlands is. De taal is van belang voor schermlezers, automatisch afbreken, automatisch genereren van aanhalingstekens, juist gebruik van decimale punt of komma, en dergelijke.
<meta charset="utf-8">
Zorgt dat de browser letters met accenten en dergelijke goed kan weergeven.
utf-8 is de beste charset (tekenset), omdat deze alle talen van de wereld (en nog heel veel andere extra tekens) bestrijkt, maar toch niet meer ruimte inneemt voor de code, dan nodig is. Als je utf-8 gebruikt, hoef je veel minder entiteiten (ä
en dergelijke) te gebruiken, maar kun je bijvoorbeeld gewoon ä gebruiken.
Deze regel moet zo hoog mogelijk komen te staan, als eerste regel binnen de <head>, omdat hij anders door sommige browsers niet wordt gelezen.
In html5 hoeft deze regel niet langer te zijn, dan wat hier staat.
<meta name="viewport" content="width=device-width, initial-scale=1">
Mobiele apparaten variëren enorm in grootte. En dat is een probleem. Sites waren, in ieder geval tot enkele jaren geleden, gemaakt voor desktopbrowsers. En die hebben, in vergelijking met bijvoorbeeld een smartphone, heel brede browservensters. Hoe moet je op 'n smartphone een pagina weergeven, die is gemaakt voor de breedte van een desktop? Je kunt natuurlijk wachten tot álle sites zijn omgebouwd voor smartphones, tablets, enzovoort, maar dan moet je waarschijnlijk heel erg lang wachten.
Mobiele browsers gokken erop dat een pagina een bepaalde breedte heeft. Safari voor mobiel bijvoorbeeld gaat ervan uit dat een pagina 980 px breed is. De pagina wordt vervolgens zoveel versmald dat hij binnen het venster van het apparaat past. Op een iPhone wordt de pagina dus veel smaller dan op een iPad. Vervolgens kan de gebruiker inzoomen op het deel van de pagina dat hij of zij wil zien.
Dit betekent ook dat bij het openen van de pagina de tekst meestal heel erg klein wordt weergegeven. (Meestal, want niet alle browsers en apparaten doen het op dezelfde manier.) Niet erg fraai, maar bedenk maar 'ns 'n betere oplossing voor bestaande sites.
Nieuwe sites of pagina's kunnen echter wel rekening houden met de veel kleinere vensters van mobiele apparaten. In dit voorbeeld bijvoorbeeld wordt de afbeelding nooit breder dan het venster.
Maar die stomme mobiele browser weet dat niet, dus die gaat ervan uit dat ook deze pagina 980 px breed is, en verkleint die dan. Dat is ongeveer even behulpzaam als de gedienstige kelner die behulpzaam de stoel naar achteren trekt, net als jij wilt gaan zitten.
Om de door de browser aangeboden hulp vriendelijk maar beslist te weigeren, wordt deze tag gebruikt. Hiermee geef je aan dat de pagina is geoptimaliseerd voor mobiele apparaten.
Een iPad in portretstand bijvoorbeeld is 768 px breed. De kreet width=device-width
zegt tegen de mobiele browser dat de breedte van de weer te geven pagina gelijk is aan de breedte van het apparaat. Voor een iPad in portretstand dus 768 px.
Er staat nog een tweede deel in de tag: initial-scale=1
. Sommige mobiele apparaten zoomen een pagina gelijk in of uit. Ook weer in een poging behulpzaam te zijn. Ook dat is hier niet nodig. Er is ook een instructie om zoomen helemaal onmogelijk te maken, maar die wordt niet gebruikt. De bezoeker kan zelf nog gewoon zoomen, wat belangrijk is voor mensen die wat slechter zien.
<link rel="stylesheet" href="053-css-dl/afbeelding-053-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.)
<p id="uitleg" tabindex="0">Gelijk op deze tekst volgt een aankruisvakje, vermomd als knop. Als je dit aanvinkt (met Spatiebalk of op soortgelijke wijze), wordt de daaronder staande afbeelding vervangen door een andere.</p>
De meeste mensen gebruiken een muis of een aanraking om te navigeren. Sommige mensen gebruiken echter de Tab-toets om links, knoppen, aankruisvakjes, en dergelijke langs te lopen. Ook allerlei andere dingen kunnen met het toetsenbord worden bediend.
Zo kan een aankruisvakje ook worden aan- en uitgevinkt met de Spatiebalk. Maar omdat het aankruisvakje hier is verborgen onder de bijbehorende <label>, is hier niet echt duidelijk, dat het hier om een aankruisvakje gaat. Daarom staat hier een korte uitleg.
Normaal genomen wordt een <p> genegeerd door de Tab-toets, maar door het toevoegen van tabindex="0" wordt deze toch herkend door de Tab-toets. De <p> staat normaal genomen onzichtbaar links buiten het browservenster. Pas als deze de focus krijgt, wordt de <p> met de uitleg binnen het venster gezet en daardoor zichtbaar.
Hoewel deze tekst buiten het browservenster staat, wordt deze toch gewoon voorgelezen door schermlezers. Ook deze weten daardoor, waarvoor de knop boven de afbeelding dient. (Hoewel een schermlezer een <input = "checkbox"> altijd al aankondigt als een aankruisvakje.)
<img id="origineel" aria-hidden="false" src="053-pics/levend-standbeeld.jpg" alt="Originele afbeelding: meisje van vijf jaar oud als levend standbeeld, kindervrijmarkt, koninginnedag 2009, Vondelpark, Amsterdam">
<img id="vervang" aria-hidden="true" src="053-pics/gitaristen.jpg" alt="Vervangende afbeelding: twee zingende gitaar spelende jongens, kindervrijmarkt, koninginnedag 2009, Vondelpark, Amsterdam">
De originele afbeelding en de vervangende afbeelding.
Schermlezers lezen bij een afbeelding de alt-tekst voor. Hier zouden beide alt-teksten worden voorgelezen, ongeacht welke afbeelding zichtbaar is. Beide afbeeldingen met bijbehorende alt-teksten zijn immers altijd aanwezig, ook al zie je er maar één.
Dat kan nogal verwarrend zijn.
Daarom wordt met behulp van aria-hidden steeds één van beide afbeeldingen met de bijbehorende alt-tekst voor schermlezers verborgen.
Bij openen van de pagina staat bij de originele afbeelding aria-hidden="false"
, waardoor deze wordt getoond. Bij de vervangende afbeelding staat juist aria-hidden="true"
, waardoor deze voor zschermlezers wordt verborgen.
Als input#toon
wordt aangevinkt en de vervangende afbeelding wordt getoond, worden de waarden achter aria-hidden
omgedraaid met behulp van wat JavaScript, waardoor dan juist de originele afbeelding met bijbehorende alt-tekst wordt verborgen voor schermlezers, en de vervangende wordt getoond.
Ook als input#toon
weer wordt uitgevinkt, worden de waarden bij aria-hidden
omgewisseld.
(De reden dat display: none;
en dergelijke niet gebruikt kan worden, om één van beide afbeeldingen te verbergen, staat bij opacity: 0;.)
<script></script>
Binnen deze tag staat het JavaScript.
Dit script gebruikt onderdelen van de pagina: de twee afbeeldingen en het aankruisvakje. Om deze te kunnen gebruiken, moeten ze eerst door de browser worden gemaakt. Daarom staat het script helemaal onderaan de html: je weet dan zeker, dat alle elementen al zijn aangemaakt.
Bovendien stopt de opbouw van de pagina, zodra de browser een script ontmoet, omdat het script eerst wordt uitgevoerd. Het zou immers kunnen dat het script (heel) belangrijk is voor de weergave. Dat is hier niet het geval. Door het script onderaan de pagina te zetten, voorkom je ook die in dit geval overbodige vertraging.
Als dit script op meerdere pagina's wordt gebruikt, kan het ook als een extern script worden gebruikt:
<script src="pad-naar-script/script.js"></script>
Ook in dat geval moet <script> helemaal onderaan de pagina worden gezet, gelijk boven </body>.
CSS
De code is geschreven in een afwijkende
lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code) is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)
Technisch gezien is er geen enkel bezwaar om de css in de stylesheet allemaal achter elkaar op één regel te zetten:
div#header-buiten {position: absolute; right: 16px; width: 100%; height: 120px; background: yellow;} div p {margin-left 16px; height: 120px; text-align: center;}
Maar als je dat doet, garandeer ik je hele grote problemen, omdat het volstrekt onoverzichtelijk is. Beter is het om de css netjes in te laten springen:
div#header-buiten {
position: absolute;
right: 16px;
width: 100%;
height: 120px;
background: yellow;
}
div p {
margin-left: 16px;
height: 120px;
text-align: center;
}
Hiernaast is het heel belangrijk voldoende commentaar (uitleg) in de stylesheet te schrijven. Op dit moment weet je waarschijnlijk (hopelijk...), waarom je iets doet. Maar over vijf jaar kan dat volstrekt onduidelijk zijn. Op deze site vind je nauwelijks commentaar in de stylesheets, maar dat heeft een simpele reden: deze uitleg is in feite één groot commentaar.
Op internet zelf is het goed, als de stylesheet juist zo klein mogelijk is. Dus voor het uploaden kun je normaal genomen het beste het commentaar weer verwijderen. Veel mensen halen zelfs alles wat overbodig is weg, voordat ze de stylesheet uploaden. Inspringingen bijvoorbeeld zijn voor mensen handig, een computer heeft ze niet nodig.
Je hebt dan eigenlijk twee stylesheets. De uitgebreide versie waarin je dingen uitprobeert, verandert, enzovoort, met commentaar, inspringingen, en dergelijke. Dat is de mensvriendelijke versie. Daarnaast is er dan een stylesheet die je op de echte site gebruikt: een gecomprimeerde versie.
Dat comprimeren kun je met de hand doen, maar er bestaan ook hulpmiddelen voor. Op de pagina met links kun je onder het kopje Gereedschap → Snelheid, testen, gzip, comprimeren (inclusief theorie) links naar sites vinden, waar je bestanden kunt comprimeren.
(Stylesheets op deze site zijn niet gecomprimeerd. Omdat het vaak juist om de css gaat, kunnen mensen dan zonder al te veel moeite de css bekijken.)
css voor alle browsers
/* afbeelding-053-dl.css */
Om vergissingen te voorkomen is het een goede gewoonte bovenaan het stijlbestand even de naam neer te zetten. Voor je het weet, zit je anders in het verkeerde bestand te werken.
body
Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.
background: #ff9;
Achtergrondkleurtje.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
font-family: Arial, Helvetica, sans-serif;
Als Arial is geïnstalleerd op de machine van de bezoeker, wordt deze gebruikt, anders Helvetica. Als die ook niet wordt gevonden, wordt in ieder geval een schreefloze letter (zonder dwarsstreepjes) gebruikt.
font-size: 110%;
Iets groter dan standaard. 't Zal de leeftijd zijn, maar ik vind de standaardgrootte wat te klein.
Als eenheid wordt de relatieve eenheid %
gebruikt, omdat bij gebruik van een absolute eenheid zoals px
niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
margin: 0;
Slim om te doen vanwege verschillen tussen browsers.
#wrapper
Het element met id="wrapper". Een <div> waar de hele handel in is gezet, zodat het makkelijker is te plaatsen en dergelijke.
text-align: center;
Tekst horizontaal centreren. Eigenlijk zou je hier moeten zeggen 'inline-elementen horizontaal centreren', want het geldt ook voor de <label>, <img>'s, en andere inline-elementen.
margin-top: 40px;
Kleine afstand tot de bovenkant van het browservenster.
#uitleg
Het element met id="uitleg". Een <p> met een korte uitleg voor gebruikers van de Tab-toets.
background: white;
Witte achtergrond.
color: black;
\Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.
width: 40vw;
Breedte.
De eenheid vw
is gebaseerd op de breedte van het venster van de browser. 1 vw is 1% van de breedte van het venster, en 40 vw is 40% van de breedte. De <p> met de uitleg wordt hierdoor nooit breder dan 40% van de breedte van het venster, ongeacht de breedte van het venster.
border: black solid 1px;
Zwart randje.
padding: 5px;
Kleine afstand tussen tekst in en buitenkant van de <p>.
position: absolute;
Om de <p> met de uitleg op de juiste plaats neer te kunnen zetten.
Er wordt gepositioneerd ten opzichte van het 'containing block'. Dat is de eerste voorouder die zelf een bepaalde eigenschap heeft, zoals een andere positie dan statisch. Als zo'n voorouder er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.
top: 0;
Bovenaan het browservenster neerzetten. Omdat een <p> standaard een marge aan boven- en onderkant heeft, komt deze toch iets van de bovenkant van het venster af te staan, wat mooier is.
left: -20000px;
Ver links buiten het browservenster parkeren. Pas als de <p> door gebruik van de Tab-toets de focus heeft gekregen, wordt deze bij #uitleg:focus binnen het venster gezet en daardoor zichtbaar.
z-index: 20;
Normaal genomen worden elementen in de volgorde van de html op het scherm gezet. Wat later in de html staat, wordt over eerdere elementen gezet. Om te zorgen dat de <p> met de uitleg altijd bovenaan staat, krijgt deze een hogere z-index.
Een z-index werkt alleen in bepaalde omstandigheden. Eén van die omstandigheden is een absolute positie. Die is iets hierboven aan de <p> gegeven, dus dat is geregeld.
#toon
Het element met id="toon". De <input> die bepaalt, welke afbeelding wordt getoond.
position: absolute;
Een <input> en een <label> zijn beide inline-elementen. Normaal genomen worden ze dan ook achter elkaar op dezelfde regel neergezet, zoals op de afbeelding is te zien. Gecentreerd, want dat is bij #wrapper met text-align: center;
opgegeven.
Door input#toon
absoluut te positioneren, wordt de <input> genegeerd door de andere elementen. Hierdoor komt de bijbehorende <label> niet naast, maar over de <input> te staan. Wat precies de bedoeling is, want een aankruisvakje is hier foeilelijk.
Voor de werking van de <input> maakt het niets uit, want de <label> is in de html met for="toon"
gekoppeld aan de <input>, waardoor het aankruisvakje ook wordt aan- of uitgevinkt door de <label> aan te raken.
#label-toon
Het element met id="label-toon". De bij input#toon
horende <label>
background: white;
Witte achtergrond.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.
display: inline-block;
Een <label> is van zichzelf een inline-element. Hierdoor zijn eigenschappen als breedte en hoogte niet te gebruiken. Een inline-block is een soort kruising tussen een inline- en een blok-element. Het komt niet op een nieuwe regel te staan, maar eigenschappen als hoogte en breedte zijn wel te gebruiken.
width: 8em;
Breedte.
Als eenheid wordt de relatieve eenheid em
gebruikt, zodat de breedte mee verandert met de lettergrootte. Bij gebruik van een absolute eenheid zoals px
verandert de breedte niet mee met de lettergrootte. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
border: black solid 1px;
Zwart randje.
border-radius: 5px;
Ronde hoeken. Omdat maar één maat is opgegeven, worden alle hoeken even rond.
padding: 10px;
Wat afstand tussen tekst in en buitenkant van de <label>.
position: relative;
Hier iets boven bij #toon is input#toon
met position: absolute;
absoluut gepositioneerd, zodat andere elementen de <input> negeren. Omdat #label-toon
op dezelfde regel staat als input#toon
, komt de <label> hierdoor over de <input> te staan. Precies de bedoeling, want de <input> is niet echt heel mooi en wordt dan verborgen onder de <label>.
Althans: dat is de bedoeling. Omdat #label-toon
in de html volgt op input#toon
, zou dat normaal genomen ook gebeuren, want latere elementen worden over eerdere heen gezet.
Alleen is input#toon
absoluut gepositioneerd, en #label-toon
heeft gewoon de standaard statische positie. En elementen die een andere positie dan statisch hebben, komen altijd boven elementen die niet zijn gepositioneerd te staan, ongeacht de volgorde in de html.
Door #label-toon
een relatieve positie te geven, zijn de <input> en de <label> beide gepositioneerd, en komt de <label> weer boven de <input> te staan, want nu geldt de volgorde in de html weer gewoon. Waarmee de niet weg te meppen <input> eindelijk is verborgen.
Omdat voor top
en dergelijke verder niets wordt opgegeven, heeft de relatieve positie verder geen enkele invloed op de <label>.
#label-toon span:last-child
Kinderen van dezelfde ouder kunnen worden geteld, net zoals dat bij kinderen uit een gezin het geval is: eerste kind, tweede kind, derde kind, enzovoort. Je kunt elementen selecteren op basis van het volgnummer binnen zo'n reeks kinderen. In dit geval wordt geen echt volgnummer gebruikt, maar :last-child
: alleen het laatste kind. Omdat dit zo vaak voorkomt, is hier een apart sleutelwoord voor: last-child
.
#label-toon
: het element met id="label-toon". De bij de <input> horende <label>.
span
: alle <span>'s binnen die <label>.
:last-child
: alleen de <span>'s die een laatste kind zijn. Binnen deze <span> zit de tekst 'Toon origineel'.
De hele selector in gewone mensentaal: alle <spans>'s binnen de label#label-toon
, die een laatste kind zijn.
Omdat er twee <spans>'s als ouder label#label-toon
hebben, zou je hier ook span:nth-child(2)
kunnen gebruiken. Maar :last-child
blijft altijd het laatste kind, ook als er eventueel <span>'s worden toegevoegd of weggehaald.
display: none;
Verbergen.
Pas als de <input> wordt aangevinkt en daardoor de vervangende afbeelding wordt getoond, wordt deze <span> bij #toon:checked + #label-toon span:last-child zichtbaar gemaakt.
#afbeeldingen
Het element met id="afbeeldingen". Een <div> waarin beide afbeeldingen zitten.
width: 400px;
Breedte. Dit is dezelfde breedte als de in de <div> zittende afbeeldingen hebben.
max-width: 90vw;
Hier gelijk boven is een breedte van 400 px opgegeven. Daardoor zou je in browservensters die smaller dan 400 px zijn horizontaal moeten scrollen om alles te zien. Daarom wordt hier een maximumbreedte opgegeven. Omdat voor de in deze <div> zittende afbeeldingen bij img een maximumbreedte van 100% wordt opgegeven, is dit ook gelijk de maximumbreedte van de afbeeldingen.
De eenheid vw
is gebaseerd op de breedte van het venster van de browser. 1 vw is 1% van de breedte van het venster, en 90 vw is 90% van de breedte. De <div> met de afbeeldingen wordt hierdoor nooit breder dan 90% van de breedte van het venster, ongeacht de breedte van het venster.
margin: 20px auto 0;
Omdat voor links geen waarde is opgegeven, krijgt links automatisch dezelfde waarde als rechts. Hier staat dus eigenlijk 20px auto 0 auto
in de volgorde boven - rechts - onder - links.
Aan de bovenkant 20 px afstand tot de erboven zittende witte knop, de <label>.
Aan de onderkant geen marge.
Links en rechts auto
, wat hier hetzelfde betekent als evenveel. Hierdoor komt de <div> altijd horizontaal gecentreerd binnen z'n ouder div#wrapper
te staan. div#wrapper
is een blok-element en wordt daardoor normaal genomen automatisch even breed als z'n ouder <main>. Ook <main> is een blok-element en wordt daardoor normaal genomen even breed als z'n ouder <body>. Het wordt eentonig: ook <body> is weer een blok-element dat dus normaal genomen even breed wordt als z'n ouder <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser.
Hierdoor staat uiteindelijk div#afbeeldingen
altijd horizontaal gecentreerd binnen het venster van de browser, ongeacht de breedte van het venster. En daarmee ook de in de <div> zittende afbeeldingen.
position: relative;
Om nakomelingen van de <div> te kunnen positioneren ten opzichte van de <div>, moet de<div> zelf een andere positie dan statisch hebben. Een relatieve positie heeft verder geen invloed op de <div> zelf, omdat niets voor top
en dergelijke wordt opgegeven.
img
Alle afbeeldingen. Dat zijn er hier maar twee: de originele en de vervangende.
max-width: 100%;
Een maximumbreedte in procenten is normaal genomen ten opzichte van de ouder van het element. Dat is hier div#afbeeldingen
, die bij #afbeeldingen met max‑width: 90vw;
een maximumbreedte van 90% van het venster van de browser heeft gekregen. Hierdoor worden ook de afbeeldingen nooit breder dan 90% van het venster.
Omdat nergens een hoogte is opgegeven voor de afbeeldingen, wordt de hoogte automatisch op dezelfde schaal aangepast als de breedte, zodat je geen lachspiegel-effect krijgt.
#vervang
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.
img {max-width: 100%; float: left;}
Het element met id="vervang". De vervangende afbeelding.
background: white;
Witte achtergrond.
Als de afbeeldingen om wat voor reden dan ook niet worden getoond, komt de alt-tekst van de vervangende afbeelding door de alt-tekst van de originele afbeelding te staan, waardoor deze niet is te lezen. Een witte achtergrond voorkomt dat. Dit wordt uitgebreider beschreven bij Zonder afbeeldingen.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst, of hier eigenlijk: de alt-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.
opacity: 0;
Volledig doorzichtig maken.
Gelijk hieronder wordt met position: absolute;
de vervangende afbeelding over de originele afbeelding heen gezet. Dit zorgt ervoor dat bij openen van de pagina toch de originele afbeelding wordt getoond.
Door de vervangende afbeelding op deze manier te verbergen, ontstaat een probleem voor schermlezers. Je ziet de vervangende afbeelding weliswaar niet, maar deze is wel gewoon aanwezig. En als de vervangende afbeelding bij #toon:checked ~ div #vervang zichtbaar wordt gemaakt en daardoor de originele afbeelding verbergt, is de originele afbeelding nog steeds gewoon aanwezig, ook al zie je die niet.
Beide afbeeldingen zijn dus altijd aanwezig, al zie je er maar één. Een schermlezer zal daardoor altijd beide alt-teksten voorlezen, ongeacht welke afbeelding zichtbaar is. Wat nogal verwarrend kan zijn. Dit wordt opgelost door met behulp van wat JavaScript en aria-hidden de niet-getoonde afbeelding met de bijbehorende alt-tekst te verbergen voor schermlezers.
Je zou dat verbergen voor schermlezers ook kunnen doen met display: none;
, maar display
is niet te combineren met de eigenschap transition
. De vervangende afbeelding wordt dan niet vertraagd zichtbaar, maar in één keer, ongeacht wat je bij transition
opgeeft.
visibility: none;
is ook niet te gebruiken om één van de afbeeldingen te verbergen voor een schermlezer, want dat kent maar twee waarden: none
en visible
. En die kun je niet langzaam veranderen. Ook bij gebruik van visibility
zou de vervangende afbeelding daardoor in één keer zichtbaar worden.
De vervangende afbeelding links buiten het browservenster parkeren of zoiets werkt ook niet, want schermlezers lezen gewoon voor, wat buiten het venster staat.
Omdat bij opacity
als waarde een getal wordt gebruikt, kan dit wel geleidelijk aan van 0 naar 1 worden veranderd, waardoor de vervangende afbeeldingen geleidelijk aan minder doorzichtig wordt.
position: absolute;
Om de afbeelding op de juiste plaats neer te kunnen zetten.
Er wordt gepositioneerd ten opzichte van het 'containing block'. Dat is de eerste voorouder die zelf een bepaalde eigenschap heeft, zoals een andere positie dan statisch. In dit geval is dat div#afbeeldingen
, die bij #afbeeldingen een relatieve positie heeft gekregen.
top: 0; left: 0;
De afbeelding in de linkerbovenhoek van div#afbeeldingen
zetten. Nu staat de vervangende afbeelding precies over de originele afbeelding heen.
#uitleg:focus
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.
#uitleg {background: white; color: black; width: 40vw; border: black solid 1px; padding: 5px; position: absolute; top: 0; left: -20000px; z-index: 20;}
Het element met id="uitleg", maar alleen als dit de focus heeft. In deze <p> staat een korte uitleg voor gebruikers van de Tab-toets. Normaal genomen kan een <p> geen focus krijgen, maar door het toevoegen van het attribuut tabindex="0" aan de <p> kan dat hier toch.
left: 10px;
Bij #uitleg is de <p> met left: -20000px;
links buiten het browservenster geparkeerd, waardoor deze - en de erin zittende tekst - verborgen worden. Nu wordt de <p> binnen het venster gezet, waardoor de tekst zichtbaar wordt.
Als de Tab-toets nogmaals wordt ingedrukt, verliest de <p> de focus weer en wordt de <p> weer links buiten het browservenster neergezet.
#toon:checked + #label-toon span:first-child
#toon:checked:
#toon
: het element met id="toon". Het aankruisvakje <input id="toon" type="checkbox">.
:checked
: maar alleen als dit is aangevinkt.
+
: het element achter de + moet in de html direct volgen op het element voor de +
. In dit geval gaat het om #label-toon
gelijk volgend op input#toon
.Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder div#wrapper
.
#label-toon
: het element met id="label-toon". De <label> die bij input#toon
hoort.
span:first-child
:
span
: alle <span>'s binnen die #label-toon
.
:first-child
: alleen de <span>'s die een eerste kind zijn. Binnen deze <span> zit de tekst 'Toon vervanging'.
De hele selector in gewone mensentaal: doe iets met de eerste <span> binnen #label-toon
, maar alleen als de gelijk voor die <label> zittende input#toon
is aangevinkt.
display: none;
De <span> en daarmee de erin zittende tekst 'Toon vervanging' verbergen.
Als het aankruisvakje is aangevinkt, wordt de vervangende afbeelding getoond. De tekst in de <label> moet dan veranderen van 'Toon vervanging' in 'Toon origineel'. Als onderdeel van deze verandering wordt dt tekst 'Toon vervanging' verborgen.
#toon:checked + #label-toon span:last-child
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
#label-toon span:last-child {display: none;}
Precies hetzelfde verhaal als bij de selector #toon:checked + #label-toon span:first-child gelijk hierboven, alleen geldt deze selector door het gebruik van span:last-child
in plaats van span:first-child
voor de laatste <span> in label#label-toon
, de <span> met 'Toon origineel'.
display: inline;
Toon de <span> met de erin zittende tekst 'Toon origineel'.
Eerder is bij #label-toon span:last-child deze <span> met display: none; verborgen. Als het aankruisvakje is aangevinkt, wordt de vervangende afbeelding getoond. Daarom moet nu de <span> met 'Toon origineel' worden getoond.
#toon:checked ~ div #vervang
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.
img {max-width: 100%; float: left;}
#vervang {background: white; color: black; opacity: 0; position: absolute; top: 0; left: 0;}
#toon:checked
:
#toon
: het element met id="toon". Het aankruisvakje <input id="toon" type="checkbox">.
:checked
: maar alleen als dit is aangevinkt.
~
: het hierachter staande element moet ergens in de html staan, na het hiervoor staande element. Het hoeft er, anders dan bij de +
, niet gelijk op te volgen, als het maar ergens na het eerste element in de html staat.
De enige voorwaarde is verder dat het voor en het na de ~
staande element dezelfde ouder hebben. Dat is hier het geval: input#toon
voor de ~
en de <div> na de ~
(dat is div#afbeeldingen
, de <div> met de afbeeldingen) hebben beide als ouder div#wrapper
.
#vervang
: de vervangende afbeelding img#vervang
.
De hele selector in gewone mensentaal: doe iets met de vervangende afbeelding die in een <div> zit, die ergens in de html op input#toon
volgt, maar alleen als de <input> is aangevinkt.
opacity: 1;
Maak de afbeelding zichtbaar.
De vervangende afbeelding is gewoon altijd aanwezig, maar is eerder bij #vervang met opacity: 0;
onzichtbaar gemaakt. Daardoor zie je de eronder zittende originele afbeelding. Door de vervangende afbeelding zichtbaar te maken, wordt de eronder zittende originele afbeelding onzichtbaar.
transition: 2s linear;
Eerder is img#vervang
bij #vervang met opacity: 0;
onzichtbaar gemaakt.
Hier gelijk boven is met opacity: 1;
de vervangende afbeelding img#vervang
zichtbaar gemaakt, als input#toon
is aangevinkt. Als je bij :hover
, :focus
, :checked
, en dergelijke een andere waarde bij een eigenschap opgeeft, kun je er met transition
bij veel eigenschappen voor zorgen dat de oude waarde niet in één keer in de nieuwe waarde wordt veranderd, maar geleidelijk, gedurende een op te geven tijdsduur.
Hier verandert opacity: 0;
(volledig doorzichtig) niet in één keer in opacity: 1;
(volledig ondoorzichtig), als input#toon
wordt aangevinkt, maar geleidelijk. Als opacity
van 0 (onzichtbaar) wordt veranderd naar 1 (zichtbaar), vindt die verandering geleidelijk aan plaats: geleidelijk van 0 naar 1.
Bij transition
staat maar één tijd: 2s
. Als er maar één tijd wordt opgegeven, bepaalt die over hoeveel tijd de verandering wordt uitgesmeerd. Dat is hier twee seconden. Een eventuele tweede tijd, die hier ontbreekt, geeft een eventueel uitstel aan het begin van de verandering aan.
linear
is een sleutelwoord, dat het verloop van de verandering aangeeft. Als je hier niets opgeeft, wordt de standaardwaarde ease
gebruikt: langzamer aan begin en einde van de verandering, sneller in het midden. linear
zorgt ervoor dat de verandering overal even snel plaatsvindt.
transition
brengt een geheel eigen risico met zich mee. In de specificatie staat, welke eigenschappen met behulp van transition
kunnen veranderen. Je kunt eventueel bij transition
opgeven, voor welke eigenschappen het geldt. Als je bijvoorbeeld top
en left
beide wilt veranderen bij :checked
, kun je bijvoorbeeld aangeven dat de geleidelijke verandering met behulp van transition
alleen voor top
geldt. left
verandert dan gewoon in één keer.
Als je niet opgeeft, voor welke eigenschappen transition
geldt, geldt het voor álle eigenschappen die bij :hover
, :focus
, :checked
, en dergelijke worden veranderd. Als daar 'n eigenschap bij zit die op dit moment niet door transition
kan worden vertraagd, verandert die gewoon in één keer. Maar als de specificatie of een van de browsermakers de geest krijgt en plotsklaps die eigenschap ook onder transition
laat vallen, kan dat tot heel onverwachte resultaten leiden.
Stel dat je een bepaalde eigenschap heel traag wilt veranderen bij :hover
en een andere eigenschap flitsend snel. Mogelijk wordt dat flitsend snel dan opeens ook heel traag, als transition
in de toekomst die eigenschap ook gaat ondersteunen. Daarom moet je absoluut zeker weten dat ook in de toekomst geen problemen kunnen ontstaan. Bij twijfel: geef aan welke eigenschap(pen) transition
mag aansturen.
Als alle eigenschappen mogen worden vertraagd door transition
, is er geen enkel risico voor de toekomst. Dat is hier het geval: alleen opacity
wordt veranderd. Verder verandert er niets. In dit geval mag dus alles vertraagd worden veranderd en is er geen risico voor de toekomst. Als dat niet zo zou zijn, moet je opgeven, voor welke eigenschappen transition
geldt.
Je kunt transition
beperken tot bepaalde eigenschappen door die eigenschappen te noemen, gevolgd door tijdsduur en eventueel vertraging:
transition: width 0.5s;
Nu geldt transition
alleen voor width
, ongeacht wat er in de toekomst mogelijk nog zou kunnen veranderen. Maar hier is dat dus niet nodig, omdat alleen opacity
wordt veranderd.
Als de originele afbeelding verandert in de vervangende afbeelding, gaat dat geleidelijk aan: het duurt 2 seconden. Maar als de vervangende afbeelding weer terug wordt veranderd naar de originele afbeelding, gaat dat zonder vertraging in één keer.
De waarden hier bij transition
gelden alleen, als input#toon
wordt aangevinkt, alleen bij #toon:checked
, als de originele afbeelding verandert in de vervangende afbeelding.
Voor het weer terug veranderen van de vervangende afbeelding naar de originele afbeelding kun je ook een vertraging opgeven, maar dat moet je dan bij #vervang doen. Als je daar transition: 20s ease-in;
op zou geven, duurt het terug veranderen van de vervangende afbeelding naar de originele 20 seconden, en het verloop is daar ease-in
: langzaam aan het begin, maar daarna overal hetzelfde tempo.
Hier is bij #vervang
geen waarde opgegeven. Daarom wordt bij het terug veranderen de standaardwaarde van transition
gebruikt: 0 seconden. Direct. Als je bij een eigenschap geen waarde opgeeft en de waarde wordt ook niet geërfd van 'n voorouder, wordt meestal de standaardwaarde gebruikt, wat bij transition
dus 0 seconde is.
Maar bij transition
is hier een uitzondering op: als je alleen bij #vervang
een waarde voor transition
opgeeft, wordt die waarde ook bij #vervang:hover
, #vervang:focus
, #vervang:checked
, en dergelijke gebruikt. Als je precies dezelfde regel transition: 2s linear;
niet hier bij #toon:checked ~ div #vervang
zou neerzetten, maar bij #vervang
, zou de verandering in beide richtingen 2 seconde duren en lineair zijn.
#toon:focus + label
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
#label-toon {background: white; color: black; display: inline-block; width: 8em; border: black solid 1px; border-radius: 5px; padding: 10px; position: relative;}
#toon:focus
: het element met id="toon", maar alleen als dit de focus heeft.
input#toon
krijgt de focus, als de <input> wordt aangeraakt of -geklikt, of als er met de Tab-toets naartoe wordt gegaan.
+
: het element achter de +
moet in de html direct volgen op het element voor de +
. In dit geval gaat het om #label-toon
gelijk volgend op input#toon
. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder div#wrapper
.
label
: de in de html gelijk op input#toon
volgende label#label-toon
.
De hele selector in gewone mensentaal: doe iets met de <label> die op input#toon
volgt, maar alleen als die <input> de focus heeft.
outline: blue solid 5px;
Blauwe outline van 5 px breed.
Sommige mensen gebruiken, om wat voor reden dan ook, de Tab-toets om links, tekstvelden, knoppen, en dergelijke langs te gaan. De browser geeft dan standaard met een kadertje aan, waar ze zijn, welk element de focus heeft. Daarmee weet de bezoeker, welke link bijvoorbeeld wordt gevolgd als op Enter wordt gedrukt.
Bij een <input type="checkbox">, zoals input#toon
hier is, wordt dat kadertje om het aankruisvakje gezet. Op de linkerafbeelding is het kadertje van Chrome te zien rond het aankruisvakje linksboven. Maar dat aankruisvakje is op de afbeelding alleen te zien, omdat de erboven zittende <label> even wat doorzichtig is gemaakt. In werkelijkheid is het vanwege aangeboren lelijkheid onzichtbaar gemaakt: je ziet alleen de erboven zittende witte <label>. En daarmee is ook het kadertje rondom het aankruisvakje onzichtbaar.
Daarom wordt hier aan de bij de <input> horende <label> een blauwe outline gegeven, zoals op de rechterafbeelding is te zien.
Dat kadertje is eigenlijk alleen nodig voor gebruikers van de Tab-toets, want als je de <label> aanklikt of aanraakt, weet je wat je hebt aangeklikt of aangeraakt. Als je door een ietwat uitbundige levensstijl niet meer weet wat je aanraakt, valt te vrezen dat een kadertje ook niet veel meer zal helpen.
Als je het eigenlijke aankruisvakje vanwege ongeneeslijke lelijkheid verstopt, moet je dat eigenlijk niet vervangen door een ongeveer even lelijke outline bij de <label>. Bij gebruik van de Tab-toets is die outline zinvol, maar bij een aanraking of een klik niet. Daarom wordt gelijk hieronder in browsers die dat ondersteunen, de outline bij gebruik van de Tab-toets wel getoond, maar niet bij een aanraking of klik.
css voor browsers die :focus-visible ondersteunen
@supports selector(:focus-visible)
De css die hier tot nu toe staat, geldt voor alle browsers.
De css die binnen deze 'feature query' staat, geldt alleen voor browsers die :focus-visible
ondersteunen. (Er bestaat geen goede Nederlandse vertaling voor 'feature query'. Het is een vraag of een bepaalde eigenschap en waarde, of een bepaalde selector, worden ondersteund: iets als 'eigenschap vraag'.)
@supports
: hierachter komt tussen haakjes de te onderzoeken selector (of de te onderzoeken eigenschap met een bepaalde waarde) te staan.
selector()
: als je, zoals hier gebeurt, niet op een eigenschap met waarde, maar op een selector wilt testen, gebruik je het sleutelwoord selector()
. Tussen de haakjes komt dan de selector te staan, waarvan je de ondersteuning wilt testen.
(:focus-visible)
: de selector, waarop je wilt testen. Omdat :focus-visible
altijd zonder verdere toevoeging wordt gebruikt, is dit voldoende. Maar zou je bijvoorbeeld op ondersteuning van :is()
willen testen, dan zou hier iets als (:is(a, b))
moeten staan.
Gelijk na deze regel komt een {
te staan, en aan het einde van de css die binnen deze query valt een bijbehorende afsluitende }
. Die zijn in de regel hierboven weggevallen, maar het geheel ziet er zo uit:
@supports selector(:focus-visible) {
body {color: silver;}
(...) rest van de css voor deze @media-regel (...)
footer {color: gold;}
}
Voor de eerste css binnen deze @supports-regel
staat dus een extra {
, en aan het eind staat een extra }
.
Je kunt ook als voorwaarde opgeven dat meerdere eigenschappen en/of waarden en/of selectors moeten worden ondersteund, of dat een eigenschap of selector juist niet mag worden ondersteund, maar dat gebeurt hier allemaal niet. Hier is de enige voorwaarde dat :focus-visible
wordt ondersteund.
Alleen browsers die :focus-visible
ondersteunen, voeren de css binnen deze feature query uit. Oudere browsers kennen :focus-visible
niet en voeren de css binnen deze feature query daarom niet uit. Als een browser zo oud is dat het hele @supports
niet wordt ondersteund, negeert ook die browser alle css binnen de feature query.
Het met @supports
testen op eigenschappen wordt al langer ondersteund, maar het op selectors testen met behulp van selector()
is relatief nieuw. Niet alle browsers die @supports
ondersteunen, ondersteunen ook al selector()
. Ook als dat het geval is, werkt het weer hetzelfde: de css binnen de feature query wordt genegeerd. (Standaard negeren browsers css die ze niet kennen.)
Omdat selector()
zo nieuw is, valideert dit ook nog niet in de css-validator van w3c. Maar omdat nieuwere browsers het allemaal wel al ondersteunen, is dat geen enkel probleem en kan de foutmelding van de validator gewoon worden genegeerd.
#toon:focus + label
Deze selector werkt alleen in browsers die :focus-visible
ondersteunen. Voor andere browsers is de uitleg hieronder niet van belang.
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
#label-toon {background: white; color: black; display: inline-block; width: 8em; border: black solid 1px; border-radius: 5px; padding: 10px; position: relative;}
#toon:focus + label {outline: blue solid 5px;}
#toon:focus
: het element met id="toon", maar alleen als dit de focus heeft.
input#toon
krijgt de focus, als de <input> wordt aangeraakt of -geklikt, of als er met de Tab-toets naartoe wordt gegaan.
+
: het element achter de +
moet in de html direct volgen op het element voor de +
. In dit geval gaat het om #label-toon
gelijk volgend op input#toon
. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder div#wrapper
.
label
: de in de html gelijk op input#toon
volgende label#label-toon
.
De hele selector in gewone mensentaal: doe iets met de <label> die op input#toon
volgt, maar alleen als die <input> de focus heeft.
outline: none;
Eerder is bij #toon:focus + label opgegeven dat de <label> een blauwe outline moet krijgen, als input#toon
de focus heeft. Dat is echter foeilelijk en eigenlijk alleen nodig voor gebruikers van de Tab-toets, niet bij gebruik van een muis of bij een aanraking. Daarom wordt die blauwe outline bij :focus
hier weer verwijderd.
Omdat dit alleen gebeurt bij browsers die :focus-visible
ondersteunen, houden andere browsers die outline gewoon. Browsers die :focus-visible
ondersteunen krijgen gelijk hieronder dezelfde outline weer terug, maar dan alleen voor gebruikers van de Tab-toets.
Op deze manier houdt elke browser, ouder of nieuwer, in ieder geval een kadertje bij gebruik van de Tab-toets, als een element de focus heeft.
#toon:focus-visible + label
Deze selector werkt alleen in browsers die :focus-visible
ondersteunen. Voor andere browsers is de uitleg hieronder niet van belang.
Voor dit element is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
#label-toon {background: white; color: black; display: inline-block; width: 8em; border: black solid 1px; border-radius: 5px; padding: 10px; position: relative;}
#toon:focus + label {outline: blue solid 5px;}
#toon:focus + label {outline: none;}
#toon:focus-visible
: het element met id="toon", maar alleen als dit de focus heeft, en alleen als die focus door gebruik van de Tab-toets is gekregen. Een focus die door een klik of aanraking is verkregen, wordt door de browser genegeerd.
+
: het element achter de +
moet in de html direct volgen op het element voor de +
. In dit geval gaat het om #label-toon
gelijk volgend op input#toon
.Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder div#wrapper
.
label
: de in de html gelijk op input#toon
volgende label#label-toon
.
De hele selector in gewone mensentaal: doe iets met de <label> die op input#toon
volgt, maar alleen als die <input> de focus heeft, en alleen als die focus door gebruik van de Tab-toets is verkregen.
outline: blue solid 5px;
Blauwe outline van 5 px breed.
Deze outline verschijnt, door het gebruik van :focus-visible
in plaats van :focus
, alleen als input#toon
de focus krijgt door gebruik van de Tab-toets, en niet bij een klik of een aanraking.
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.
(function () {
"use strict";
let toon = document.querySelector("#toon"),
origineel = document.querySelector("#origineel"),
vervang = document.querySelector("#vervang");
toon.addEventListener("change", wijzigAriaHidden);
function wijzigAriaHidden (e) {
if (e.target.checked) {
origineel.setAttribute("aria-hidden", true);
vervang.setAttribute("aria-hidden", false);
} else {
origineel.setAttribute("aria-hidden", false);
vervang.setAttribute("aria-hidden", true);
}
}
}) ();
Als je bovenstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.
Met dit script wordt voorkomen dat schermlezers altijd de alt-teksten bij beide afbeeldingen voorlezen. Door het aanpassen van de waarde bij aria-hidden wordt alleen de alt-tekst van de getoonde afbeelding voorgelezen.
(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 aan- en uitvinken van input#toon
. Om die functie goed te laten werken, moet de computer eerst wat voorbereidend werk verrichten. Daarvoor moet het script worden gelezen. Maar dat hele script zit in een functie, en die functie doet dus pas wat, als die wordt aangeroepen.
Om te zorgen dat de buitenste functie, die waar alle code in zit, toch vanzelf wordt uitgevoerd, zet je er een (
voor. En helemaal aan het eind, achter de afsluitende }
, zet je de tegenhanger )
. Om te zorgen dat de functie echt vanzelf wordt uitgevoerd, moeten hierachter nog twee haakjes ()
worden gezet. Nu wordt de functie automatisch uitgevoerd, zonder dat deze hoeft te worden aangeroepen. En kan de code in het script worden gelezen, waardoor het benodigde voorbereidende werk kan worden uitgevoerd.
(Je kunt de code ook in een niet alles omvattende functie zetten. Dan wordt de code gelijk uitgevoerd. Maar dat brengt belangrijke risico's met zich mee. In dit script worden namen voor variabelen gebruikt als 'toon' en 'origineel'. 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.
let toon = document.querySelector("#toon"),
Als je in de html een andere id dan 'toon' hebt gebruikt bij input#toon
, moet je die id ook in bovenstaande regel aanpassen. Dit is de enige plaats in het script, waar je dit moet aanpassen.
In dit deel van de code worden een paar dingen voorbereid. Het écht uitvoerende deel van het script, waarin bijvoorbeeld een toetsaanslag daadwerkelijk wordt herkend, volgt later.
Het is gebruikelijk dit soort voorbereidende zaken bovenin het script te zetten.
Deze regel valt in een aantal delen uiteen, die worden gescheiden door een komma. Het eerste deel begint met let
. Dit sleutelwoord let
wordt automatisch ook voor de andere delen geplaatst, omdat die delen op een komma volgen. Door die komma weet het script dat het hier om bij elkaar horende delen van één regel gaat.
Na het laatste 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 let
voor alle delen geldt, dat hier drie variabelen worden aangemaakt: in elke regel één.
Pardon? Variwiewatwaar? Ha, leuk dat je het vraagt.
let
: het begin van het eerste deel van de eerste regel. Met het sleutelwoord let
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 let
volgen de namen van de variabelen. Als er meerdere variabelen zijn, zoals hier het geval is, worden die gescheiden door een komma. Hier zijn de variabelen 'toon', 'origineel' en 'vervang' Elke variabele staat óf helemaal alleen op een eigen regel, óf aan het begin van een regel, gelijk gevolgd door een isgelijkteken.
In 'toon', 'origineel' en 'vervang' 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. Als het om iets simpels gaat, wordt het hier opgegeven. Als het om iets meer ingewikkelds gaat, of als nog niet bekend is, wat moet worden opgeslagen, gebeurt het later.
(Heel vaak zou je in plaats van iets opbergen in deze variabelen iets elke keer dat het nodig is opnieuw kunnen opzoeken. Zo wordt hieronder input#toon
opgezocht met document.querySelector("toon")
en opgeslagen in de variabele 'toon'. Je zou ook elke keer input#toon
opnieuw kunnen opzoeken. Maar dat is een bijzonder slecht idee. De code wordt veel minder leesbaar en vooral: dat opzoeken kost relatief veel tijd. Daarom kun je vaak beter iets één keer opzoeken en het resultaat van die speurtocht opslaan en gebruiken.)
De variabelen krijgen hier hun naam, ze worden hier 'gedeclareerd' of 'aangemaakt'. Dat gebeurt in de volgorde, waarin ze in het script worden gebruikt. Die volgorde hoeft niet, dat is een kwestie van voorkeur. Je hoeft ook niet alle variabelen aan het begin van het script aan te maken, maar dat is wel overzichtelijker.
Omdat deze variabelen helemaal bovenaan de bij (function () { beschreven buitenste functie al worden aangemaakt, kunnen deze variabelen overal binnen die functie worden gebruikt. En omdat dit hele script binnen die functie staat, kunnen ze overal in het script worden gebruikt.
Hieronder worden de aangemaakte variabelen één voor één doorgenomen.
toon = document.querySelector("#toon"),
Als je in de html een andere id dan 'toon' hebt gebruikt bij input#toon
, moet je die id ook in bovenstaande regel aanpassen. Dit is de enige plaats in het script, waar je dit moet aanpassen.
toon
: dit is de variabele, waarin iets moet worden opgeborgen.
=
: 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.querySelector("#toon")
: het middelste stukje querySelector
is een zogenaamde 'functie'. Een functie is een stukje in de browser ingebakken code, waarmee je iets kunt doen. Deze functie is te vinden in het object document
, vandaar dat document
ervoor staat.
Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.
JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document
bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.
Met de methode querySelector()
uit document
kan JavaScript het eerste element van 'n bepaalde soort opzoeken, zoals de eerste <div>, het eerste element met een class="hoera", en dergelijke. Het gegeven waarnaar wordt gezocht, staat tussen aanhalingstekens tussen de haakjes:
querySelector("#toon")
.
Hierbij is de syntax van het deel tussen de aanhalingstekens precies hetzelfde als bij een selector in css. In bovenstaande regel wordt naar het element met id="toon" gezocht, net zoals je in css in een selector #toon {...}
zou gebruiken.
Zou je naar de eerste <span> zoeken die een eerste kind is, dan zou je de volgende regel gebruiken:
querySelector("span:first-child")
Precies zoals selectors in css werken.
De hele declaratie toon = document.querySelector("#toon")
: sla het element met id="toon" op in toon
. Dat wil zeggen dat in variabele toon
een ongelooflijke hoeveelheid informatie over input#toon
wordt gestopt, waar het script later gebruik van kan maken. Zo zit bijvoorbeeld alle css, die aan input#toon
is gegeven, ook in toon
. Maar niet alleen de in de stylesheet opgegeven css, ook alle standaardwaarden, en ook alle css die van voorouders wordt geërfd. Alle nakomelingen van input#toon
en hun css, attributen, enzovoort, zitten ook in toon
.
Van al deze informatie in toon
kan het script gebruik maken. En ook kunnen veel van deze dingen worden veranderd door het script, zoals een kleur veranderen, of een element verwijderen, of juist toevoegen.
Feitelijk is input#toon
in de vorm van een object in toon
opgeslagen. Naast allerlei informatie die in dat object zelf in toon
wordt opgeslagen, kun je daardoor ook gebruik maken van allerlei methoden, die JavaScript gratis en voor niets toevoegt aan het object in toon
.
Het script gebruikt het object in variabele toon
, de input#toon
, om te kijken of input#toon
wordt aan- of uitgevinkt. Aan de hand daarvan kan dan met behulp van het veranderen van de waarde bij aria-hidden worden gezorgd, dat schermlezers alleen de alt-tekst van de getoonde afbeelding voorlezen.
,
: helemaal aan het eind staat nog een komma. De regel eindigt hier niet, er moeten nog meer variabelen worden aangemaakt.
De hele regel in gewone taal: stop input#toon
in de vorm van een object in variabele 'toon'.
origineel = document.querySelector("#origineel"),
Als je in de html een andere id dan 'origineel' hebt gebruikt bij img#origineel
, moet je die id ook in
bovenstaande regel aanpassen. Dit is de enige plaats in het script, waar je dit moet aanpassen.
Dit werkt precies hetzelfde als bij toon = document.querySelector("#toon"), hier gelijk boven, alleen wordt hier in variabele 'origineel' de originele afbeelding img#origineel
opgeslagen.
vervang = document.querySelector("#vervang");
Als je in de html een andere id dan 'vervang' hebt gebruikt bij img#vervang, moet je die id ook in bovenstaande regel aanpassen. Dit is de enige plaats in het script, waar je dit moet aanpassen.
Het enige verschil is verder dat hier aan het einde van de regel geen ,
staat, maar een ;
. Dit is de laatste variabele die wordt aangemaakt, en daarom eindigt de regel hier echt. In gewone tekst zou je hier een punt gebruiken om het eind van de regel aan te geven, in JavaScript gebruikt je daar een puntkomma voor.
if (e.target.checked) {
Deze regel is onderdeel van function wijzigAriaHidden (e) {
if
: dat betekent gewoon 'als': als er aan de voorwaarde hierachter is voldaan. Die voorwaarde staat tussen haakjes, omdat dat nou eenmaal zo hoort. Het is het hele deel tussen de twee buitenste haakjes achter de if
.
e
: in e
zit een zogenaamd object, waarin allerlei informatie zit. Bij function wijzigAriaHidden (e) {, de functie waar deze regel een onderdeel van is, is dit object aan de functie doorgegeven. Hierdoor kan de code in de functie de informatie uit dit object gebruiken.
target
: dit is zo'n stukje informatie uit het hierboven genoemde object: hierin zit het element, wat de functie heeft aangeroepen. Hier is dat input#toon
, want bij toon.addEventListener("change", wijzigAriaHidden); is gezorgd dat bij aan- of uitvinken van input#toon
deze functie wordt aangeroepen.
Feitelijk is target
ook weer een object. Hierdoor zit er allerlei informatie in over input#toon
(en zou je ook van alles met input#toon
kunnen doen, maar dat gebeurt hier niet.)
checked
: dit is zo'n stukje informatie uit target
. Als input#toon
is aangevinkt, heeft checked
de waarde 'true'. Als input#toon
is uitgevinkt, heeft checked
de waarde 'false'.
{
: de code die wordt uitgevoerd, als aan deze if
-voorwaarde wordt voldaan, wordt tussen accolades gezet. Het script weet dan, wat bij deze if
hoort. Aan het eind van de code bij deze if
staat de afsluitende }
.
De hele regel in gewone taal: als input#toon
is aangevinkt, voer dan de code tussen de {}
achter de if
uit.
} else {
Deze regel is onderdeel van function wijzigAriaHidden (e) {
Deze else
hoort bij if (e.target.checked) {: als input#toon
is aangevinkt. De code tussen de {}
achter deze else
wordt daarom alleen uitgevoerd, als input#toon
niet is aangevinkt.
}
: dit is de afsluitende accolade van de code die bij de hierboven genoemde if
hoort.
else
: als de voorwaarde bij die if
niet waar is, voer dan de code tussen de {}
bij deze else
uit. Er staat hier verder geen voorwaarde of zo: deze code wordt gewoon altijd uitgevoerd, als de voorwaarde bij de if
niet waar is.
{
: de code die wordt uitgevoerd, als aan deze else
wordt voldaan, wordt tussen accolades gezet. Het script weet dan, wat bij deze else
hoort. Aan het eind van de code bij deze else
staat de afsluitende }
.
De hele regel in gewone taal: voer de code tussen de {}
bij de else
uit, als input#toon
niet is aangevinkt.