Skip links en inhoudsopgave

Onderdelen van een formulier in- en uitschakelen met behulp van enabled en disabled - uitleg

Laatst aangepast: .

Formulier met in- en uigeschakelde onderdelen

Korte omschrijving

Onderdelen in een formulier worden in- of uitgeschakeld, afhankelijk van eerdere keuzes in dat formulier.

BELANGRIJK

Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.

Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.

Als je dit lastig vindt, kun je bovenaan de pagina de hele handel downloaden. In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.

Alles op deze site kan vrij worden gebruikt, met twee beperkingen:

* Je gebruikt het materiaal op deze site volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte info zitten. Voor eventuele schade die door gebruik van materiaal van deze site ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.

* Deze uitleg wordt regelmatig bijgewerkt. Het is daarom niet toegestaan deze uitleg op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat de uitleg afkomstig is van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.

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 in een gewone letter vanwege de leesbaarheid.)

Opmerkingen

Links in deze uitleg, vooral links naar andere sites, kunnen verouderd zijn. Op de pagina met links vind je steeds de meest recente links.

Alles op deze site is gemaakt op een systeem met Linux (Kubuntu). Daarbij is vooral gebruik gemaakt van Komodo Edit, GIMP en Firefox met extensies. De pdf-bestanden zijn gemaakt met LibreOffice.

Vragen of opmerkingen? Fout gevonden? Ga naar het forum.

Achterliggend idee

Al in html 4.01 kon het attribuut disabled aan bepaalde elementen worden toegevoegd. Hiermee werd voorkomen dat het element kon worden gewijzigd. Dit attribuut heeft dan ook alleen maar zin in elementen, die kúnnen worden gewijzigd: <button>, <input>, <optgroup>, <option>, <select>, <textarea> en <fieldset>. Als het wordt toegepast bij een <fieldset>, geldt het voor alle nakomelingen van die <fieldset>.

Browsers geven een uitgeschakeld element op een andere manier weer, in de regel wat vager. Schermlezers geven het ook op een of andere manier duidelijk aan.

Omdat disabled in de html staat, kan het alleen maar met behulp van iets als JavaScript worden gewijzigd. Ook het uiterlijk van een in- of uitgeschakeld element kon alleen met behulp van iets als JavaScript worden veranderd.

Het in- en uitschakelen van een element gebeurt nog steeds met behulp van JavaScript. Maar css3 kent de pseudo-classes :enabled en :disabled. En met behulp daarvan kan het uiterlijk van een in- of uitgeschakeld element met behulp van css worden gewijzigd. Waarmee het attribuut disabled gelijk een stuk interessanter wordt.

Als een element in de html het attribuut disabled heeft gekregen, kan dit worden aangesproken met behulp van de selector :disabled. Als een element is ingeschakeld, kan het worden aangesproken met behulp van de selector :enabled.

Als een element in de html niet het attribuut disabled heeft, is het automatisch ingeschakeld. Er bestaat geen enabled of zoiets voor html, alleen disabled. De selector :enabled zal dan ook minder snel gebruikt worden, want dat is feitelijk de standaardinstelling.

Als een <input> bijvoorbeeld een witte achtergrond heeft, kun je aan die <input> met JavaScript het attribuut disabled aan toevoegen. Met de css-selector :disabled kun je dan daarop testen en bijvoorbeeld de achtergrond rood maken. Het verwijderen van disabled uit de html is voldoende om de achtergrond dan weer wit te maken.

Iets als input:enabled {background: white;} is niet nodig. Het simpele verwijderen van het attribuut disabled is voldoende om de achtergrond weer wit te maken.

Als in de css bij dit voorbeeld :enabled {background: green;} zou worden toegevoegd, is de achtergrond van alle elementen in het formulier gelijk groen, zonder verder iets te doen. (Dit geldt niet voor de elementen, waar in de html het attribuut disabled staat, want die zijn niet enabled.)

Kortom: de selector :enabled zal, anders dan :disabled, niet zo snel gebruikt worden.

Bij opening van de pagina is bij de vraag 'Moet de rekening ook naar dit adres?' met behulp van het attribuut checked 'Ja' aangevinkt. Pas als hier 'nee' wordt aangevinkt, kun je een afwijkend adres voor de rekening opgeven.

Bij de velden voor Naam, Adres, Stad en Postcode onder 'Rekening sturen naar' is in de html het attribuut disabled toegevoegd. Met behulp van de selector input:disabled wordt de achtergrond van de velden rood gekleurd en verandert de cursor in een 'verboden'-symbooltje. De browser zelf blokkeert de invoer van tekst bij gebruik van disabled.

Als bij de vraag 'Moet de rekening ook naar dit adres?' vervolgens voor 'Nee' wordt gekozen, wordt met behulp van JavaScript het attribuut disabled verwijderd bij Naam, Adres, Stad en Postcode onder 'Rekening sturen naar:'. Hierdoor worden ze niet meer aangesproken door input:disabled en verdwijnt de rode achtergrond.

De browser zelf zorgt ervoor dat de velden nu ook zijn in te vullen.

Als je kiest voor 'Nee', een adres opgeeft, en daarna weer voor 'Ja' kiest, blijft het ingevoerde adres gewoon staan. Als beveiliging is dit dan ook volslagen waardeloos, het is heel makkelijk te omzeilen. Vertrouw nooit op alleen het attribuut disabled als je een formulier verstuurt.

Bij opening van de pagina is bij de vraag 'Ben je achttien jaar of ouder?' met behulp van het attribuut checked 'Nee' ingevuld. Bij een aantal dranken daaronder onder het kopje 'Ja! Stuur mij met spoed één fles:' is het attribuut disabled toegevoegd: deze dranken kunnen niet worden aangevinkt.

Met behulp van de selector input:disabled + label wordt bij deze dranken de achtergrond rood gekleurd, de tekst wordt wat vager en de cursor verandert in een 'verboden'-symbooltje.

Als het antwoord op de leeftijdsvraag wordt veranderd in 'Ja', wordt met behulp van JavaScript het attribuut disabled verwijderd uit de html. Hierdoor verdwijnt ook de rode achtergrond en wordt de tekst gewoon zwart. De browser accepteert nu ook het aanvinken van deze dranken.

Als is opgegeven dat de bezoeker achttien jaar of ouder is, kun je alle dranken aanvinken. Als daarna toch wordt gezegd dat de bezoeker nog geen achttien is, zijn die dranken al aangevinkt. Bij zo'n verandering van 'achttien of ouder' naar 'nog geen achttien', worden bij die dan 'verboden' dranken de vinkjes verwijderd. Bij de andere dranken blijven ze gewoon staan.

Om dit te kunnen doen is aan de drankjes voor achttien en ouder een class='achttien' gegeven. Door hier met JavaScript naar te zoeken, kun je alleen bij die drankjes het vinkje verwijderen, terwijl het vinkje bij de toegestane drankjes gewoon blijft staan.

Schermlezers en dergelijke hebben niets aan al die mooie kleurtjes en vinkjes en zo. Daarom is voor schermlezers gebruik gemaakt van zogenaamde WAI-ARIA-codes. Deze lopen in dit geval ongeveer parallel met de html-attributen checked en disabled.

Het aanbrengen en wijzigen van deze codes wordt in de uitleg beschreven, op dezelfde plaatsen als waar de 'gewone' codes worden beschreven. Een apart verhaal over de in dit voorbeeld gebruikte WAI-ARIA-codes is te vinden bij WAI-ARIA-codes.

De voorvoegsels -moz-, -ms- en -webkit-

Voordat een nieuwe css-eigenschap wordt ingevoerd, is er in de regel een experimentele fase. Browsers passen het dan al toe, maar met een aangepaste naam. Tijdens deze fase kunnen problemen worden opgelost en worden veldslagen uitgevochten, over hoe de standaard precies moet worden toegepast.

Als iedereen het overal over eens is en alle problemen zijn opgelost, wordt de officiële naam uit de standaard gebruikt.

De belangrijkste browsers hebben elk een eigen voorvoegsel:

Firefox: -moz-, naar de maker: Mozilla.

Op webkit gebaseerde browsers, zoals Google Chrome, Safari en Android browser: -webkit-.

(Google Chrome is van webkit overgestapt op een eigen weergave-machine: blink. Blink gaat geen voorvoegsels gebruiken. Het is echter een aftakking van webkit, dus het zal nog wel even duren voor -webkit- hier helemaal uit is verdwenen. Ook Opera gebruikt inmiddels Blink, inclusief het daar nog in gebruikte -webkit-. Hierdoor is het tot voor kort door Opera gebruikte voorvoegsel -o- niet meer nodig.)

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

In dit voorbeeld wordt ::placeholder gebruikt.

Zodra de experimentele fase voorbij is, wordt het voorvoegsel weggelaten. Omdat dat moment niet bij alle browsers hetzelfde is, zet je nu ook al de officiële naam erbij. Deze wordt als laatste opgegeven. Bijvoorbeeld Android browser herkent -webkit-linear-gradient. Zodra Android browser linear-gradient gaat herkennen, zal dit -webkit-linear-gradient overrulen, omdat het er later in staat. Dat ze er beide in staan, is dus geen enkel probleem.

::placeholder

::placeholder is een pseudo-element uit de selectors level 4. css is inmiddels zo groot geworden, dat het is opgesplitst in een groot aantal onderdelen, die los van elkaar een eigen level krijgen. Je zou kunnen zeggen dat dit een selector is uit css4, behalve dat css4 dus niet bestaat en ook nooit zal bestaan.

Er bestaan nogal wat schrijfwijzen voor dit pseudo-element. In de ontwerp-specificatie wordt gezegd dat het uiteindelijk waarschijnlijk ::placeholder wordt, maar ook dat is niet zeker. Het wordt in dit voorbeeld echter alleen gebruikt om de tekst in het tekstveld onderaan iets duidelijker te maken. Als het alsnog helemaal zou wijzigen en daardoor niet meer zou werken, is dat niet zo'n ramp.

Om dit schrijfwijzenfestijn nog feestelijker te maken, moeten de diverse css-regels elk op een aparte regel worden neergezet. Anders werken ze niet. Verder heeft Microsoft twee variaties: eentje voor Internet Explorer en eentje voor Edge. En dan laten we de oudere vormen voor Firefox en dergelijke nog buiten beschouwing...

Op dit moment moet je nog schrijven:

textarea:-ms-input-placeholder {...;}

textarea::-ms-input-placeholder {...;}

textarea::-webkit-input-placeholder {...;}

textarea::-moz-placeholder {...;}

textarea::placeholder {...;}

In de toekomst kun je volstaan met:

::placeholder {...)

Maar het kan dus prima, dat de uiteindelijke vorm toch weer anders wordt.

Inmiddels is de algemene mening dat 'vendor prefixes', zoals deze voorvoegsels in het Engels heten, geen groot succes zijn. Eén van de grootste problemen: veel sitemakers gebruiken alleen de -webkit-variant. Daar kwamen ze in het verleden nog mee weg, omdat Apple op mobiel zo'n beetje 'n monopolie had. Inmiddels is dat niet meer zo, maar deze gewoonte bestaat nog steeds. Waardoor 'n site alleen in op webkit georiënteerde browsers goed is te bekijken.

Dit is zo'n groot probleem dat andere browsers soms de variant met -webkit- ook maar zijn gaan implementeren, naast de standaard. Want als 'n site het niet goed doet in 'n bepaalde browser, krijgt in de regel niet de site maar de browser de schuld.

Voorlopig zijn we echter nog niet van deze voorvoegsels af. Als je ze gebruikt, gebruik dan álle varianten, en eindig met de variant zonder voorvoegsel, zoals die uiteindelijk ooit gebruikt gaat worden. Als je alleen de -webkit-variant gebruikt, ben je in feite 'n onbetaalde reclamemaker voor Apple.

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 ergens op de pagina te rechtsklikken en te kiezen voor Paginabron bekijken, of door in het menu te kiezen voor Extra → Webontwikkelaar → Paginabron. (Of door de veel snellere sneltoets Ctrl+U.) Elke browser heeft dit soort mogelijkheden.

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

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

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

Elke browser heeft inmiddels mogelijkheden om de gegenereerde code te bekijken. In Firefox bijvoorbeeld in het menu Extra → Webontwikkelaar → Hulpmiddelen in-/uitschakelen. In Google Chrome in het menu onder Meer hulpprogramma's → Hulpprogramma's voor ontwikkelaars. In Internet Explorer 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.

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

Door het op de goede manier gebruiken van semantische elementen, kunnen zoekmachines, schermlezers, enz. 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.

Meestal wordt op deze site weinig of geen aandacht aan JavaScript besteed. In dit voorbeeld is dit anders, omdat de hier gebruikte attributen en de bijbehorende selectors alleen met behulp van JavaScript kunnen worden veranderd.

Html5 heeft een aantal nieuwe elementen, die speciaal zijn bedoeld om de opbouw van een pagina aan te geven, zoals <nav>, <header> en <footer> In dit voorbeeld wordt hiervan alleen <main> gebruikt: het begin van de belangrijkste inhoud van de pagina.

WAI-ARIA-codes

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

Er worden in dit voorbeeld twee WAI-ARIA-codes gebruikt: aria-checked en aria-disabled. Dit zijn speciale codes voor schermlezers, zoals blinden die gebruiken.

Nieuwere schermlezers hebben dit niet meer nodig, die gebruiken gewoon de 'boekhouding' van de browser. Maar oudere schermlezers hebben wel een WAI-ARIA-code nodig. En sommige schermlezers zijn peperduur, dus niet iedereen werkt met de nieuwste versie.

Wat betreft het in dit voorbeeld gebruikte attribuut disabled: de ondersteuning hiervan in schermlezers is nogal onduidelijk, maar het lijkt erop dat die bepaald niet heel goed is. aria-disabled is dus hoe dan ook nodig, en dan is het een kleine moeite om ook aria-checked toe te voegen.

Het is in dit voorbeeld hoe dan ook niet zoveel extra werk, omdat toch al JavaScript nodig is om het disabled-attribuut in de html af te handelen.

aria-checked

Als een radioknop of keuzevakje wordt aangevinkt, is dit element 'checked'. Tja, css is nou eenmaal een Engelse taal, dus aan Engels is niet te ontkomen, vrees ik.

Als je het element bij openen van de pagina al aangevinkt wilt hebben, voeg je in de html het attribuut checked toe. Dat is op deze pagina gebeurd bij 'Ja' onder 'Moet de rekening ook naar dit adres?', bij 'Nee' onder 'Ben je achttien jaar of ouder?' en bij de dranken die onder de achttien niet gekocht mogen worden.

Bij de leeftijdsvraag ziet dat er zo uit:

<input type="radio" name="achttien" id="geen-achttien" value="nee" checked aria-checked="true">

Dat het element is aangevinkt, wordt op een of andere manier aangegeven door de browser, bijvoorbeeld door een kruisje in het keuzevakje te zetten. Per browser verschilt dit.

Dit wordt verder helemaal door de browser afgehandeld en is alleen nog van belang, als een formulier wordt verzonden. (En voor enkele trucs, zoals de zogenaamde 'checkbox hack', waar ik hier verder niet op inga.)

Dat zichtbare weergeven van aangevinkt zijn of niet is mooi, maar een schermlezer heeft daar niets aan. Die leest de pagina voor en een blinde wordt vermoedelijk niet vrolijk als bij elk keuzevakje en dergelijke het uiterlijk wordt beschreven: "Mooi vormgegeven blauw vierkantje met daarin een artistiek zwart kruisje", bij elk keuzevakje. En dat dan vijftig keer of zo per formulier.

Daarom geeft een schermlezer gewoon aan, of een element is aangevinkt of niet. Dat doet elke schermlezer op z'n eigen manier, maar allemaal in ieder geval korter dan zoals ik het hierboven deed.

Voor schermlezers wordt een speciale WAI-ARIA-code toegevoegd, als het element is aangevinkt: aria-checked="true".

In het stukje code hier iets boven staat dit ook. Daar is het gewoon in de html opgegeven, omdat de radioknop bij openen van de pagina aangevinkt moet zijn. Dat gebeurt door het attribuut checked te gebruiken, en aria-checked="true" is daar het tweelingzusje voor schermlezers van.

Als bij een van bovenstaande vragen 'Ja' in 'Nee' wordt veranderd, of omgekeerd, verandert 'checked'. Dat wordt volledig door de browser afgehandeld. Om te zorgen dat ook schermlezers dit weten, wordt met behulp van JavaScript bij elk vinkje dat wordt geplaatst aria-checked="true" toegevoegd. En bij elk vinkje dat wordt verwijderd aria-checked="false".

Omdat deze codes door JavaScript worden ingevoegd of gewijzigd, zijn ze niet zichtbaar, als je gewoon de html bekijkt. Ze zijn alleen zichtbaar in de gegenereerde code.

aria-disabled

Je kunt elementen in een formulier uitschakelen met behulp van het attribuut disabled. Vervolgens kun je met behulp van de css-selector :disabled het uiterlijk veranderen.

In dit voorbeeld zijn, bij opening van de pagina, de mogelijkheid een ander adres voor de rekening op te geven en bepaalde keuzen bij de dranken uitgeschakeld. Dat ziet er bij de alom bekende en beruchte Fiedelvitriool als volgt uit:

<input name="fiedelvitriool" id="fiedelvitriool" class="achttien" type="checkbox" disabled aria-disabled="true">

De toevoeging disabled zorgt ervoor dat deze drank niet aangevinkt kan worden. En met behulp van de css-selector :disabled wordt de achtergrond rood gemaakt, de tekst wordt iets vager en de cursor verandert in een 'verboden'-symbooltje.

Aan deze verandering van het uiterlijk heeft een schermlezer niets. Voor schermlezers wordt daarom de code aria-disabled="true" toegevoegd. Dit wordt gewoon in de html aangebracht, op dezelfde plaats als waar ook disabled staat.

Afhankelijk van de antwoorden op twee vragen, kunnen bepaalde elementen toch nog worden gekozen of ingevuld. Om dit voor elkaar te krijgen, wordt met behulp van JavaScript het attribuut disabled verwijderd. Als ze weer uitgeschakeld moeten worden, wordt met behulp van JavaScript disabled weer toegevoegd.

Elke keer als disabled wordt toegevoegd, wordt door het JavaScript ook de WAI-ARIA-code aria-disabled="true" toegevoegd. En elke keer als disabled wordt verwijderd, wordt de code aria-disabled="false" toegevoegd.

Omdat deze codes door JavaScript worden ingevoegd, zijn ze niet zichtbaar, als je gewoon de html bekijkt. Ze zijn alleen zichtbaar in de gegenereerde code.

De code aanpassen aan je eigen ontwerp

Toegankelijkheid en zoekmachines

Het eerste deel van deze tekst is voor alle voorbeelden hetzelfde. Eventueel specifiek voor dit voorbeeld geldende dingen staan verderop onder het kopje Specifiek voor dit voorbeeld.

Toegankelijkheid (accessibility in het Engels) 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:

Specifiek voor dit voorbeeld

Getest in

Laatst gecontroleerd op 14 december 2015.

Onder dit kopje staat alleen maar, hoe en waarin is getest. Eventuele problemen, ook die met betrekking tot zoomen en lettergroottes, staan 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!

Eventuele opmerkingen over de toegankelijkheid specifiek voor dit voorbeeld staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld.

Dit voorbeeld is getest op de volgende systemen:

Er is steeds getest met de laatste versie van de browsers op de aan het begin van dit hoofdstukje genoemde controledatum, omdat ik geen zin heb om rekening te houden met mensen die met zwaar verouderde browsers surfen. Dat is trouwens vragen om ellende, want updates van browsers hebben heel vaak met beveiligingsproblemen te maken.

Ook op Windows XP kunnen mensen surfen met Firefox, Opera of Google Chrome, dus ook daar zijn mensen niet afhankelijk van Internet Explorer 8. Ik maak één uitzondering: Android browser. Omdat Android vaak niet geüpdatet kan worden, test ik ook nog in oudere versies van Android browser.

In resoluties groter dan 800x600 is ook in- en uitzoomen en – voor zover de browser dat kan – een kleinere en grotere letter getest. Er is ingezoomd en vergroot tot zover de browser kan, maar niet verder dan 200%.

Er is getest met behulp van muis en toetsenbord, behalve op de iPad, Android en Windows Phone, waar een touchscreen is gebruikt. Op Windows 8.1 is getest met een touchscreen, met een combinatie van toetsenbord en touchpad, en met een combinatie van toetsenbord en muis.

Op de desktop is ook getest, als JavaScript uitstaat. Eventuele problemen staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld. (Op iOS, Android en Windows Phone is niet getest zonder JavaScript, omdat je JavaScript in een toenemend aantal mobiele browsers niet uit kunt zetten. Bovendien is een mobiel apparaat zonder JavaScript niet veel meer dan een duur en groot uitgevallen horloge.)

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

Lynx is een browser die alleen tekst laat zien en geen css gebruikt. Er is getest op Linux.

WebbIE is een browser die gericht is op mensen met een handicap. Er is getest op Windows 7.

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

TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome.

VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS en OSX.

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 opmerkingen over de toegankelijkheid specifiek voor dit voorbeeld staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld.

Alleen op de hierboven genoemde systemen en browsers is getest. Er is dus niet getest op bijvoorbeeld 'n Blackberry. De kans is (heel erg) groot dat dit voorbeeld niet (volledig) werkt op niet-geteste systemen en apparaten. Om het wel (volledig) werkend te krijgen, zul je vaak (kleine) wijzigingen en/of (kleine) aanvullingen moeten aanbrengen, bijvoorbeeld met JavaScript.

Er is ook geen enkele garantie dat iets werkt in een andere tablet of smartphone dan hierboven genoemd, omdat fabrikanten in principe de software kunnen veranderen. Dit is anders dan op de desktop, waar browsers altijd (vrijwel) hetzelfde werken, zelfs op verschillende besturingssystemen. Iets wat in Android browser werkt, zal in de regel overal werken in die browser, maar een garantie is er niet. De enige garantie is het daadwerkelijk testen op een fysiek apparaat. En aangezien er duizenden mobiele apparaten zijn, is daar eigenlijk geen beginnen aan.

De html is gevalideerd met de validator van w3c, de css ook. Als om een of andere reden niet volledig gevalideerd kon worden, wordt dat bij Bekende problemen (en oplossingen) vermeld.

Nieuwe browsers test ik pas, als ze uit het bèta-stadium zijn, omdat er anders 'n redelijke kans is dat ik 'n bug zit te omzeilen, 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 kan ik niet beantwoorden, en het melden van fouten in niet-geteste browsers heeft ook geen enkel nut. (Melden van fouten, problemen, enz. in wel geteste browsers: graag!)

Bekende problemen (en oplossingen)

Waarop en hoe is getest, kun je gelijk hierboven vinden bij Getest in.

Als je hieronder geen oplossing vindt voor een probleem dat met dit voorbeeld te maken heeft, kun je op het forum proberen een oplossing te vinden voor je probleem. Om forumspam te voorkomen, moet je je helaas wel registreren, voordat je op het forum een probleem kunt aankaarten.

Android browser

In de <textarea> onderaan is alvast een tekst ingevuld met behulp van het placeholder-attribuut. Deze tekst is te lang voor één regel. Op de smartphone met Android 4.1.2 wordt de tekst toch op één lange regel gezet, waardoor een groot deel van de tekst rechts van het venster verdwijnt. De tekst kan ook niet door scrollen zichtbaar worden gemaakt.

Dit gebeurt ook in Android 4.4.2 op de tablet, maar alleen bij de tablet met de gewone resolutie (90-99 dpi). Op de hogeresolutie-tablet, gaat het wel goed.

Hoogst merkwaardig, want beide tablets zijn van Samsung en hebben dezelfde versie van Android.

Internet Explorer 9

  • In het tekstvak onderaan is alvast een tekst ingevuld met behulp van het placeholder-attribuut. Internet Explorer 9 kent dit niet, dus is bij deze browser in het tekstvak niets ingevuld.

    Als je dit belangrijk vindt, kun je eventueel een zogenaamde 'polyfill' gebruiken: een JavaScript dat een ontbrekende functie (min of meer) mogelijk maakt in browsers, die deze functie anders niet kunnen uitvoeren. Op HTML5 Cross Browser Polyfills staat een gigantische lijst met polyfills.

  • Internet Explorer 9 kent border-radius niet. De hoekjes van de border rondom de <fieldset>'s zijn daardoor gewoon recht. Net als hier gelijk boven kun je ook hiervoor, als je dit belangrijk vindt, eventueel een polyfill gebruiken.

Wijzigingen

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

:

Nieuw opgenomen.

14 december 2015:

css voor ::placeholder verbeterd. Bij de documentatie van Mozilla voor Firefox ontbrak wat, waardoor onbekend was dat voor Firefox ook opacity gebruikt moet worden.

Inhoud van de download en licenties

De inhoud van deze download kan vrij worden gebruikt, met drie beperkingen:

* Sommige onderdelen die van 'n andere site of zo afkomstig zijn, vallen mogelijk onder een of andere licentie. Dat is hieronder bij het betreffende onderdeel te vinden.

* Je gebruikt het materiaal uit deze download volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte code en dergelijke zitten. Voor eventuele schade die door gebruik van materiaal uit deze download ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.

* Dit voorbeeld (en de bijbehorende uitleg en dergelijke) wordt regelmatig bijgewerkt. Het is daarom niet toegestaan dit voorbeeld (en de bijbehorende uitleg en dergelijke) op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat voorbeeld, uitleg, en dergelijke afkomstig zijn van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.

Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.

tekst-106-dl.html: de pagina met het voorbeeld.

tekst-106.pdf: deze uitleg (aangepast aan de inhoud van de download).

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

106-css-dl:

tekst-106-dl.css: stylesheet voor tekst-106-dl.html.

106-js:

tekst-106.js: het JavaScript dat disabled, checked, en dergelijke toevoegt en verwijdert.

HTML

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

In de html hieronder wordt alleen de html besproken, waarover iets meer is te vertellen. Een <h1> bijvoorbeeld wordt in de regel niet genoemd, omdat daarover weinig interessants valt te melden. (Als bijvoorbeeld het uiterlijk van de <h1> wordt aangepast met behulp van css, staat dat verderop bij de bespreking van de css.)

Zaken als een doctype en charset hebben soms wat voor veel mensen onbekende effecten, dus daarover wordt hieronder wel een en ander geschreven.

Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.

Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.

Als je dit lastig vindt, kun je bovenaan de pagina de hele handel downloaden. In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.

<!DOCTYPE html>

Een document moet met een doctype beginnen om weergaveverschillen tussen browsers te voorkomen. Zonder doctype is de kans op verschillende (en soms volkomen verkeerde) weergave tussen verschillende browsers heel erg groot.

Geldige doctypes vind je op www.w3.org/QA/2002/04/valid-dtd-list.

Gebruik het volledige doctype, inclusief de eventuele url, anders werkt het niet goed.

Het hier gebruikte doctype is dat van html5. Dit kan zonder enig probleem worden gebruikt: het werkt zelfs in Internet Explorer 6.

<html lang="nl">

De toevoeging lang="nl" bij <html> geeft aan dat de pagina in het Nederlands is. De taal is van belang voor schermlezers, automatisch afbreken, automatisch genereren van aanhalingstekens, juist gebruik van decimale punt of komma, en dergelijke.

<meta charset="utf-8">

Zorgt dat de browser letters met accenten en dergelijke goed kan weergeven.

utf-8 is de beste charset (tekenset), omdat deze alle talen van de wereld (en nog heel veel andere extra tekens) bestrijkt, maar toch niet meer ruimte inneemt voor de code, dan nodig is. Als je utf-8 gebruikt, hoef je veel minder entiteiten (&auml; en dergelijke) te gebruiken, maar kun je bijvoorbeeld gewoon ä gebruiken

Deze regel moet zo hoog mogelijk komen te staan, als eerste regel binnen de <head>, omdat hij anders door sommige browsers niet wordt gelezen.

In html5 hoeft deze regel niet langer te zijn, dan wat hier staat.

<meta name="viewport" content="width=device-width, initial-scale=1">

Mobiele apparaten variëren enorm in breedte. En dat is een probleem. Sites waren, in ieder geval tot voor kort, gemaakt voor desktopbrowsers. En die hebben, in vergelijking met bijvoorbeeld een smartphone, heel brede browservensters. Hoe moet je op 'n smartphone een pagina weergeven, die is gemaakt voor de breedte van een desktop? Je kunt natuurlijk wachten tot álle sites zijn omgebouwd voor smartphones, tablets, enz., maar dan moet je waarschijnlijk heel erg lang wachten.

Mobiele browsers gokken erop dat een pagina een bepaalde breedte heeft. Safari voor mobiel bijvoorbeeld gaat ervan uit dat een pagina 980 px breed is. De pagina wordt vervolgens zoveel versmald dat hij binnen het venster van het apparaat past. Op een iPhone wordt de pagina dus veel smaller dan op een iPad. Vervolgens kan de gebruiker inzoomen op het deel van de pagina dat hij of zij wil zien.

Dit betekent ook dat bij het openen van de pagina de tekst meestal heel erg klein wordt weergegeven. (Meestal, want niet alle browsers en apparaten doen het op dezelfde manier.) Niet erg fraai, maar bedenk maar 'ns 'n betere oplossing voor bestaande sites.

Nieuwe sites of pagina's kunnen echter wel rekening houden met de veel kleinere vensters van mobiele apparaten. Op deze pagina bijvoorbeeld passen de maten van het formulier en de onderdelen daarvan zich aan de breedte van het venster aan: ze worden 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 gebruik ik niet. De bezoeker kan zelf nog gewoon zoomen, wat belangrijk is voor mensen die wat slechter zien.

<input type="radio" name="rekening" id="zelfde-adres" value="ja" checked aria-checked="true">

<input type="radio" name="rekening" id="ander-adres" value="nee" aria-checked="false">

De twee radioknoppen bij de vraag 'Moet de rekening ook naar dit adres?'. Deze knoppen regelen, of het eronder staande rekening-adres kan worden gebruikt of niet.

Bij de eerste knop is het attribuut checked toegevoegd, zodat bij openen van de pagina deze knop al is aangevinkt. Bij deze eerste knop staat ook het attribuut aria-checked="true". Dit is feitelijk hetzelfde als checked, maar dan op schermlezers gericht.

Bij de tweede knop staat geen 'unchecked' of zoiets. Als er geen checked staat, is dat in feite hetzelfde als 'unchecked'. Dat ligt anders voor schermlezers, daarom is wel aria-checked="false" toegevoegd.

Aangevinkt of niet wordt volledig door de browser bijgehouden. De WAI-ARIA-code aria-checked wordt veranderd met behulp van JavaScript, zodat deze altijd correct weergeeft, of de knop is aangevinkt of niet. Deze door JavaScript ingevoegde of gewijzigde WAI-ARIA-codes zijn niet zichtbaar, als je gewoon de html bekijkt. Ze zijn alleen zichtbaar in de gegenereerde code.

Meer over aria-checked staat bij WAI-ARIA-codes. Meer over JavaScript staat bij JavaScript.

<input name="rekening-naam" id="rekening-naam" disabled aria-disabled="true">

<input name="rekening-adres" id="rekening-adres" disabled aria-disabled="true"> <input name="rekening-stad" id="rekening-stad" disabled aria-disabled="true"> <input name="rekening-postcode" id="rekening-postcode" disabled aria-disabled="true">

De vier <input>'s onder 'Rekening sturen naar:'

Bij deze vier velden is het attribuut disabled toegevoegd, zodat ze bij openen van de pagina zijn uitgeschakeld. Bij deze vier velden staat ook het attribuut aria-disabled="true". Dit is feitelijk hetzelfde als disabled, maar dan op schermlezers gericht.

Of deze velden zijn in- of uitgeschakeld, is afhankelijk van het antwoord op de erboven staande vraag 'Moet de rekening ook naar dit adres?'. Als het antwoord op die vraag wordt gewijzigd, wordt bij deze vier <input>'s in de html disabled toegevoegd of verwijderd met behulp van JavaScript.

Ook de WAI-ARIA-code aria-disabled wordt veranderd met behulp van JavaScript, zodat deze altijd correct weergeeft, of het veld is in- of uitgeschakeld.

Deze door JavaScript ingevoegde of gewijzigde WAI-ARIA-codes zijn niet zichtbaar, als je gewoon de html bekijkt. Ze zijn alleen zichtbaar in de gegenereerde code.

Meer over aria-disabled staat bij WAI-ARIA-codes. Meer over JavaScript staat bij JavaScript.

<input type="radio" name="achttien" id="is-achttien" value="ja" aria-checked="false">

<input type="radio" name="achttien" id="geen-achttien" value="nee" checked aria-checked="true">

De twee radioknoppen bij de vraag 'Ben je achttien jaar of ouder?'. Deze knoppen regelen, of bij de eronder staande dranken alle dranken kunnen worden aangevinkt of niet.

Bij de eerste knop is het attribuut checked toegevoegd, zodat bij openen van de pagina deze knop al is aangevinkt.

Het verhaal is verder exact hetzelfde als hierboven bij <input type="radio" name="rekening" id="zelfde-adres" value="ja" checked aria-checked="true">.

<input name="arseendrab" id="arseendrab" class="achttien" type="checkbox" disabled aria-disabled="true">

tot en met

<input name="wortelsap" id="wortelsap" type="checkbox">

In totaal veertien <input>'s, waarbij een keuzevakje kan worden aangevinkt. Zes van deze <input>'s hebben, net zoals de eerste regel met 'arseendrab' hierboven, het attribuut disabled en de class 'achttien' gekregen. Acht van deze <input>'s missen dit, net zoals de tweede regel met 'wortelsap' hierboven.

Bij openen van de pagina zijn zes van de <input>'s met behulp van het attribuut disabled uitgeschakeld. Bij deze zes <input>'s staat ook het attribuut aria-disabled="true". Dit is feitelijk hetzelfde als disabled, maar dan op schermlezers gericht.

Zodra bij de boven deze veertien <input>'s staande vraag 'Ben je achttien jaar of ouder?' 'Ja' wordt ingevuld, wordt met behulp van JavaScript het attribuut disabled verwijderd. Parallel daaraan wordt aria-disabled="true" veranderd in aria-disabled="false".

Als het antwoord op de vraag 'Ben je achttien jaar of ouder?' weer in 'Nee' wordt veranderd, wordt, bij de zes <input>'s met class="achttien", disabled weer toegevoegd en aria-disabled="false" weer veranderd in aria-disabled="true". Ook dit gebeurt door middel van JavaScript.

Meer over aria-disabled staat bij WAI-ARIA-codes. Meer over JavaScript staat bij JavaScript.

<label id="label-klachten" for="klachten">Aangezien onze spullen gewoon goed zijn, zijn klachten overbodig, onnodig en onzinnig. Lekker puh!</label>

Onder dit <label> staat een <textarea>, dat met disabled ontoegankelijk is gemaakt. Met behulp van het attribuut placeholder is in de <textarea> een tekst. Als het goed is, wordt die niet voorgelezen door schermlezers (sommige lezen het wel voor).

Daarom is dezelfde tekst hier ook neergezet binnen <label>, dat bij dat tekstvak hoort. Het wordt met behulp van css links buiten het scherm neergezet, waardoor je het niet ziet. Maar schermlezers vinden het wel en lezen het gewoon voor.

In dit geval is dat voorlezen van belang, omdat anders volstrekt onduidelijk is, waarom de <textarea> is uitgeschakeld.

<textarea name="klachten" id="klachten" placeholder="Aangezien onze spullen gewoon goed zijn, zijn klachten overbodig, onnodig en onzinnig. Lekker puh!" disabled aria-disabled="true"></textarea>

De natte droom van een aantal aandeelhouders: de klachtenafdeling gereduceerd tot een niet te wijzigen mededeling. Mocht een bedrijf deze techniek met deze letterlijke tekst daadwerkelijk gaan gebruiken, dan kondig ik nu al een claim voor liederlijk hoge copyright-, patent-, trademark-, en noem-maar-op-rechten aan.

Met behulp van het attribuut placeholder wordt een tekst in het invoerveld gezet. Standaard wordt deze tekst grijs weergegeven, waardoor hij meestal erg slecht te lezen is. Firefox maakt de tekst onduidelijker met behulp van opacity. Met behulp van css is de tekst beter leesbaar te krijgen. Meer daarover is te vinden bij textarea:-ms-input-placeholder {color: black;} en de daarop volgende css.

Door het toevoegen van het attribuut disabled is het veld ontoegankelijk gemaakt en kan de tekst niet worden gewijzigd. aria-disabled="true" betekent hetzelfde, maar dan voor schermlezers. Meer over aria-disabled staat bij WAI-ARIA-codes.

<script src="106-js/tekst-106.js"></script>

Onderaan de html staat een link naar een JavaScript. Deze link staat helemaal onderaan, omdat het script een aantal html-elementen nodig heeft. Die moeten eerst door de browser worden aangemaakt. Als het script te snel op zoek gaat naar deze nog niet bestaande elementen, ontstaat een acute identiteitscrisis die eindigt met een gruwelijk technische foutmelding. Meestal zie je die foutmelding tegenwoordig niet meer, maar in dat geval sterft het script in stilte een vreselijke dood. Oftewel: het werkt niet.

Een tweede reden om dit helemaal onderaan te zetten: als een browser een script tegenkomt, wordt alles stopgezet tot het script is uitgevoerd. Soms is dat nodig, maar in dit geval niet. Door het script helemaal onderaan neer te zetten, voorkom je een overbodige vertraging bij het laden en weergeven van de pagina.

CSS

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

Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.

Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.

Als je dit lastig vindt, kun je bovenaan de pagina de hele handel downloaden. In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.

Technisch gezien is er geen enkel bezwaar om de css in de stylesheet allemaal achter elkaar op één regel te zetten:

div#header-buiten {position: absolute; right: 16px; width: 100%; height: 120px; background: yellow;} div p {margin-left 16px; height: 120px; text-align: center;}

Maar als je dat doet, garandeer ik je hele grote problemen, omdat het volstrekt onoverzichtelijk is. Beter is het om de css netjes in te laten springen:

              div#header-buiten {
            position: absolute;
            right: 16px;
            width: 100%;
            height: 120px;
            background: yellow;
        }

        div p {
            margin-left: 16px;
            height: 120px;
            text-align: center;
        }

Hiernaast is het heel belangrijk voldoende commentaar (uitleg) in de stylesheet te schrijven. Op dit moment weet je waarschijnlijk (hopelijk...), waarom je iets doet. Maar over vijf jaar kan dat volstrekt onduidelijk zijn. Op deze site vind je nauwelijks commentaar in de stylesheets, maar dat heeft een simpele reden: deze uitleg is in feite één groot commentaar.

Op internet zelf is het goed, als de stylesheet juist zo klein mogelijk is. Dus voor het uploaden kun je normaal genomen het beste het commentaar weer verwijderen. Veel mensen halen zelfs alles wat overbodig is weg, voordat ze de stylesheet uploaden. Inspringingen bijvoorbeeld zijn voor mensen handig, een computer heeft ze niet nodig.

Je hebt dan eigenlijk twee stylesheets. De uitgebreide versie waarin je dingen uitprobeert, verandert, enz., 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. Als je op internet zoekt naar 'css' en 'compress' of 'comprimeren', vind je tal van sites, waar je dat automatisch kunt laten doen.

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

/* tekst-106-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, geef ik de kleur toch op. Hierboven heb ik een achtergrondkleur opgegeven. Sommige mensen hebben zelf de kleur en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als ik nu de achtergrondkleur verander, maar niet de voorgrondkleur, loop ik het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.

Door beide op te geven, weet ik 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;

Lettersoort. Als er geen Arial is, wordt gezocht naar Helvetica. Als dat er ook niet is in ieder geval 'n lettersoort zonder schreef (dwarsstreepjes).

margin: 0; padding: 0;

Verschillende browsers hebben verschillende standaard-instellingen hiervoor. Door ze gewoon op 0 te zetten, zijn ze overal hetzelfde.

main

Een van de nieuwe html5-elementen. Het geeft het begin van de belangrijkste inhoud op de pagina aan, zodat schermlezers en dergelijke er snel naartoe kunnen springen.

Op deze pagina staat alleen een formulier, dus eigenlijk is <main> hier niet echt nodig. Maar het is een goede gewoonte het toch te gebruiken. Gebruikers van een schermlezer weten van tevoren niet, hoeveel of hoe weinig er op een pagina staat.

display: block;

<main> is een blok-element. Maar Internet Explorer 9, 10 en 11 kennen dit element niet. En een onbekend element wordt standaard gezien als een inline-element. Dit corrigeert dat voor Internet Explorer 9, 10 en 11.

padding-top: 10px;

Kleine afstand tussen formulier en bovenkant van het browservenster.

form

Alle formulieren. Dat is er hier maar een.

background: white;

Witte achtergrond.

color: black;

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

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

Door beide op te geven, weet ik 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.

Ik heb dit 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.

box-sizing: border-box;

Hieronder worden een marge, border en padding opgegeven bij het formulier. Normaal genomen worden die bij de breedte opgeteld.

Hieronder wordt ook een breedte van 500 px voor het formulier opgegeven. En een maximumbreedte van 100%, voor browservensters die smaller dan 500 px zijn. In vensters smaller dan 500 px is het venster dus al voor de volle breedte gevuld.

Als hier nog marge, border en padding bij komen, wordt het formulier breder dan 100% van het venster, waardoor een deel buiten het venster komt te staan. Met deze regel worden marge, border en padding binnen de breedte gezet, zodat het formulier nooit breder wordt dan 100% van het venster.

width: 500px;

Breedte.

max-width: 100%;

Een breedte in procenten wordt altijd genomen ten opzichte van de ouder van het element. Dat is hier <main>. Bij <main> is geen breedte opgegeven, dus ook <main> krijgt de breedte van z'n ouder. Dat is <body>. Het wordt eentonig: ook bij <body> is geen breedte opgegeven. Op naar de ouder van <body>. Dat is <html>. En ook daar is geen breedte opgegeven.

In dat geval krijgt <html> de breedte van het venster van de browser. En daarmee ook <body>, <main> en uiteindelijke <form>. De maximumbreedte van 100% van <form> geldt dus ten opzichte van het venster van de browser: <form> wordt nooit breder dan het venster en is dus altijd volledig zichtbaar. In een venster dat smaller is dan 500 px, wordt <form> ook smaller.

Omdat de belangrijkste breedtematen van de onderdelen van het formulier ook in procenten zijn opgegeven, blijven ook de onderdelen van het formulier binnen het browservenster passen en blijven de onderlinge verhoudingen van de onderdelen redelijk intact.

font-size: 0.9em;

Iets kleinere letter.

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

margin: 0 auto;

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

Boven en onder geen marge. Links en rechts auto, wat hier hetzelfde betekent als evenveel. Het formulier staat dus altijd horizontaal gecentreerd, ongeacht de breedte van het browservenster.

Deze manier van horizontaal centreren van een blok-element werkt alleen, als het te centreren element een breedte heeft.

border: black solid 1px;

Zwart randje.

padding: 5px 5px 10px;

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

Kleine afstand tussen de buitenkant van het formulier en de erin zittende onderdelen.

fieldset

Alle <fieldset>'s. Een <fieldset> is een makkelijke manier om een aantal bij elkaar horende onderdelen van een formulier te groeperen. De <fieldset>'s in dit voorbeeld zijn makkelijk te herkennen, omdat ze een blauwe achtergrondkleur hebben.

background: #d0f0ef;

Achtergrondkleurtje.

color: black;

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

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

Door beide op te geven, weet ik 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.

Ik heb dit 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.

margin-bottom: 8px;

Kleine marge aan de onderkant. Hierdoor ontstaat er wat ruimte tussen de verschillende <fieldset>'s met de daarin zittende bij elkaar horende onderdelen.

padding-left: 10px;

Wat ruimte tussen de linkerkant van de <fieldset> en wat erin staat.

border-radius: 5px;

Ronde hoekjes.

Internet Explorer 9 kent dit niet, dus daar blijven de hoekjes gewoon recht.

legend

Alle <legend>'s. Aan elke <fieldset> met bij elkaar horende onderdelen is met behulp van <legend> een kopje gegeven.

font-weight: bold;

Vette letter.

margin-left: -2px;

Iets naar links zetten, zodat het kopje links wordt uitgelijnd met de andere onderdelen van het formulier.

ol

Alle <ol>'s. Dat zijn er hier twee: een voor het bezorgadres en een voor het rekening-adres.

Door de onderdelen van de adressen elk in een eigen lijst-item te zetten, zijn ze makkelijker op te maken.

list-style-type: none;

De volgnummers en dergelijke van een <ol> zijn hier niet welkom.

margin: 0; padding: 0;

De standaardwaarden hiervan zijn bij verschillende browsers iets verschillend. Door ze beide op 0 te zetten, is dat opgelost.

li

Alle lijst-items. De onderdelen van het bezorg- en rekening-adres staan elk in een <li>.

padding: 4px 0;

Omdat voor onder en links geen waarde is ingevuld, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 4px 0 4px 0 in de volgorde boven – rechts – onder – links. Dit geeft wat ruimte tussen de verschillende <li>'s.

label

Alle <label>'s.

display: inline-block; Zonder breedte kunnen de invoervelden niet netjes worden uitgelijnd

Een <label> is een inline-element. Dat is hartstikke mooi, ik heb ze onder m'n beste vrienden, maar nu even niet. Althans: gedeeltelijk niet.

Een inline-element komt, anders dan een blok-element, niet op een nieuwe regel te staan. Dat is prima, want nu blijft de tekst in de <label>'s op dezelfde regel staan als de bijbehorende <input>.

Maar aan een inline-element kun je geen breedte geven, zoals hieronder gebeurt. En zonder breedte ziet het eruit zoals op de afbeelding: een ongeregeld zootje, waarbij de breedte van de <label> afhankelijk is van de toevallige lengte van het erin staande woord. Hierdoor staan ook de <input>'s (de witte vakken) schots en scheen onder elkaar.

Een inline-block verenigt het beste uit beide werelden: het komt niet op een nieuwe regel te staan, maar je kunt er wel een breedte aan geven.

width: 25%;

Breedte 25%. Nu worden alle <label>'s netjes even breed, waardoor de erachter staande <input>'s ook netjes links staan uitgelijnd.

Een breedte wordt altijd genomen ten opzichte van de ouder van het element. Dat is hier <fieldset>. Omdat <fieldset> geen breedte heeft gekregen, wordt die ook weer even breed als z'n ouder. Dat is hier <form>, dat bij form een breedte van 500 px en een maximumbreedte van 100% heeft gekregen. Daardoor wordt het formulier nooit breder dan het venster van de browser.

In vensters van 500 px of meer breed is de breedte van de <label>'s 25% van 500 px, oftewel 125 px. In smallere vensters wordt <form> smaller, vanwege de maximumbreedte van 100%. De <label>'s zijn 25% van de breedte van <form>, dus in vensters smaller dan 500 px worden de <label>'s minder dan 125 px breed. Maar ze blijven altijd breed genoeg voor de erin staande woorden.

Voor sommige <label>'s wordt verderop in de css de breedte aangepast.

input

Alle <input>'s.

Er zijn verschillende types <input> in gebruik: 'radio', 'checkbox' en 'text'. (Het type 'text' is niet vermeld in de html, omdat dit het standaardtype van <input> is.) Voor sommige <input>'s worden verderop bepaalde eigenschappen apart aangepast.

width: 70%;

70% breed. Dit is alleen van belang voor de <input>'s bij de adressen. Dat zijn de <input>'s met het type 'text'. De breedte van de andere <input>'s wordt later aangepast, want een radioknop die 70% van de breedte van het formulier beslaat, is 'n pietsie overdreven.

Een breedte wordt altijd genomen ten opzichte van de ouder van het element. Dat is hier <fieldset>. Omdat <fieldset> geen breedte heeft gekregen, wordt die ook weer even breed als z'n ouder. Dat is hier <form>, dat bij form een breedte van 500 px en een maximumbreedte van 100% heeft gekregen. Daardoor wordt het formulier nooit breder dan het venster van de browser.

In vensters van 500 px of meer breed is de breedte van de <input>'s 70% van 500 px, oftewel 350 px. In smallere vensters wordt <form> smaller, vanwege de maximumbreedte van 100%. De <input>'s zijn 70% van de breedte van <form>, dus in vensters smaller dan 500 px worden de <input>'s minder dan 350 px breed. Dat is geen probleem, want als bijvoorbeeld de straatnaam er niet in past, schuift de tekst gewoon op. Maar ook in smallere vensters is 70% nog steeds redelijk veel ruimte voor adres en dergelijke.

Hierboven bij <label> hebben de <label>'s een breedte van 25% gekregen. Met de hier aan de bijbehorende <input> opgegeven breedte van 70%, vullen ze samen 95% van de breedte van het formulier.

margin: 0;

Verschillende browser geven een verschillende standaardmarge aan een <input>. Door de marge gewoon weg te halen, is het overal hetzelfde.

.kiezen label

Voor deze elementen geldt ook de bij label opgegeven css, voor zover die hier niet wordt gewijzigd.

De <label>'s binnen de elementen met class="kiezen". Er zijn twee <fieldset>'s met class="kiezen": de <fieldset>'s waarbinnen de vragen over het rekening-adres en de leeftijd staan. Binnen elk van deze <fieldset>'s staan twee <label>'s, eentje met 'Ja' en eentje met 'Nee'.

width: 38%;

Bij label is aan alle <label>'s een breedte van 25% gegeven. Door deze <label>'s breder te maken, komen de bijbehorende radioknoppen boven de keuzevakjes met dranken te staan. Zo uitgelijnd ziet het er netter uit.

Een breedte wordt altijd genomen ten opzichte van de ouder van het element. Dat is hier fieldset.kiezen. Omdat fieldset.kiezen geen breedte heeft gekregen, wordt die ook weer even breed als z'n ouder. Dat is hier <form>, dat bij form een breedte van 500 px en een maximumbreedte van 100% heeft gekregen. Daardoor wordt het formulier nooit breder dan het venster van de browser.

In vensters van 500 px of meer breed is de breedte van deze <label>'s 38% van 500 px, oftewel 190 px. In smallere vensters wordt <form> smaller, vanwege de maximumbreedte van 100%. De <label>'s zijn 38% van de breedte van <form>, dus in vensters smaller dan 500 px worden de <label>'s minder dan 190 px breed. Maar altijd ruim breed genoeg voor de erin zittende woorden 'Ja' en 'Nee'.

.kiezen input, #drank input

Voor deze elementen geldt ook de eerder bij input opgegeven css, voor zover die hier niet wordt gewijzigd.

De <input>'s binnen elementen met class="kiezen", en de <input>'s binnen het element met id="drank".

Er zijn twee <fieldset>'s met class="kiezen": de <fieldset>'s met de vragen over rekening-adres en leeftijd. De hierbinnen zittende <input>'s zijn de radioknoppen voor 'Ja' en 'Nee' bij deze vragen.

Het element met id="drank" is de <fieldset> waarbinnen de dranken met bijbehorende <input>'s in de vorm van keuzevakjes zitten.

width: auto;

Bij input hebben alle <input>'s een breedte van 70% gekregen. Dat is 70% van de breedte van het formulier. Dat is een beetje al te enthousiast voor een simpele radioknop of keuzevlakje. Hiermee krijgen deze <input>'s weer de breedte, die ze van zichzelf hebben.

vertical-align: -2px;

Sommige browsers zetten deze knoppen wat hoog neer. Met deze kleine correctie staan ze wat meer op gelijke hoogte met de bijbehorende tekst.

#drank label

Voor deze elementen geldt ook de eerder bij label opgegeven css, voor zover die hier niet wordt gewijzigd.

De <label>'s binnen het element met id="drank". De <label>'s waarin de namen van de dranken staan.

width: 38%;

Bij label hebben alle <label>'s een breedte van 25% gekregen. Dat is prima voor de <label>'s bij de adressen, omdat daarachter een breed tekstveld komt te staan. Deze <label>'s worden slechts vergezeld door een bescheiden keuzevakje.

Met deze breedte passen er makkelijk twee kolommen dranknamen met bijbehorende <input>'s naast elkaar.

Een breedte wordt altijd genomen ten opzichte van de ouder van het element. Dat is hier <fieldset>. Omdat <fieldset> geen breedte heeft gekregen, wordt die ook weer even breed als z'n ouder. Dat is hier <form>, dat bij form een breedte van 500 px en een maximumbreedte van 100% heeft gekregen. Daardoor wordt het formulier nooit breder dan het venster van de browser.

In vensters van 500 px of meer breed is de breedte van deze <label>'s 38% van 500 px, oftewel 190 px. In smallere vensters wordt <form> smaller, vanwege de maximumbreedte van 100%. De <label>'s zijn 38% van de breedte van <form>, dus in vensters smaller dan 500 px worden de <label>'s minder dan 190 px breed. Maar altijd ruim breed genoeg voor de erin zittende namen.

margin: 5px 0;

Omdat voor onder en links geen waarde is opgegeven, krijgen die automatisch dezelfde waarde als boven en rechts. Hier staat dus eigenlijk 5px 0 5px 0 in de volgorde boven – rechts – onder – links. Boven en onder een kleine marge, links en rechts geen. Dit geeft wat ruimte tussen de namen van de dranken en de bijbehorende keuzevakjes. Dat is vooral van belang op touchscreens: een muis is een muis, maar het zou kunnen dat een dokwerker iets bredere vingers heeft dan de priegelvingertjes van Marietje van drie.

(Hmmm, als Marietje van drie al een formulier aan het invullen is... Dat geeft toch te denken. Heeft dat kind geen interessantere dingen te doen op die leeftijd?)

border-radius: 3px; Dranken die niet kunnen worden gekozen, krijgen een rode achtergrond

Rondje hoekjes. De naam 'border-radius' is wat ongelukkig gekozen, want het gaat hier om ronde hoekjes bij de achtergrond. Er ís niet eens een border.

Normaal genomen is geen achtergrond aanwezig bij deze <label>'s. Maar als is aangegeven dat iemand nog geen achttien is, dan krijgt een aantal dranken een rode achtergrond. En dan zie je de ronde hoekjes wel.

Op bovenstaande afbeelding kunnen de dranken 'Arseendrab' en 'Fiedelvitriool' niet worden gekozen, omdat die alleen voor boven de achttien zijn.

(Volgens ingewijden wordt op de wekelijkse ministerraad ruim fiedelvitriool geschonken, en waar dat toe leidt is helaas duidelijk waar te nemen bij bepaalde leden van de regering, zoals minister Plasterk, winnaar van de Big Brother Awards 2015 van Bits of Freedom.)

padding: 0 3px;

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

Boven en onder geen padding. Links en rechts een kleine padding, zodat er wat ruimte komt tussen de teksten in de <label> en het bijbehorend keuzevakje.

p

Alle <p>'s. Dat is er hier maar eentje, vlak boven de <textarea> onderaan.

Normaal genomen zul je niet zo snel álle <p>'s zo selecteren, omdat er vaak heel veel <p>'s op een pagina aanwezig zullen zijn. Maar hier kan het op deze simpele manier, omdat er maar eentje is.

margin: 0;

Standaard heeft een<p> een marge aan boven- en onderkant. Die is hier niet welkom.

padding-left: 6px;

Kleine ruimte links. Hiermee wordt de tekst netjes rechts uitgelijnd met de tekst in de <textarea> eronder.

#label-klachten

Voor dit element geldt ook de eerder bij label opgegeven css.

Het element met id="label-klachten". Dit is een <label> speciaal voor schermlezers.

Binnen het onder dit label staande tekstveld is met behulp van het placeholder-attribuut een tekst in de <textarea> gezet. Die tekst kan niet worden gewijzigd, omdat het tekstveld is uitgeschakeld met behulp van het attribuut disabled.

TalkBack en VoiceOver lezen de tekst uit de placeholder voor, maar dit is eigenlijk niet de bedoeling. WebbIE, Lynx en NVDA negeren deze tekst, zoals het hoort.

Alle schermlezers kondigen een tekstveld aan, waarin geen tekst kan worden ingevoerd. Als de tekst uit de placeholder niet wordt voorgelezen, is de reden van dit tekstveld een raadsel. Er wordt dan alleen een tekstveld genoemd, waarin je niets kunt invullen. Daarom wordt voor het tekstveld een <label> geplaatst met dezelfde tekst als in de placeholder. Dit wordt door elke schermlezer voorgelezen, zodat ook gebruikers van een schermlezer horen, waarom er geen reden is voor een klacht.

position: absolute; left: -20000px;

De <label> links buiten het scherm parkeren. Nu verstoort de <label> de lay-out niet, maar schermlezers lezen hem gewoon voor. Verbergen met display: none; of visibility: hidden; is geen goed idee, want dan wordt de <label> niet voorgelezen door een schermlezer.

Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf is gepositioneerd. Die is hier niet. In dat geval wordt gepositioneerd ten opzichte van het venster van de browser. Precies de bedoeling: door de <label> zover links buiten het scherm te parkeren, verstoord het de lay-out op het scherm niet.

textarea

Alle <textarea>'s. Dat is er hier maar eentje: helemaal onderaan het formulier.

box-sizing: border-box;

Hieronder worden een border en een padding opgegeven bij de <textarea>. Normaal genomen worden die bij de breedte opgeteld.

Hieronder wordt ook een breedte van 100% opgegeven: even breed als de ouder van <textarea>. Dat is hier <form>. In browservensters smaller dan 500 px vult <form> de volle breedte van het venster. Dat geldt dus ook voor <textarea>, die even breed wordt als <form>.

Als hier nog border en padding bij komen, wordt de <textarea> breder dan 100% van het venster, waardoor een deel buiten het venster komt te staan. Met deze regel worden border en padding binnen de breedte gezet, zodat <textarea> nooit breder wordt dan 100% van het venster.

width: 100%;

Een breedte in procenten wordt altijd genomen ten opzichte van de ouder van het element. Dat is hier <form>, dat bij form een breedte van 500 px heeft gekregen, maar nooit breder dan het venster van de browser.

height: 5em;

Hoogte. De eenheid maakt hier weinig uit, want het tekstvak kan toch niet worden bewerkt.

overflow: hidden;

Om redenen die alleen Microsoft waarschijnlijk kent, zetten Internet Explorer 9, 10 en 11 (niet op Windows Phone) een verticale scrollbalk naast het tekstvak. Dat is nergens voor nodig en hiermee wordt deze snode aanslag op de esthetiek verijdeld: de scrollbalk wordt hiermee verwijderd.

border: black solid 1px;

Zwart randje.

border-radius: 5px;

Ronde hoekjes.

padding: 5px;

Kleine afstand tussen rand van en tekst in de <textarea>.

textarea:-ms-input-placeholder {color: black;}

textarea::-ms-input-placeholder {color: black;} textarea::-webkit-input-placeholder {color: black;} textarea::-moz-placeholder {color: black; opacity: 1;} textarea::placeholder {color: black; opacity: 1;}

Dit is een gloednieuwe selector, vandaar deze hele verzameling. Feitelijk staat er vijf keer bijna hetzelfde: textarea::placeholder {color: black;}. Waarom dat zo is, en waarom er zelfs vijf aparte regels staan, staat verder beschreven bij De voorvoegsels -moz-, -ms- en -webkit-. Iets hieronder staat, waarom in de laatste twee regels ook opacity staat.

::placeholder is een zogenaamd pseudo-element. Het is geen echt element, maar kan wel min of meer op dezelfde manier worden aangestuurd met css.

textarea::placeholder wil zeggen: alle <textarea>'s met het attribuut placeholder. Dat is er hier maar eentje: het tekstveld onderaan het formulier.

De volledige html van de <textarea>:

<textarea name="klachten" id="klachten" placeholder="Aangezien onze spullen gewoon goed zijn, zijn klachten overbodig, onnodig en onzinnig. Lekker puh!" disabled aria-disabled="true"></textarea>

Het gaat hier om het stukje placeholder="Aangezien ... t/m ... puh!". De hierin staande tekst is zichtbaar in het tekstvak, maar verdwijnt zodra er iets in het tekstvak wordt getypt. (In dit geval is het tekstvak met het attribuut disabled uitgeschakeld, maar dat maakt voor de rest van het verhaal niet uit.)

Deze tekst wordt standaard in de meeste browsers grijs weergegeven. En omdat het tekstveld is uitgeschakeld, is het in sommige browsers ook nog iets vager dan normaal. Door de kleur in zwart te veranderen, wordt het een stuk beter leesbaar.

Als enige browser maakt Firefox de kleur onduidelijk met behulp van opacity: 0.4;. Daarom is bij de regel voor Firefox (die met -moz-placeholder) ook opacity: 1; gebruikt. Omdat onduidelijk is hoe het uiteindelijk precies gaat worden, is ook in de laatste regel – die zonder voorvoegsels – opacity toegevoegd. Als dit uiteindelijk onnodig blijkt te zijn, maakt dat niets uit, want opacity: 1; is de standaardwaarde.

input:disabled, input:disabled + label

De eerste selector, die voor de komma: alle <input>'s met het attribuut disabled. Bij opening van de pagina zijn dit de <input>'s bij het rekening-adres en de <input>'s bij sommige dranken.

De tweede selector, die achter de komma: de <label>'s die in de html gelijk volgen op een <input> die het attribuut disabled heeft. Dit zijn de <label>'s die bij dranken die zijn uitgeschakeld horen.

Deze selectors werken alleen, als het element het attribuut disabled in de html heeft staan.

Afhankelijk van de antwoorden op de twee vragen over rekening-adres en leeftijd wordt disabled met behulp van JavaScript toegevoegd of verwijderd, waarover meer is te vinden bij JavaScript hier iets onder. Als disabled is toegevoegd of verwijderd met behulp van JavaScript, is dat niet te zien, als je gewoon de html bekijkt. Ze zijn alleen zichtbaar in de gegenereerde code. Als je de gewone html bekijkt, zie je alleen wat je zelf hebt ingetypt.

disabled heeft alleen nut bij elementen die je uit kunt schakelen. Dat zijn <button>, <input>, <optgroup>, <option>, <select>, <textarea> en <fieldset>. Als het wordt toegepast bij een <fieldset>, geldt het voor alle nakomelingen van die <fieldset>.

De selector :enabled bestaat ook: het is de tegenhanger van :disabled. Alleen zal deze niet zo snel worden gebruikt, omdat de genoemde elementen standaard enabled zijn, zodra disabled ontbreekt. Als je aan de css toe zou voegen :enabled {background: yellow;}, dan wordt de achtergrond van alle genoemde elementen onmiddellijk geel, behalve van de elementen waar disabled aanwezig is. Zonder dat je ergens in de html enabled of iets anders hoeft toe te voegen.

background: lightpink;

Achtergrond lichtrood kleuren.

color: #555;

De tekst is normaal genomen zwart. Hier wordt die veranderd in donkergrijs. Deze kleurverandering heeft alleen effect op de <label>'s uit de selector, want alleen die bevatten tekst.

cursor: not-allowed;

Cursor veranderen in het symbool voor 'verboden'. Deze 'verboden'-cursor ziet er in iedere browser anders uit.

Op veel touchscreens heeft dit uiteraard geen effect, omdat op veel touchscreens een cursor ontbreekt.

JavaScript

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

Het hier gebruikte JavaScript kan 'n stuk korter. Zo wordt bijvoorbeeld de ternary operator niet gebruikt. Ook zouden schakelAdres() en schakelLeeftijd() waarschijnlijk prima gecombineerd kunnen worden in één functie. Maar dat maakt het allemaal veel ingewikkelder, dus dat heb ik niet gedaan. Om dezelfde redenen ga ik hier ook niet in op het belang van commentaar, comprimeren, en dergelijke.

Als je bovenstaande begrijpt, dan is dit voorbeeld waarschijnlijk niet voor jou bedoeld. En als je het niet begrijpt, dan hoef je je er niets van aan te trekken. In dat geval is dit voorbeeld wel, maar bovenstaande alinea niet voor jou bedoeld.

(Dit was les 1 in de spoedcursus: Hoe Krijg Ik Altijd Gelijk?)

De uitleg hieronder is bepaald geen cursus JavaScript. Het zou voldoende moeten zijn om je enigszins op weg te helpen met het attribuut disabled, veel meer is het niet. Als je zelf het script gaat aanpassen, heb je daar waarschijnlijk nog wel hulp bij nodig. Die kun je op tal van forums vinden, waaronder – in beperkte mate, want deze site is vooral op css gericht – het forum op deze site.

Om het script voor mensen leesbaar te houden, wordt gebruikt gemaakt van nieuwe regels, inspringen, en dergelijke. Voor de computer is dat niet nodig. Voordat een script naar de server wordt geüpload, wordt het vaak zo klein mogelijk gemaakt. Als je op internet zoekt naar 'minify javascript', vind je tal van sites, waar dat automatisch kan worden gedaan.

Je hebt dan in feite twee scripts: eentje met de voor mensen makkelijker vorm, waarin je wijzigingen kunt aanbrengen, en eentje in een voor mensen onleesbare vorm, die daadwerkelijk wordt gebruikt.

Op deze site zijn veel scripts niet geminificeerd, omdat ik ze makkelijk leesbaar wil houden voor mensen die de code willen bekijken.

Dit JavaScript valt als het ware in twee delen uiteen. Het eerste deel bevat de bovenste vier regels, die elk beginnen met document.getElementById, en de daaronder staande vier regels, waarvan de eerste begint met var en de laatste alleen bestaat uit }.

Alles daaronder begint met function en hoort bij het twee deel. Het eerste deel, de bovenste acht regels, wordt automatisch uitgevoerd. Het tweede deel, de drie stukjes die elk beginnen met function(, wordt pas uitgevoerd als daar een reden voor is. Die reden is in dit geval het veranderen van het antwoord op de vraag 'Moet de rekening ook naar dit adres?' of de vraag 'Ben je achttien jaar of ouder?', of van het uit- of aanvinken van een van de keuzevakjes bij 'n drank.

Bij het veranderen van één van die antwoorden moeten delen van het formulier worden in- of uitgeschakeld. Voor dat in- en uitschakelen zorgt dit script.

/* tekst-106.js */

Om vergissingen te voorkomen is het een goede gewoonte bovenaan het script even de naam neer te zetten. Voor je het weet, zit je anders in het verkeerde bestand te werken.

document.getElementById("zelfde-adres").addEventListener("change", schakelAdres);

document.getElementById("ander-adres").addEventListener("change", schakelAdres); document.getElementById("is-achttien").addEventListener("change", schakelLeeftijd); document.getElementById("geen-achttien") .addEventListener("change", schakelLeeftijd);

De eerste vier regels van het script. Deze lijken nogal op elkaar, daarom worden ze samen behandeld.

Deze vier regels met code zijn te lang om op één regel te passen. Het tweede deel van de regel springt in, maar hoort eigenlijk gewoon achter het eerste deel te staan. Voor de computer maakt dit verder niets uit. Voor mensen is dat inspringen wel belangrijk, want anders zie je niet wat bij elkaar hoort.

document: dit is gewoon 'n soort wegwijzer, zodat de browser weet in welke 'afdeling' hij het erachter staande kan vinden.

getElementById: dit is wat uit de 'afdeling' document gebruikt moet worden: de functie getElementById(). Een functie is gewoon een naam voor een stukje bij elkaar horende code. Met behulp van de functie getElementById() kun je op de pagina zoeken naar een element met een bepaalde id.

Tussen de haakjes staat, naar welke id gezocht moet worden. De id staat tussen aanhalingstekens, zodat het script weet dat het hier om een letterlijke naam gaat. Bij elk van de vier regels wordt naar een andere id gezocht:

zelfde-adres: de <input> die hoort bij de radioknop voor 'Ja' bij de vraag 'Moet de rekening ook naar dit adres?'.

ander-adres: de <input> die hoort bij de radioknop voor 'Nee' bij de vraag 'Moet de rekening ook naar dit adres?'.

is-achttien: de <input> die hoort bij de radioknop voor 'Ja' bij de vraag 'Ben je achttien jaar of ouder?'.

geen-achttien: de <input> die hoort bij de radioknop voor 'Nee' bij de vraag 'Ben je achttien jaar of ouder?'.

Zou je naar een andere id willen zoeken, dan is dit het stukje dat je moet vervangen door die andere id.

Als je document.getElementById("zelfde-adres") zou 'vertalen' naar css, staat daar #zelfde-adres, waarmee je de css voor het element met id="zelfde-adres" zou beginnen. Maar JavaScript is nou eenmaal een heel andere taal dan css, dus daarin gelden andere taalregels.

addEventListener: dit is weer bij alle vier de regels hetzelfde. Er wordt een zogenaamde 'eventlistener' gekoppeld aan het element met de id, waarnaar is gezocht. Een eventlistener luistert naar een gebeurtenis. Die gebeurtenis kan van alles zijn: het indrukken van een toets, klikken, scrollen, de video is afgespeeld, van alles. Tussen de haakjes van addEventListener() staat, naar welke soort gebeurtenis moet worden geluisterd, en wat er moet gebeuren als die gebeurtenis zich voordoet. Zeg maar 'n soort rampenplan: áls doodsmak, bel dán 112'.

change: ook bij alle vier hetzelfde. En ook weer tussen aanhalingstekens, zodat het script weet dat dit weer een letterlijke naam is. Dit is de naam van de gebeurtenis, waarnaar wordt geluisterd, waarop wordt gewacht: 'change'. Verandering, in het Nederlands.

En wanneer verandert een radioknop? Als die van aangevinkt naar uitgevinkt gaat, of omgekeerd. De hierachter staande functie wordt dus uitgevoerd, elke keer als een van deze vier radioknoppen wordt aan‑ of uitgevinkt.

schakelAdres en schakelLeeftijd: bij twee regels voor de radioknoppen voor het rekening-adres staat 'schakelAdres', bij de twee regels voor de radioknoppen voor de leeftijd staat schakelLeeftijd.

Deze twee namen staan niet tussen aanhalingstekens, omdat het hier niet om letterlijke namen of zo gaat. Ze verwijzen naar een 'functie', iets wat moet gebeuren. Die twee functies staan iets hieronder. De ene heet 'schakelAdres', de andere 'schakelLeeftijd'.

(Probeer op dit moment vooral niet de logica van wel of geen aanhalingstekens te begrijpen. Het makkelijkste is om dat soort dingen maar gewoon te accepteren.)

;: aan het eind van elke regel staat een puntkomma. Daarmee geef je aan, dat de regel is afgelopen. In een gewoon boek zou je hier een punt gebruiken, om aan te geven dat een nieuwe zin begint.

De hele handel nog eens samengevat: als een radioknop bij de vraag over het rekening-adres (#zelfde-adres en #ander-adres) wordt aan‑ of uitgevinkt, voer dan de functie 'schakelAdres' uit.

Als een radioknop bij de vraag over de leeftijd (#is-achttien en #geen-achttien) wordt aan‑ of uitgevinkt, voer dan de functie 'schakelLeeftijd' uit.

var dranken = document.querySelectorAll("#drank input");

for (var i = 0; i < dranken.length; i++) { dranken[i].addEventListener("change", stuurDrank); }

O jee, dit lijkt net echt programmeren! Als je nog nooit zoiets hebt gezien, doet het waarschijnlijk aan een door een dronken vertaler uit het Oegandees naar het Siberisch vertaald modern liefdesgedicht of zoiets denken. Maar als je het in stukjes hakt, wordt het mogelijk iets beter te volgen.

var dranken = document.querySelectorAll("#drank input");

De bovenste regel. Weer in stukjes hakken om het begrijpelijk te maken.

var dranken: var is een sleutelwoord. Je geeft ermee aan, dat het erop volgende woord de naam van een 'variabele' is. Een variabele is een soort portemonnee: er kan van alles in zitten, en de inhoud kan veranderen. Alleen is de inhoud van een variabele beter te sturen dan de inhoud van menig portemonnee.

De variabele heet hier 'dranken'. In 'dranken' wordt dus iets opgeborgen. Omdat de variabele een naam heeft ('dranken'), kan de rest van het script de variabele aanroepen bij deze naam. Net zoals je iemand die 'Piet' heet kunt aanroepen met 'Piet', ongeacht of Piet aardig, lang, kort of kaal is, ongeacht de 'inhoud' van Piet.

=: achter het isgelijkteken staat, wat er in de variabele 'dranken' opgeslagen gaat worden.

document: dit is gewoon 'n soort wegwijzer, zodat de browser weet in welke 'afdeling' hij het erachter staande kan vinden.

querySelectorAll: dit is wat uit de 'afdeling' document gebruikt moet worden: de functie querySelectorAll(). Een functie is gewoon een naam voor een stukje bij elkaar horende code. Met behulp van de functie querySelectorAll() kun je op de pagina zoeken naar bijvoorbeeld alle elementen met een bepaalde class.

Tussen de haakjes staat, waarnaar gezocht moet worden. Dat staat tussen aanhalingstekens, zodat het script weet dat het hier om een letterlijke tekst gaat: "#drank input".

#drank input: de elementen waarnaar wordt gezocht. Dit lijkt heel erg op een css-selector, en dat is geen toeval. Zoek naar alle <input>'s binnen het element met id="drank". Dit zijn de <input>'s die horen bij de dranken.

;: met de puntkomma wordt aangegeven, dat de regel hier eindigt.

Alles nog eens samengevat: zoek alle <input>'s binnen het element met id="drank"op, en stop die in de variabele met de naam 'dranken'. Als dat is gedaan, kunnen we gaan stoeien met de inhoud van 'dranken'. En omdat die inhoud feitelijk de <input>'s binnen #drank zijn, stoeien we in werkelijkheid niet met 'dranken', maar met de <input>'s binnen #drank. Als ik alles in 'dranken' bijvoorbeeld 100 px breed zou maken, zouden de <input>'s binnen #dranken op het scherm plotsklaps 100 px breed zijn.

Er is een verzameling <input>'s, die binnen de variabele 'dranken' zit. En daar moet iets mee gebeuren, want anders hadden we ze niet hoeven te vangen. De volgende regel zorgt ervoor dat er met elk van die <input>'s iets gaat gebeuren. Wát er gaat gebeuren, dat komt nog iets later. Hier wordt alleen bepaald dát er iets gaat gebeuren.

for (var i = 0; i < dranken.length; i++) { (...) regel code (...) }

Weer in stukjes hakken, om het te kunnen begrijpen.

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

Hier eerst het deel dat ervoor zorgt dat elke eerder gevonden <input> netjes aan de beurt komt.

(: met dit haakje opent het deel dat ervoor zorgt, dat elke <input> aan de beurt komt. Aan het eind van de regel staat de bijbehorende ), waardoor het script weet dat dit het einde van dit deel van de code is.

var i = 0;: met het sleutelwoord var geef je aan dat het erop volgende woord de naam van een 'variabele' is. Dat variabele heet hier 'i'. Dat is een heel korte naam. 'i' wordt gebruikt als een teller (waarover later meer), en bij dit soort tellers is het gebruikelijk ze de naam 'i' te geven. Dat soort gewoontes maakt het voor mensen een stuk makkelijker elkaars code te lezen en te begrijpen.

We hebben dus een variabele met de naam 'i'. Met = 0 wordt vervolgens aangegeven dat de inhoud van die variabele, de waarde, '0' is. En omdat het een variabele is, kan de waarde veranderen, variëren. Wat later in de regel ook gaat gebeuren: elke keer als er een <input> is afgehandeld, wordt 'i' met 1 verhoogd. Dat gebeurt in het laatste deel van de regel.

De ; geeft aan, dat dit stukje code, waarin de variabele 'i' wordt aangemaakt, hier eindigt.

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

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

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

Als i 1 is, betekent i++: i wordt 1 + 1 (heel goed, jij kunt rekenen, dat is '2').

Enz.

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

i < dranken.length;: het middelste deel. In 'dranken' zitten de eerder gevonden <input>'s. Met length kan het aantal gevonden <input>'s worden vastgesteld. Er zijn eerder veertien <input>'s gevonden, dus in 'dranken' zitten veertien <input>'s opgeborgen. De length ('lengte') van 'dranken' is dus 14.

In dit geval is dranken.length dus hetzelfde als het getal 14. Zouden er 38 <input>'s zijn gevonden, dan zou dranken.length hetzelfde zijn als het getal 38.

'i' bevat een getal. Aan het begin is dat getal 0, want dat is hierboven opgegeven.

Het teken < betekent: kleiner dan.

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

In gewone mensentaal staat hier:

zolang teller 'i' kleiner is dan het aantal <input>'s in 'dranken'.

Als niet meer aan deze voorwaarde wordt voldaan, als teller 'i' niet meer kleiner is dan het aantal <input>'s, stop dan met het uitvoeren van de code die tussen de {} staat.

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

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

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

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

Aan het begin heeft i de waarde 0. Na de eerste ronde heeft i de waarde 1. Na de tweede ronde heeft i de waarde 2. Enz. Na de veertiende ronde heeft i de waarde 14. Waarmee i niet meer kleiner is dan de lengte van 'dranken', het aantal daarin zittende <input>'s.

Omdat niet meer aan de voorwaarde i < dranken.length wordt voldaan, wordt gestopt met het behandelen van de <input>'s. En dat komt goed uit, want alle <input>'s zijn precies allemaal één keer aan de beurt gekomen. Niet meer, niet minder. Bij allemaal is de tussen de {} staande code één keer toegepast.

dranken[i].addEventListener("change", stuurDrank);

En dan nu eindelijk wát er met wat moet gebeuren met die veertien <input>'s. Aan het begin van deze regel staat, waarmee iets moet gebeuren. Daarachter staat, wat er moet gebeuren.

dranken[i]: in dranken zitten alle <input>'s. Veertien stuks in totaal. Als je iets met een van die <input>'s wilt doen, moet je die specifieke <input> eerst opzoeken. Dat kan met behulp van een volgnummer. De eerste <input> heeft volgnummer 0, de tweede volgnummer 1, enz. De laatste <input> heeft volgnummer 13.

Dit is voor mensen even wennen, want mensen beginnen met 1 te nummeren. Een computer begint met 0. Er zijn dus veertien <input>'s met de volgnummers 0 tot en met 13. Even wennen, maar na 'n tijdje is het echt simpeler dan de huisnummering van Amsterdam, om maar iets bij tijd en wijle volslagen onnavolgbaars te noemen.

Die volgnummers staan tussen twee teksthaken []. De eerste <input> kan gevonden worden met dranken[0], de tweede met dranken[1], enz. De veertiende en laatste kan worden gevonden met dranken[13].

Omdat hier bekend is dat er veertien <input>'s zijn, zou je je vingers naar de filistijnen kunnen typen door veertien keer hetzelfde in te typen, steeds beginnend met een ander volgnummer. Dat zou hier nog wel gaan, omdat het 'n heel kort regeltje is. Maar soms gaat het om duizenden regels code en geen veertien, maar veertienhonderd elementen. Of het aantal is onbekend. En als je één nieuwe <input> aan #dranken zou toevoegen in de html, zou je ook hier gelijk nieuwe code moeten intypen.

Dat kan gelukkig slimmer.

En hier komt de 'i' om de hoek kijken: de teller. Deze is bij 0 begonnen en wordt elke keer dat een <input> is behandeld met 1 verhoogd, zoals iets hierboven is beschreven. Oftewel: 'i' telt van 0 tot 13. En hé, als dat niet toevallig is: dat zijn ook de volgnummers van de <input>'s! Daar moet iets mee te fabrieken zijn.

En dat is zo. Daarom staat er geen dranken[0] of dranken[11], maar dranken[i]. Elke ronde wordt 'i' met 1 verhoogd. Bij de eerste ronde staat er in werkelijkheid geen dranken[i], maar dranken[0]: het 'adres' van de eerste <input>. Bij de tweede ronde staat er in werkelijkheid geen dranken[i], maar dranken[1]. Enz., tot dranken[13] voor de veertiende en laatste <input>.

En daarna houdt het op, want zodra 'i' niet meer kleiner is dan de lengte van 'dranken' (14, het aantal gevonden <input>'s), stopt de hele handel.

addEventListener: Er wordt een zogenaamde 'eventlistener' gekoppeld aan het element met de id, waarnaar is gezocht. Een eventlistener luistert naar een gebeurtenis. Die gebeurtenis kan van alles zijn: het indrukken van een toets, klikken, scrollen, de video is afgespeeld, van alles. Tussen de haakjes van addEventListener() staat, naar welke soort gebeurtenis moet worden geluisterd, en wat er moet gebeuren als die gebeurtenis zich voordoet.

Teller 'i' en dergelijke zorgen ervoor dat dit bij elk van de veertien in 'dranken' zittende <input>'s gebeurt.

change: Dit staat weer tussen aanhalingstekens, zodat het script weet dat dit weer iets letterlijks is. Dit is de gebeurtenis, waarnaar wordt geluisterd, waarop wordt gewacht: 'change'. Verandering, in het Nederlands.

En wanneer verandert een van deze veertien <input>'s, een van deze veertien keuzevakjes? Als een vinkje wordt geplaatst of weggehaald.

(De in 'dranken' gestopte veertien <input>'s zijn van type="checkbox". Dat soort dingen is opgeslagen in 'dranken', bij elke <input>. Van elke <input> is een ongelooflijke hoeveelheid gegevens in 'dranken' opgeslagen, zoals de id, de plaats op het scherm, of de <input> is aangevinkt of niet, noem maar op.)

stuurDrank: deze naam staat niet tussen aanhalingstekens, omdat het hier niet om letterlijke naam of zo gaat. 'stuurDrank' verwijst naar een 'functie', iets wat moet gebeuren. Die functie staat iets hieronder en heet 'stuurDrank'.

Dat alle veertien <input>'s dezelfde functie aangekoppeld krijgen, maakt niets uit. De browser houdt die functie toch automatisch keurig gescheiden voor elke <input>. Het vinkje van de ene <input> bijt het vinkje van de andere <input> niet.

Samengevat: stop alle veertien <input>'s (keuzevakjes) in fieldset#drank in de variabele 'dranken'. Als één van die <input>'s wordt aan‑ of uitgevinkt, voer dan de functie 'stuurDrank' uit.

Dit is het einde van het eerste deel van het script. Dit deel wordt altijd automatisch uitgevoerd, daar hoeft niets voor te gebeuren. De rest van het script wordt pas uitgevoerd, als een antwoord op de vraag 'Moet de rekening ook naar dit adres?' of 'Ben je achttien jaar of ouder?' wordt veranderd, of als een keuzevakje bij één van de veertien dranken wordt aan‑ of uitgevinkt. Bij verandering van één van die antwoorden of keuzevakjes, bij 'change'.

Wát er dan precies wordt uitgevoerd bij een verandering, bij 'change', ligt aan de naam van de functie die met behulp van 'addEventListener' aan de betreffende <input> is toegevoegd.

Als de antwoorden op die twee vragen en die veertien keuzevakjes nooit worden veranderd, zul je helemaal niets van dit script merken.

function schakelAdres() {

var zelfde = document.getElementById("zelfde-adres"), ander = document.getElementById("ander-adres"), rekening = document.querySelectorAll("#rekening-naar input");
for (var i = 0; i < rekening.length; i++) { if (zelfde.checked) { zelfde.setAttribute("aria-checked", "true"); ander.setAttribute("aria-checked", "false"); rekening[i].setAttribute("disabled", "true"); rekening[i].setAttribute("aria-disabled", "true"); } else { zelfde.setAttribute("aria-checked", "false"); ander.setAttribute("aria-checked", "true"); rekening[i].removeAttribute("disabled"); rekening[i].setAttribute("aria-disabled", "false"); } } }

Het bovenstaande stukje code heet een 'functie'. Het wordt pas uitgevoerd, als daar een reden voor is, als de functie wordt 'aangeroepen'.

Gelijk na het woord function volgt de naam van de functie. Die is hier 'schakelAdres'. Als je deze functie wilt uitvoeren, wilt aanroepen, moet je 'schakelAdres' roepen. Als je nu enthousiast 'schakelAdres' begint te brullen, heb je wel kans dat je huisgenoten of de buren zich aangeroepen voelen, maar de functie niet. Dat aanroepen van een functie gebeurt volgens heel specifieke regels.

In het eerste deel van dit script is de gebeurtenis 'change', verandering, gekoppeld aan de <input>'s, de radioknoppen, met 'Ja' en 'Nee' bij de vraag 'Moet de rekening ook naar dit adres?'. Dat is gebeurd bij document.getElementById("ander-adres").addEventListener("change", schakelAdres); en document.getElementById("zelfde-adres").addEventListener("change", schakelAdres);.

Bij een verandering van een van die radioknoppen, als er eentje wordt aan‑ of uitgevinkt, moet er iets gebeuren. Wát er moet gebeuren, is ook in het eerste deel van het script bepaald; het aanroepen van de functie 'schakelAdres'. En dat is deze functie!

Als het antwoord op de vraag 'Moet de rekening ook naar dit adres?', als een van de bijbehorende radioknoppen, wordt gewijzigd, wordt deze functie aangeroepen en dus uitgevoerd.

function schakelAdres() {

function: het sleutelwoord waarmee het begin van een functie wordt aangegeven.

schakelAdres: de naam van de functie. Als het beestje geen naam heeft, kun je het ook niet aanroepen en heb je er dus niets aan. (Dit klopt niet helemaal. JavaScript kent ook equivalenten van 'hé!', 'hé, jij daar!', 'hé, jij daar in die zwarte jas', en dergelijke, maar die worden hier niet gebruikt. En het is zo al ingewikkeld genoeg.)

(): tja, dat hoort nou eenmaal zo na de naam van een functie.. (Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen, wat de functie dan weer kan gebruiken. Maar dat gebeurt hier niet, dus dat slaan we lekker over.)

{: hiermee geef je aan dat de code van de functie, het deel dat moet worden uitgevoerd, nu echt gaat beginnen. Aan het eind staat de bijbehorende } . Die } staat eenzaam te wezen op een eigen regel, want dat is leesbaarder voor mensen.

var zelfde = document.getElementById("zelfde-adres"), ander = document.getElementById("ander-adres"), rekening = document.querySelectorAll("#rekening-naar input");

In dit deel van de functie worden een paar dingen voorbereid. Het doel van deze functie is het veranderen van dingen in de html, zodat het uiterlijk van de pagina wordt aangepast. Om dat te kunnen doen, moeten eerst de html-elementen worden opgezocht, waarbij dingen veranderd moeten worden. En als die gevonden zijn, moeten ze worden bewaard op een manier, waar het script iets mee kan. Dat gebeurt hier. Het écht uitvoerende deel van de functie, waarin de html daadwerkelijk wordt veranderd, volgt daarna.

Het is gebruikelijk dit soort voorbereidende zaken bovenin de functie te zetten.

Het derde deel van de regel, het deel dat eindigt met input");, is te lang om op één regel te passen, daarom staat het laatste stukje met een inspringing op een nieuwe regel. Maar in werkelijkheid is dat dus één lange regel.

Deze regel valt in drie delen uiteen, die worden gescheiden door een komma. Het eerste deel begint met var. Dit sleutelwoord var wordt automatisch ook voor het tweede en derde deel geplaatst, omdat deze delen volgen op een komma. Door die komma weet het script dat het hier om drie bij elkaar horende delen van één regel gaat.

Na het derde deel staat een puntkomma: dit is het echte einde van deze regel code.

Het is gebruikelijk zo'n tweede, derde, ... deel op een nieuwe regel te laten beginnen en iets in te laten springen. Zo zie je in één oogopslag dat het sleutelwoord var voor alle drie de delen geldt, dat hier drie variabelen worden aangemaakt.

var zelfde =: met het sleutelwoord var wordt aangegeven dat het erop volgende woord de naam van een 'variabele' is. Een variabele is een soort portemonnee: er kan van alles in zitten, en de inhoud kan veranderen.

Gelijk na var volgt de naam van de variabele. Dat is hier 'zelfde'. In 'zelfde' wordt dus iets opgeborgen. Omdat de variabele een naam heeft ('zelfde'), kan de rest van de functie de variabele aanroepen bij deze naam. Net zoals je iemand die 'Marie' heet kunt aanroepen met 'Marie', ongeacht of Marie aardig, lang, kort of kaal is, ongeacht de 'inhoud' van Marie.

Achter het isgelijkteken staat, wat er in de variabele 'zelfde' opgeslagen gaat worden.

document: dit is gewoon 'n soort wegwijzer, zodat de browser weet in welke 'afdeling' hij het erachter staande kan vinden.

getElementById: dit is wat uit de 'afdeling' document gebruikt moet worden: de functie getElementById(). Een functie is gewoon een naam voor een stukje bij elkaar horende code. Met behulp van de functie getElementById() kun je op de pagina zoeken naar een element met een bepaalde id.

Tussen de haakjes staat, naar welke id gezocht moet worden. De id staat tussen aanhalingstekens, zodat het script weet dat het hier om een letterlijke tekst gaat.

"zelfde-adres": in dit geval wordt gezocht naar de id 'zelfde-adres', de id die bij de 'Ja'-knop van de vraag 'Moet de rekening ook naar dit adres?' hoort.

Als de id is gevonden, wordt de bijbehorende <input> als het ware opgeborgen in de variabele 'zelfde'. Niet alleen de id, maar allerlei dingen van de <input> worden in 'zelfde' opgeborgen, zoals de positie op het scherm, de grootte, of de knop is aangevinkt of niet, enz.

Als je nu iets met 'zelfde' gaat doen, zoals hieronder gaat gebeuren, doe je in feite iets met de in 'zelfde' opgeborgen input#zelfde-adres.

ander = document.getElementById("ander-adres")

In dit tweede deel van de regel gebeurt precies hetzelfde als in het eerste deel. De uitleg hierboven voor het eerste deel geldt precies zo voor dit tweede deel. Het enige verschil is dat nu naar de id 'ander-adres' wordt gezocht, en dat het bijbehorende element input#ander-adres nu in de variabele 'ander' wordt opgeborgen.

rekening = document.querySelectorAll("#rekening-naar input")

Het derde deel van de regel is iets anders dan de eerste twee delen.

Er wordt weer een variabele gemaakt, net als bij de eerste twee delen. Die heet hier 'rekening'. Er wordt weer iets gebruikt uit de 'afdeling' document. Maar nu is dat de functie querySelectorAll(). Met het in de eerste twee delen gebruikte getElementById() kun je zoeken naar één bepaalde id. Met het hier gebruikte querySelectorAll() kun je naar van alles zoeken.

In dit geval wordt gezocht naar "#rekening-naar input". Dit lijkt erg op een css-selector, en het werkt ook min of meer hetzelfde. Er wordt gezocht naar alle <input>'s die binnen het element met id="rekening-naar" zitten.

fieldset#rekening-naar bevat het adres, waarnaar eventueel de rekening moet worden gestuurd. Daarbinnen zitten vier <input>'s: voor Naam, Adres, Stad en Postcode. Er worden hier dus vier <input>'s gevonden. Anders dan bij de hierboven beschreven variabelen 'zelfde' en 'ander', wordt hier dus niet één <input> gevonden, maar vier.

In de variabele 'rekening' worden vier <input>'s opgeslagen. Ook van elk van die vier <input>'s is een hele rits gegevens opgeslagen, zoals de id, de plaats op het scherm, de breedte, noem maar op.

Omdat in 'rekening' vier <input>'s zijn opgeslagen, kun je niet gewoon 'rekening' gebruiken als naam om 'n bepaalde <input> aan te spreken. Dat kan wel bij de eerder gemaakte variabelen 'zelfde' en 'ander', want daar zit maar één <input> in.

Bij 'rekening' wordt daarom met een volgnummer gewerkt. Helaas zijn computers dol op het getal '0', daarom krijgt de eerste <input> volgnummer '0'. De tweede <input> krijgt volgnummer '1', de derde volgnummer '2' en de vierde en laatste volgnummer '3'. Dat is even wennen voor mensen, maar het is niet anders.

Het volgnummer wordt tussen twee teksthaken [] gezet, achter de naam van de variabele: rekening[0] is in werkelijkheid de eerste <input> binnen 'rekening'.

rekening[1] is de tweede <input>, rekening[2] is de derde <input> en rekening[3] is de vierde en laatste <input>.

(Gelukkig hoef je deze echte volgnummers maar heel weinig te gebruiken, want het blijft voor mensen lastig dat 'n computer met 0 begint te tellen. Je vergist je daar heel snel mee.)

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

'zelfde' bevat de <input> die bij de 'Ja' hoort bij de vraag 'Moet de rekening ook naar dit adres?'.

'ander' bevat de <input> die bij de 'Nee' hoort bij de vraag 'Moet de rekening ook naar dit adres?'.

'rekening' bevat de vier <input>'s die bij Naam, Adres, Stad en Postcode van het rekening-adres horen.

Nu deze elementen zijn gevonden en opgeslagen, kunnen we ze gaan veranderen, als dat nodig is. Daarvoor zorgt de rest van deze functie.

for (var i = 0; i < rekening.length; i++) {(...) code (...)}

Weer in stukjes hakken om het te kunnen begrijpen.

for: doe iets met iets, zolang iets waar is. Wát er waarmee moet gebeuren, komt later. Dat staat tussen de {} aan het eind van de regel. (In de echte code staat de laatste } ook een stuk lager, achter wat er waarmee moet gebeuren.)

Hier eerst het deel dat ervoor zorgt dat elke eerder gevonden <input> aan de beurt komt.

(: met dit haakje opent het deel dat ervoor zorgt, dat elke <input> aan de beurt komt. Aan het eind van de regel staat de bijbehorende ), waardoor het script weet dat dit het einde van dit deel van de code is.

var i = 0;: met het sleutelwoord var geef je aan dat het erop volgende woord de naam van een 'variabele' is. Dat is hier 'i'. Dat is een heel korte naam. 'i' wordt gebruikt als een teller (waarover later meer), en bij dit soort tellers is het gebruikelijk ze de naam 'i' te geven. Dat soort gewoontes maakt het voor mensen een stuk makkelijker elkaars code te lezen en begrijpen.

We hebben dus een variabele met de naam 'i'. Met = 0 wordt vervolgens aangegeven dat de inhoud van die variabele, de waarde, '0' is. En omdat het een variabele is, kan de waarde veranderen. Wat later in de regel ook gaat gebeuren: elke keer als er een <input> is afgehandeld, wordt 'i' met 1 verhoogd. Dat gebeurt in het laatste deel van de regel:

De ; geeft aan dat dit stukje code, waarin de variabele 'i' wordt aangemaakt, hier eindigt.

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

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

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

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

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

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

i < rekening.length;: het middelste deel. In 'rekening' zitten de eerder gevonden <input>'s. Met length kan het aantal gevonden <input>'s worden vastgesteld. Er zijn eerder vier <input>'s gevonden en in 'rekening' opgeborgen. De length (lengte) van 'rekening' is dus 4.

In dit geval is rekening.length dus hetzelfde als het getal 4. Zouden er 38 <input>'s zijn gevonden, dan zou rekening.length hetzelfde zijn als het getal 38.

'i' bevat een getal. Aan het begin is dat getal 0, want dat is hierboven opgegeven.

Het teken < betekent: kleiner dan.

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

In gewone mensentaal staat hier: zolang teller 'i' kleiner is dan het aantal <input>'s in 'rekening'.

Als niet meer aan deze voorwaarde wordt voldaan, als teller 'i' niet meer kleiner is dan het aantal <input>'s, stop dan met het uitvoeren van de code die tussen de {} staat.

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

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

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

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

Aan het begin heeft i de waarde 0. Na de eerste ronde heeft i de waarde 1. Na de tweede ronde heeft i de waarde 2. Na de derde ronde heeft i de waarde 3. Na de vierde ronde heeft i de waarde 4. Waarmee i niet meer kleiner is dan de lengte van 'rekening', het aantal daarin zittende <input>'s.

Omdat niet meer aan de voorwaarde i < rekening.length wordt voldaan, wordt gestopt met het behandelen van de <input>'s. En dat komt goed uit, want alle <input>'s zijn precies allemaal één keer aan de beurt gekomen. Niet meer, niet minder. Bij allemaal is de tussen de {} staande code één keer toegepast.

Tot nu toe hebben we een aantal elementen gevonden en opgeborgen, en er is gezorgd dat elk van die elementen aan de beurt kan komen.

Er zijn twee mogelijke toestanden bij de beantwoording van de vraag 'Moet de rekening ook naar dit adres?'. 'Ja' is aangevinkt of 'Ja' is niet aangevinkt.

Als 'Ja' is aangevinkt, ontvinkt de browser automatisch de bijbehorende radioknop met 'Nee'. Als 'Nee' is aangevinkt, ontvinkt de browser automatisch de bijbehorende radioknop met 'Ja'. We kunnen dus volstaan met kijken of 'Ja' is aangevinkt of niet. De radioknop met 'Nee' wordt door de browser afgehandeld.

In de variabele 'zelfde' zat de <input> die bij 'Ja' hoort opgeslagen. Inclusief allerlei eigenschappen van die <input>, waaronder of de <input> is aangevinkt of niet. Dit is opgeslagen in checked. Dit opslaan in checked wordt automatisch door de browser gedaan.

Als de knop is aangevinkt, is checked 'true', waar. Als checked niet is aangevinkt, is checked 'false', onwaar.

Daar kun je op controleren en aan de hand daarvan bepaalde dingen doen of niet doen. Dat controleren gebeurt hier met behulp if():

if (zelfde.checked) {(...) code (...)}

Net als bij for staat het deel dat bij if hoort tussen twee haakjes. Dat is hier zelfde.checked. Dat is heel kort, maar soms is dit heel lang, en zonder haakjes zou de if niet weten waar het einde van de voorwaarde is.

De voorwaarde? De voorwaarde is hier dat zelfde.checked 'true' moet zijn. Dat 'true' laat je weg, alweer vanwege luiheid bij programmeurs, maar eigenlijk staat hier iets als (zelfde.checked === true). (Let even niet op het driedubbele isgelijkteken. Dat is een JavaScript-taalregel, die in dit voorbeeld verder niet belangrijk is.)

zelfde.checked is 'true', als input#zelfde, de radioknop met 'Ja', is aangevinkt. Als dat zo is, wordt de tussen de {} staande code uitgevoerd, net zoals bij for.

(Je zult dat niet gelijk oppikken, maar er zit meestal een ijzeren logica in de taalregels, de 'syntax', van programmeertalen. Veel meer dan in door mensen gesproken talen. Wat het trouwens wel weer veel lastiger maakt om, bijvoorbeeld, een romantische liefdesgedicht in JavaScript te schrijven.)

De andere mogelijkheid is dat 'Ja' niet is aangevinkt. Dan is zelfde.checked 'false', niet waar. In dat geval moeten er andere dingen worden gedaan, dan wanneer zelfde.checked 'true' is.

Dat geef je als volgt aan in JavaScript:

        if (zelfde.checked) {
      (...)
      code als zelfde.checked 'true' is
      (...)
} else {
      (...)
      code als zelfde.checked 'false' is
      (...)
}

Als zelfde.checked 'true' is, voer dan de code tussen if ('als') en else ('anders') uit. Begin en einde van die code wordt met { en } aangegeven.

Als zelfde.checked niet 'true' is, kan er maar één ander iets aan de hand zijn: het is 'false'. Anders dan bij bijvoorbeeld een teller, die veel waarden kan krijgen, zijn hier maar twee mogelijkheden. Dat komt overeen met de twee mogelijkheden van een radioknop: aangevinkt of niet. Een radioknop half aanvinken kan niet.

Als er maar twee mogelijkheden zijn, kun je volstaan met het gebruik van else, 'anders', voor de tweede mogelijkheid. Als zelfde.checked 'false' is, wordt de code achter else uitgevoerd. Ook daarvan wordt begin en eind weer aangegeven met { en }.

zelfde.setAttribute("aria-checked", "true");

De eerste regel van de code boven de else die moet worden uitgevoerd, als zelfde.checked 'true' is, als 'Ja' is aangevinkt bij de vraag 'Moet de rekening ook naar dit adres?'

zelfde.: wat achter zelfde staat, is hetgeen wat gedaan gaat worden met zelfde.

In de variabele 'zelfde' is hierboven input#zelfde-adres, de 'Ja'-knop, opgeborgen. Wat er achter zelfde staat, gaat dus feitelijk gedaan worden met input#zelfde-adres.

De punt is de scheiding tussen de variabele 'zelfde' (waarin input#zelfde-adres is opgeborgen, en datgene wat gedaan gaat worden met zelfde.

setAttribute(): een 'attribuut' is een toevoegsel bij een html-element, zoals width="100" of checked. Daar zijn er nogal wat van (nog los van eigengemaakte attributen). Met setAttribute() verander je de waarde bij een attribuut. Als het attribuut nog niet bestaat, wordt het gemaakt.

Tussen de haakjes staat voor de komma de naam van het attribuut, na de komma staat de waarde.

"aria-checked": de naam van het attribuut. Het staat tussen aanhalingsteken om aan te geven dat dit letterlijk zo in de html gezet moet worden. Tussen de naam van het attribuut en de daarop volgende waarde wordt in de html automatisch een isgelijkteken gezet.

"true": de waarde die het attribuut krijgt. Ook weer tussen aanhalingstekens, omdat dit een letterlijke waarde is.

;: hiermee wordt weer het eind van een regel aangegeven.

Alles samen: voeg aan input#zelfde-adres het attribuut aria-checked toe en geef dit de waarde 'true':

<input type="radio" name="rekening" id="zelfde-adres" value="ja" checked aria-checked="true">

Het vette deel hierboven is hetgeen door deze regel wordt toegevoegd aan de html.

Deze regel wordt alleen uitgevoerd, als de waarde van input#zelfde-adres, van de 'Ja'-knop bij de vraag over het adres, verandert. Want dit hele gedoe, deze hele functie, is bij document.getElementById("zelfde-adres").addEventListener("change", schakelAdres); met behulp van 'change' ('verander') aan input#zelfde-adres gekoppeld.

Bovendien wordt dit dan ook nog eens alleen uitgevoerd, als zelfde.checked 'true' is, als de 'Ja'-knop bij de vraag over het rekening-adres is aangevinkt. Als de 'Ja'-knop niet is aangevinkt, moet er iets anders gebeurd. Dat wordt hieronder afgehandeld, bij de regels die onder else staan.

Kortom: elke keer als input#zelfde-adres, de 'Ja'-knop, wordt aangevinkt, wordt dit uitgevoerd, wordt aria-checked="true" toegevoegd aan input#zelfde-adres.

Bij opening van de pagina is aria-checked="true" al aanwezig, omdat dit al in de html staat. Bij opening van de pagina is deze regel dus overbodig. Maar als de 'Ja'-knop wordt uitgevinkt, wordt dit veranderd in aria-checked="false". Bij het opnieuw aanvinken van de 'Ja'-knop moet dat weer worden veranderd in aria-checked="true", en dan heeft deze regel wel nut.

Als je deze veranderingen zelf wilt zien in de broncode, moet je de gegenereerde code bekijken. Als je in de gewone broncode kijkt, zie je niets van deze veranderingen. Als je in de de gegenereerde code kijkt, zie je de html veranderen op het moment dat je de 'Ja'-knop aan‑ of uitvinkt.

aria-checked is een zogenaamde WAI-ARIA-code, die aan schermlezers duidelijk maakt dat de radioknop niet is aangevinkt. Je kunt daar meer over vinden bij WAI-ARIA-codes.

ander.setAttribute("aria-checked", "false");

De tweede regel van de code boven de else die moet worden uitgevoerd, als zelfde.checked 'true' is, als 'Ja' is aangevinkt bij de vraag 'Moet de rekening ook naar dit adres?'.

Hier gebeurt vrijwel hetzelfde als iets hierboven uitgebreid is beschreven bij zelfde.setAttribute("aria-checked", "true");. Maar dan net iets anders. (Ja, 't zal 'ns gewoon simpel helemaal hetzelfde zijn, pfff.)

Aan het begin staat hier geen zelfde, maar ander. Dat is de variabele waarin bij ander = document.getElementById("ander-adres") input#ander-adres is opgeborgen. Deze regel wordt dus uitgevoerd bij input#ander-adres: de 'Nee'-knop bij de vraag 'Moet de rekening ook naar dit adres?'.

Verder wordt hier aria-checked="false" toegevoegd aan input#ander-adres: de 'Nee'-knop is niet aangevinkt, niet checked. En dat klopt, want deze regel wordt alleen uitgevoerd als de 'Ja'-knop is aangevinkt, en dan vinkt de browser automatisch de 'Nee'-knop uit.

rekening[i].setAttribute("disabled", "true"); rekening[i].setAttribute("aria-disabled", "true");

De derde en vierde regel van de code boven de else die moet worden uitgevoerd, als zelfde.checked 'true' is, als 'Ja' is aangevinkt bij de vraag 'Moet de rekening ook naar dit adres?'.

Deze twee regels doen vrijwel hetzelfde, dus heb ik ze bij elkaar gezet.

rekening: in de variabele 'rekening' zijn bij rekening = document.querySelectorAll("#rekening-naar input") de vier <input>'s opgeborgen, die binnen fieldset#rekening-naar staan: voor Naam, Adres, Stad en Postcode elk een. Omdat in 'rekening' niet één, maar vier elementen zijn opgeslagen, moet je een volgnummer gebruiken om de juiste <input> te aan te spreken. Dit volgnummer zet je tussen twee teksthaken [], gelijk achter rekening:

rekening[i]: pardon? Een volgnummer? Daar staat toch echt een 'i'. Jawel, maar dat is ook weer een variabele. En binnen die variabele 'i' staat eerlijk waar wel een gewoon volgnummer. Die variabele 'i' is aangemaakt bij for (var i = 0; i < rekening.length; i++) {(...) code (...)}. Het is een teller die ervoor zorgt dat deze regels met code voor elke <input> worden uitgevoerd. Elke keer als een <input> is behandeld, wordt de teller met 1 verhoogd.

Omdat een computer gek is op '0', begint de teller met '0'. Aan het begin staat er dus eigenlijk rekening[0]. En dat komt goed uit, want ook de volgnummers van de <input>'s in 'rekening' beginnen met 0. rekening[0] is de eerste <input> uit 'rekening'.

Als de regels met code voor de eerste <input> zijn afgehandeld, wordt de 'i' met 1 verhoogd. Bij de tweede ronde staat er dus eigenlijk rekening[1]: de tweede <input>. Bij de derde ronde is het rekening[2] en bij de vierde ronde rekening[3]. Dit is tevens de laatste <input>, dus hier stopt het.

(Hoe de teller wordt verhoogd, en waarom het na de vierde <input> stopt, is te vinden bij for (var i = 0; i < rekening.length; i++) {(...) code (...)}.)

Een heel verhaal, maar het komt er dus simpelweg op neer dat elk van de vier <input>'s binnen fieldset#rekening-naar aan de beurt komt.

setAttribute(): een 'attribuut' is een toevoegsel bij een html-element, zoals width="100" of checked. Daar zijn er nogal wat van (nog los van eigengemaakte attributen). Met setAttribute() verander je de waarde bij een attribuut. Als het attribuut nog niet bestaat, wordt het gemaakt. Tussen de haakjes staat voor de komma de naam van het attribuut, achter de komma staat de waarde.

"disabled" en "aria-disabled": de eerste regel voegt het attribuut 'disabled' toe, de tweede regel het attribuut 'aria-disabled'. Ze betekenen hetzelfde, maar de tweede is een WAI-ARIA-code, specifiek bedoeld voor schermlezers. Je kunt daar meer over lezen bij WAI-ARIA-codes.

De namen van de attributen staan tussen aanhalingstekens, zodat het script weet dat het hier om letterlijke namen gaat.

"true": de waarde die het attribuut krijgt. Ook weer tussen aanhalingstekens, omdat dit een letterlijke waarde is.

De eerste regel voegt disabled="true" in bij de <input> uit 'rekening' die aan de beurt is, de tweede regel aria-disabled="true".

(Eigenlijk zou het voldoende zijn om alleen 'disabled' toe te voegen, maar de regels van JavaScript eisen dat altijd een waarde aan een attribuut wordt gegeven. Vandaar dat disabled="true" wordt toegevoegd, en niet alleen disabled. De browser kan hier prima mee overweg, dus dit is verder geen probleem.)

Als je deze veranderingen zelf wilt zien in de broncode, moet je de gegenereerde code bekijken. Als je in de gewone broncode kijkt, zie je niets van deze veranderingen. Als je in de de gegenereerde code kijkt, zie je de html veranderen op het moment dat je de 'Ja'-knop aan‑ of uitvinkt.

De vier regels boven de else die worden uitgevoerd als input#zelfde-adres 'true', checked is, als de 'Ja'-knop is aangevinkt, doen samengevat het volgende:

Voeg aria-checked="true" toe aan input#zelfde-adres.

Voeg aria-checked="false" toe aan input#ander-adres.

Voeg disabled="true" en aria-disabled="true" aan de vier <input>'s met Naam, Adres, Stad en Postcode in fieldset#rekening-naar (onder het kopje 'Rekening sturen naar').

De toevoeging van disabled="true" maakt de vier <input>'s onder 'Rekening sturen naar' ontoegankelijk. Bovendien kan het uiterlijk met behulp van de css-selector :disabled worden aangepast, zodat ook zichtbaar wordt dat ze niet gewijzigd kunnen worden.

Dit alles gebeurt alleen, als de 'Ja'-knop bij de vraag 'Moet de rekening ook naar dit adres?' is aangevinkt.

Dan zijn er nog de vier regels onder de else, die alleen worden uitgevoerd als de 'Ja'-knop niet is aangevinkt. (In dat geval is de 'Nee'-knop automatisch aangevinkt, want dat is de enige manier om het vinkje bij de 'Ja'-knop weg te halen.):

zelfde.setAttribute("aria-checked", "false"); ander.setAttribute("aria-checked", "true"); rekening[i].removeAttribute("disabled"); rekening[i].setAttribute("aria-disabled", "false");

Deze vier regels doen exact hetzelfde als de vier regels boven de else, alleen zijn 'false' en 'true' omgewisseld. Samen werken deze twee keer vier regels als een soort aan-uitschakelaar: als de 'Ja'-knop wordt aan‑ of uitgevinkt, verandert 'true' in 'false', en omgekeerd.

Er is, uiteraard en om je te pesten en traditiegetrouw en zo, natuurlijk toch weer iets dat 'n beetje anders is dan bij de eerste vier regels.

De derde regel gebruikt geen setAttribute(), maar removeAttribute():

rekening[i].removeAttribute("disabled");

Als je hier, wat je zou verwachten, setAttribute("disabled", "false") zou gebruiken, voegt het script inderdaad braaf disabled="false" toe aan de <input>. Helaas blijkt die stomme browser alleen disabled te begrijpen en wordt het false genegeerd. Oftewel: hoewel je disabled uit wilt schakelen, blijft dit gewoon werken. De oplossing is removeAttribute(): verwijder het hele disabled, als de 'Ja'-knop wordt uitgevinkt. Als de 'Ja'-knop weer wordt aangevinkt, zet je gewoon weer disabled="true" neer, dat levert geen enkel probleem op. Browser gelukkig, script gelukkig, sitebouwer overspannen. Met dank aan de schrijvers van de diverse specificaties voor hun fantastische samenwerking...

Ook hier geldt weer dat je de veranderingen in de html alleen in de gegenereerde code ziet. Als je in de gewone broncode kijkt, zie je niets van deze veranderingen.

function schakelLeeftijd() {

var isAchttien = document.getElementById("is-achttien"), geenAchttien = document.getElementById("geen-achttien"), drank = document.querySelectorAll("#drank input.achttien");
for (var i = 0; i < drank.length; i++) { if (isAchttien.checked) { isAchttien.setAttribute("aria-checked", "true"); geenAchttien.setAttribute("aria-checked", "false"); drank[i].removeAttribute("disabled"); drank[i].setAttribute("aria-disabled", "false"); } else { isAchttien.setAttribute("aria-checked", "false"); geenAchttien.setAttribute("aria-checked", "true"); drank[i].setAttribute("disabled", "true"); drank[i].setAttribute("aria-disabled", "true"); drank[i].setAttribute("aria-checked", "false"); drank[i].checked = false; } } }

Onder de bezielende leiding van Rutte en met de hartelijke medewerking van geen-bedrijfsleider-van-het-kabinet Samsom is de zorgpremie gigantisch gestegen en de zorgverlening gigantisch gedaald, dus ik ga hier niet deze hele functie beschrijven. Dat zou een gang naar de vinger-fysiotherapeut noodzakelijk maken, en die is dus weggeRutSomd.

Goed, nog eens proberen. Deze functie schakelLeeftijd() lijkt heel erg op de hierboven uitgebreid beschreven functie schakelAdres(). Alleen de verschillen met die functie komen hier aan bod. De tekst is bepaald al lang genoeg.

Het inleidende stukje is hetzelfde als bij schakelAdres(), alleen is de naam van de functie hier 'schakelLeeftijd'. Verder is deze functie gekoppeld aan de radioknoppen met 'Ja' en 'Nee' onder de vraag 'Ben je achttien jaar of ouder?'. De functie wordt uitgevoerd, als een van deze twee knoppen wordt aan‑ of uitgevinkt.

function schakelLeeftijd() {

Zelfde verhaal als bij function schakelAdres() {. Alleen de naam van de functie is hier anders: 'schakelLeeftijd'.

var isAchttien = document.getElementById("is-achttien"),
geenAchttien = document.getElementById("geen-achttien"),
drank = document.querySelectorAll("#drank input.achttien");

Vrijwel hetzelfde verhaal als bij var zelfde = document.getElementById("zelfde-adres"). Alleen wordt hier gezocht naar de id's 'is-achttien' en 'geen-achttien'. In de variabele 'isAchttien' wordt de radioknop input#is-achttien en in de variabele 'geenAchttien' de radioknop input#geen-achttien opgeborgen. Dit zijn de 'Ja'- en 'Nee'-knop bij de vraag 'Ben je achttien jaar of ouder?'.

De derde regel is ook grotendeels hetzelfde als de derde regel bij schakelAdres(), waarover meer is te vinden bij rekening = document.querySelectorAll("#rekening-naar input"). Alleen wordt hier gezocht naar #drank input.achttien: de <input>'s met class="achttien" binnen het element met id="drank". Dit zijn de <input>'s binnen fieldset#drank die horen bij de de dranken die niet gekozen kunnen worden, als iemand jonger is dan achttien. Niet álle <input>'s uit #drank worden dus opgeslagen in de variabele 'drank', maar alleen de <input>'s met class="achttien". Dat zijn er zes.

for (var i = 0; i < drank.length; i++) {(...) code (...)}

Zelfde verhaal als bij for (var i = 0; i < rekening.length; i++) {(...) code (...)}. Alleen wordt hier niet rekening.length, maar drank.length gebruikt: de lengte van drank, wat overeenkomt met het aantal daarin zittende <input>'s. Dat zijn er hier zes, omdat zes <input>'s binnen fieldset#drank class="achttien" hebben. Alleen deze zes <input>'s moeten eventueel uitgeschakeld worden. De andere dranken kunnen altijd gekozen worden, onafhankelijk van de leeftijd.

Er zijn twee mogelijke toestanden bij de beantwoording van de vraag 'Ben je achttien jaar of ouder? 'Ja' is aangevinkt of 'Ja' is niet aangevinkt. Bij opening van de pagina is 'Nee' aangevinkt en staat 'Ja' dus uitgevinkt. (Bovendien zijn de zes dranken die je onder de achttien niet mag kopen uitgeschakeld bij openen van de pagina.)

Als 'Ja' is aangevinkt, is achttien.checked 'true' en wordt de code boven de else uitgevoerd. Als 'Ja' niet is aangevinkt, 'false' is, wordt de code onder de else uitgevoerd:

        if (isAchttien.checked) {
      (...)
      code als isAchttien.checked 'true' is
      (...)
} else {
      (...)
      code als isAchttien.checked 'false' is
      (...)
}

Het verhaal is verder hetzelfde als bij Er zijn twee mogelijke toestanden... Alleen gaat het hier dus om het antwoord op de vraag 'Ben je achttien jaar of ouder?' en de bij die vraag horende radioknoppen met 'Ja' en 'Nee".

De code onder de if en onder de else werkt ook weer grotendeels hetzelfde als bij zelfde.setAttribute("aria-checked", "true") wordt beschreven. Hier volgt die code:

Maar deze code hoort bij de 'Ja'- en 'Nee'-knop van de vraag 'Ben je achttien jaar of ouder?', bij input#is-achttien en input#geen-achttien. Het zijn hier de attributen bij die twee elementen die worden gewijzigd. Ook hier geldt weer dat die wijzigingen alleen in de gegenereerde code te zien zijn, niet in de gewone broncode.

Hier wordt niet het rekening-adres ontoegankelijk gemaakt, maar de zes dranken die je onder de achttien niet mag kopen: Arseendrab, Fiedelvitriool, Jenever, Likeur, Rum en Whisky. Dit zijn de <input>'s uit fieldset#drank die een class="achttien" hebben. Alleen deze zes <input>'s zijn in de variabele 'dranken' aanwezig, dus alleen die zes <input>'s worden behandeld.

Ten slotte staan hier onder de else nog twee extra regels, die in de functie schakelAdres() missen:

drank[i].setAttribute("aria-checked", "false"); drank[i].checked = false;

Beide regels betekenen weer hetzelfde. De eerste regel is speciaal voor schermlezers. Hij voegt de WAI-ARIA-code aria-checked="false" toe, waarover meer is te lezen bij WAI-ARIA-codes.

De tweede regel zorgt dat de betreffende <input> niet meer is aangevinkt: checked wordt 'false' gemaakt. checked = false doet hetzelfde als het hier veel vaker gebruikte setAttribute("checked", "false"), alleen werkt deze laatste niet goed in alle browsers, vanwege verschillen tussen JavaScript en html. (De aanhalingstekens rondom false missen hier, omdat het hier niet om de letterlijke tekst 'false' gaat, maar om de waarde, het sleutelwoord false. Het voert hier te ver om op dit soort verschillen in te gaan.)

drank[i]: werkt hetzelfde als overal hier. Bij de eerste ronde staat hier eigenlijk drank[0], de eerste <input>. Bij de tweede ronde staat er eigenlijk drank[1]: de tweede <input>. Enz., tot de vijfde en laatste ronde: drank[5] voor de zesde <input> met class="achttien".

setAttribute("aria-checked", "false") en checked = false: de eerste is voor schermlezers, de tweede voor het gewone scherm.

Als iemand al heeft gekozen voor dranken boven de achttien en dan vervolgens alsnog de vraag 'Ben je achttien jaar of ouder?' met 'Nee' beantwoordt, blijven de al aangevinkte dranken voor boven de achttien aangevinkt. Jaja, dat had zoonlief van 16 gedacht...

Daarom worden, als voor 'Nee' is gekozen, alle <input>'s met dranken voor boven de achttien nagelopen en wordt bij elk van die <input>'s uitgevinkt. Dranken die altijd gekocht mogen worden zitten niet in de variabele 'drank' en worden dus genegeerd.

(Als beveiliging is dit volstrekt onvoldoenden. Vertrouw nooit alleen op dingen als disabled en checked als beveiliging, want deze zijn uiterst simpel te omzeilen. Goede controle op de server blijft absoluut noodzakelijk.

function stuurDrank() {

for (var i = 0; i < dranken.length; i++) { if (dranken[i].checked) { dranken[i].setAttribute("aria-checked", "true"); } else { dranken[i].setAttribute("aria-checked", "false"); } } }

Ook dit is weer een stukje JavaScript, dat kenners waarschijnlijk een gruwel is. Normaal genomen zou je deze hele functie waarschijnlijk bij een van de andere twee onderbrengen, of ze zelfs alle drie tot één functie terugbrengen. Maar dit is dus geen cursus JavaScript, het is alleen een poging te laten zien wat er zoal allemaal mogelijk is met een combinatie van html5, css3 en JavaScript.

Na me aldus veilig ingedekt te hebben voor elke kritiek, kan ik nu met een gerust hart aan de echte toelichting beginnen. (Hèhè, ben ik een gediplomeerd gluup of niet?)

Bij de veertien dranken die gekocht kunnen worden, handelt de browser het aan‑ en uitvinken af. Ook houdt de browser intern bij, welke keuzevakjes zijn aan‑ en welke zijn uitgevinkt, zodat dit bij het versturen van het formulier verder op de server verwerkt kan worden.

Dat is zonder meer uiterst prijzenswaardig, maar een schermlezer heeft aan al dat fraais weinig. Als een keuzevakje is aan‑ of uitgevinkt, moet daarom voor schermlezers nog een speciale WAI-ARIA-code worden aangebracht, die aangeeft of het keuzevakje is aangevinkt of niet. Meer over deze WAI-ARIA-codes kun je vinden bij WAI-ARIA-codes.

Gelijk na het woord function volgt de naam van de functie. Die is hier 'stuurDrank'. Als je deze functie wilt uitvoeren, wilt aanroepen, moet je 'stuurDrank' aanroepen.

In het eerste deel van dit script is de gebeurtenis 'change', verandering, gekoppeld aan de <input>'s, de keuzevakjes onder het kopje 'Ja! Stuur mij met spoed één fles:'. Dat is gebeurd bij var dranken = document.querySelectorAll("#drank input");. Elke <input>, elk keuzevakje, binnen fieldset#drank is in de variabele 'dranken' gestopt. In totaal veertien stuks.

Bij een verandering van een van die keuzevakjes, als er eentje wordt aan‑ of uitgevinkt, moet er iets gebeuren. Wát er moet gebeuren, is ook in het eerste deel van het script bepaald; het aanroepen van de functie 'stuurDrank'. En dat is deze functie.

Als het vinkje bij één van de veertien keuzevakjes bij de dranken wordt verwijderd of geplaatst, wordt deze functie aangeroepen en dus uitgevoerd.

function stuurDrank() {

function: het sleutelwoord waarmee het begin van een functie wordt aangegeven.

stuurDrank: de naam van de functie. Als het beestje geen naam heeft, kun je het ook niet aanroepen en heb je er dus niets aan. (Dit klopt niet helemaal. JavaScript kent ook equivalenten van 'hé!', 'hé, jij daar!', 'hé, jij daar in die zwarte jas', en dergelijke, maar die worden hier niet gebruikt. En het is zo al ingewikkeld genoeg.)

(): tja, dat hoort nou eenmaal zo na de naam van een functie.. (Behalve dat het zo hoort, kun je hier ook voor van alles gebruik van maken. Maar dat gebeurt hier niet, dus dat slaan we lekker over.)

{: hiermee geef je aan dat de code van de functie, het deel dat moet worden uitgevoerd, nu echt gaat beginnen. Aan het eind staat de bijbehorende }. Die } staat eenzaam te wezen op een eigen regel, want dat is leesbaarder voor mensen.

for (var i = 0; i < dranken.length; i++) {(...) code (...)}

Weer in stukjes hakken om het te kunnen begrijpen.

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

Hier eerst het deel dat ervoor zorgt dat elke eerder gevonden <input> aan de beurt komt.

(: met dit haakje opent het deel dat ervoor zorgt, dat elke <input> aan de beurt komt. Aan het eind van de regel staat de bijbehorende ), waardoor het script weet dat dit het einde van dit deel van de code is.

var i = 0;: met het sleutelwoord var geef je aan dat het erop volgende woord de naam van een 'variabele' is. Dat is hier 'i'. Dat is een heel korte naam. 'i' wordt gebruikt als een teller (waarover later meer), en bij dit soort tellers is het gebruikelijk ze de naam 'i' te geven. Dat soort gewoontes maakt het voor mensen een stuk makkelijker elkaars code te lezen en begrijpen.

We hebben dus een variabele met de naam 'i'. Met = 0 wordt vervolgens aangegeven dat de inhoud van die variabele, de waarde, '0' is. En omdat het een variabele is, kan de waarde veranderen. Wat later in de regel ook gaat gebeuren: elke keer als er een <input> is afgehandeld, wordt 'i' met 1 verhoogd. Dat gebeurt in het laatste deel van de regel:

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

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

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

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

Enz.

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

i < dranken.length;: het middelste deel. In 'dranken' zitten de eerder gevonden <input>'s. Met length kan het aantal gevonden <input>'s worden vastgesteld. Er zijn eerder veertien <input>'s gevonden en in 'dranken' opgeborgen. De length (lengte) van 'dranken' is dus 14.

In dit geval is dranken.length dus hetzelfde als het getal 14. Zouden er 38 <input>'s zijn gevonden, dan zou dranken.length hetzelfde zijn als het getal 38.

'i' bevat een getal. Aan het begin is dat getal 0, want dat is hierboven opgegeven.

Het teken < betekent: kleiner dan.

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

In gewone mensentaal staat hier:

zolang teller 'i' kleiner is dan het aantal <input>'s in 'dranken'.

Als niet meer aan deze voorwaarde wordt voldaan, als teller 'i' niet meer kleiner is dan het aantal <input>'s, stop dan met het uitvoeren van de code die tussen de {} staat.

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

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

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

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

Aan het begin heeft i de waarde 0. Na de eerste ronde heeft i de waarde 1. Na de tweede ronde heeft i de waarde 2. Enz. Na de veertiende ronde heeft i de waarde 14. Waarmee i niet meer kleiner is dan de lengte van 'dranken', het aantal daarin zittende <input>'s.

Omdat niet meer aan de voorwaarde i < dranken.length wordt voldaan, wordt gestopt met het behandelen van de <input>'s. En dat komt goed uit, want alle <input>'s zijn precies allemaal één keer aan de beurt gekomen. Niet meer, niet minder. Bij allemaal is de tussen de {} staande code één keer toegepast.

Tot nu toe hebben we veertien keuzevakjes, veertien <input>'s, gevonden en opgeborgen in de variabele 'dranken', en er is gezorgd dat elk van die <input>'s aan de beurt kan komen.

Een keuzevinkje is aangevinkt of het is niet aangevinkt. Een andere mogelijkheid is er niet. Bij de in 'dranken' opgeslagen <input>'s is ook opgeslagen, of het keuzevakje is aangevinkt of niet. Of het 'checked' of 'true' is of niet. Dit is opgeslagen in checked. Dit opslaan in checked wordt automatisch door de browser gedaan.

Als de knop is aangevinkt, is checked 'true', waar. Als checked niet is aangevinkt, is checked 'false', onwaar.

Daar kun je op controleren en aan de hand daarvan bepaalde dingen doen of niet doen. Dat controleren gebeurt hier met behulp van if():

if (dranken[i].checked) {(...) code (...)}

Net als bij for staat het deel dat bij if hoort tussen twee haakjes. Dat is hier dranken[i].checked. Dat is heel kort, maar soms is dit heel lang, en zonder haakjes zou de if niet weten waar het einde van de voorwaarde is.

De voorwaarde? Ja. De voorwaarde is hier dat dranken[i].checked 'true' moet zijn. Dat 'true' laat je weg, alweer vanwege luiheid bij programmeurs, maar eigenlijk staat hier iets als (dranken[i].checked === true). (Let even niet op het driedubbele isgelijkteken. Dat is een JavaScript-taalregel, die in dit voorbeeld verder niet belangrijk is.)

dranken[i].checked is 'true', als het keuzevakje dat bij dranken[i] hoort, is aangevinkt. Als dat zo is, wordt de tussen de {} staande code uitgevoerd, net zoals bij for.

Tussen twee teksthaken [] staat een variabele 'i'. Binnen die variabele 'i' staat een gewoon volgnummer. Die variabele 'i' is aangemaakt bij for (var i = 0; i < dranken.length; i++) {(...) code (...)}. Het is een teller die ervoor zorgt dat deze regels met code voor elke <input> worden uitgevoerd. Elke keer als een <input> is behandeld, wordt de teller met 1 verhoogd.

Omdat een computer gek is op '0', begint de teller met '0'. Aan het begin staat er dus eigenlijk dranken[0]. En dat komt goed uit, want ook de volgnummers van de <input>'s in 'rekening' beginnen met 0. dranken[0] is de eerste <input> uit 'dranken'.

Als de alle regels code zijn afgehandeld, wordt de 'i' met 1 verhoogd. Bij de tweede ronde staat er dus eigenlijk dranken[1]: de tweede <input>. Bij de derde ronde is het dranken[2] en bij de veertiende ronde dranken[13]. Dit is tevens de laatste <input>, dus hier stopt het.

(Hoe de teller wordt verhoogd, en waarom het na de vierde <input> stopt, is te vinden bij for (var i = 0; i < dranken.length; i++) {(...) code (...)}.)

Een heel verhaal, maar het komt er dus simpelweg op neer dat elk van de veertien <input>'s binnen fieldset#drank aan de beurt komt.

De andere mogelijkheid is dat het keuzevakje niet is aangevinkt. Dan is dranken[i].checked 'false', niet waar. In dat geval moeten er andere dingen worden gedaan, dan wanneer dranken[i].checked 'true' is.

Dat geef je als volgt aan in JavaScript:

        if (dranken[i].checked) {
      (...)
      code als dranken[i].checked 'true' is
      (...)
} else {
      (...)
      code als dranken[i].checked 'false' is
      (...)
}

Als dranken[i].checked 'true' is, voer dan de code tussen if en else uit. Begin en einde van die code wordt met { en } aangegeven.

Als dranken[i].checked niet 'true' is, kan er maar één ander iets aan de hand zijn: het is 'false'. Anders dan bij bijvoorbeeld een teller, die veel waarden kan krijgen, zijn hier maar twee mogelijkheden. Dat komt overeen met de twee mogelijkheden van een keuzevakje: aangevinkt of niet. Een keuzevakje half aanvinken kan niet.

Als er maar twee mogelijkheden zijn, kun je volstaan met het gebruik van else, 'anders', voor de tweede mogelijkheid. Als dranken[i].checked 'false' is, wordt de code achter else uitgevoerd. Ook daarvan wordt begin en eind weer aangegeven met { en }:

Beide regels voor en na else lijken op elkaar. Bij beide word setAttribute() uitgevoerd. Hiermee wordt een attribuut gewijzigd of, als het attribuut nog niet aanwezig is, nieuw toegevoegd.

De naam van het attribuut staat voor de komma tussen aanhalingstekens: "aria-checked", en is bij beide regels hetzelfde.

Daarachter staat tussen aanhalingstekens de waarde die aria-checked moet krijgen. Als checked 'true' is, als het keuzevakje is aangevinkt, krijgt aria-checked ook de waarde 'true'. Als het keuzevakje 'false' is, niet is aangevinkt, krijgt aria-checked ook de waarde 'false'.

aria-checked is een zogenaamde WAI-ARIA-code, gericht op schermlezers, zodat ook schermlezers weten, of een keuzevakje is aangevinkt of niet. Je kunt er meer over vinden bij WAI-ARIA-codes.

De wijzigingen die hier door het script worden aangebracht, zijn alleen te zien in de gegenereerde code, niet in de normale broncode.

Zoals vaker gezegd: dit kan veel efficiënter worden geschreven, maar wordt dan gelijk een stuk ingewikkelder. Omdat maar hoogstens één keuzevakje tegelijk kan worden gewijzigd, is het onzin ze alle veertien te controleren, om die éne gewijzigde eruit te pikken. Maar code die dat kan is wel veel korter en efficiënter, maar ook 'n stuk ingewikkelder. Dus daar heb ik voor dit voorbeeld van afgezien.