Bij aanraken van, hoveren over of tabben naar een gearceerd woord opent een illustratie - uitleg
Laatst aangepast: .

Korte omschrijving
Als de cursor boven een van de gearceerde woorden komt, een van de gearceerde woorden wordt aangeraakt, of als je met de Tab-toets naar een van de gearceerde woorden gaat, opent een bij de woorden horende kleine afbeelding.
BELANGRIJK
Deze uitleg hoort bij het voorbeeld dat in de download zit. Het voorbeeld uit de download verschilt iets van het voorbeeld hier op de site. In de download ontbreekt bijvoorbeeld de navigatie voor de site. Ook in de kopregels zit vaak wat verschil. Daarnaast kunnen er nog andere (meestal kleine) verschillen zijn.
Als je deze uitleg leest naast de broncode van het voorbeeld op de site, kan het dus bijvoorbeeld zijn dat 'n <h1> uit de css bij 'n <h2> uit de html hoort. Maar het gaat niet om hele grote, fundamentele afwijkingen.
Als je dit lastig vindt, kun je bovenaan de pagina de hele handel downloaden. In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.
Als je deze handleiding graag uitprint (zonde van het bos), gebruik dan de pdf in de download. Deze pagina is niet geoptimaliseerd voor printen, de pdf kan wel makkelijk worden geprint.
Alles op deze site kan vrij worden gebruikt, met drie beperkingen:
* Je gebruikt het materiaal op deze site volledig op eigen risico. Het kan prima zijn dat er fouten in de hier verstrekte info zitten. Voor eventuele schade die door gebruik van materiaal van deze site ontstaat, in welke vorm dan ook, zijn www.css-voorbeelden.nl en medewerkers daarvan op geen enkele manier verantwoordelijk.
* Deze uitleg wordt regelmatig bijgewerkt. Het is daarom niet toegestaan deze uitleg op welke manier dan ook te verspreiden, zonder daarbij duidelijk te vermelden dat de uitleg afkomstig is van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie is te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.
* Het kan zijn dat materiaal is gebruikt dat van anderen afkomstig is. Dat materiaal kan onder een bepaalde licentie vallen, waardoor het mogelijk niet onbeperkt gebruikt mag worden. Als dat zo is, wordt dat vermeld onder Inhoud van de download en licenties.
Een link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.
Alle code is geschreven in een afwijkende
lettersoort en -kleur. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles vanwege de leesbaarheid in een gewone letter.)
Opmerkingen
-
Dit voorbeeld is oorspronkelijk gemaakt in de tijd dat er nog (vrijwel) alleen (grote) desktopcomputers met toetsenbord en muis bestonden. Dat was relatief simpel: als je met een muis over een gearceerd woord hoverde, verscheen een afbeelding. Gebruikers van het toetsenbord hadden pech, want ook deze site deed nog niet zoveel aan toegankelijkheid.
Deze laatste versie van dit voorbeeld werkt inmiddels ook op touchscreens, op smartphones en met het toetsenbord. Maar als je ziet hoeveel aanpassingen er voor allerlei browsers en systemen nodig zijn om afwijkingen en bugs op te vangen, ziet het geheel er toch wat wiebelig uit. Je kunt je dan ook afvragen, of het verstandig is deze techniek 'in het echt' te gebruiken.
-
De in dit voorbeeld gebruikte afbeeldingen zijn bedoeld als kleine aanvullingen. Daarom worden ze niet getoond of beschreven in schermlezers. Voor grotere afbeeldingen die echt wezenlijke informatie geven (en dus voor schermlezers een omschrijving horen te hebben) is deze constructie absoluut ongeschikt.
Voor schermlezers is deze constructie hoe dan ook niet te gebruiken. Als je gewoon de tekst leest, gaat dat prima. Maar in deze tekst zitten 37 afbeeldingen. Als een schermlezer de tekst voorleest en dat voorlezen 37 keer onderbreekt voor 'n afbeelding, is de tekst niet meer te volgen.
- De 36 afbeeldingen worden altijd allemaal geladen, ook als ze niet worden getoond. Maar omdat deze samen slechts 76,3 kilobyte groot zijn, maakt dat hier weinig uit.
- Er zijn 36 afbeeldingen, maar in de tekst wordt regelmatig het getal 37 genoemd. Weer niet van de whisky af kunnen blijven? Nou, nee. Eén afbeelding wordt twee keer gebruikt. (Mogelijk heb ik bij de eerste versie jaren geleden door woeste uitspattingen wel 'n keer 'n afbeelding dubbel gezien, dat weet ik niet meer.)
Links in deze uitleg, vooral links naar andere sites, kunnen verouderd zijn. Op de pagina met links vind je steeds de meest recente links.
Dit voorbeeld is gemaakt op een systeem met Linux (Kubuntu). Daarbij is vooral gebruik gemaakt van Visual Studio Code, GIMP en Firefox met extensies. De pdf-bestanden zijn gemaakt met LibreOffice.
Vragen of opmerkingen? Fout gevonden? Ga naar het forum.
Achterliggend idee
De tekst is 'n gewone normale tekst (nou ja, normaal, wat heet...). In die tekst zijn bepaalde woorden gearceerd. Die woorden staan in 'n <span>, en als je over die span hovert wordt een kleine afbeelding zichtbaar, die bij dat woord hoort. Als er niet wordt gehoverd, staat die afbeelding links buiten het scherm geparkeerd.
Dat was het oorspronkelijke voorbeeld, zoals dat werkte op desktopcomputers met een muis.
Met een muis of touchpad werkt het nog grotendeels hetzelfde. Alleen wordt nu gebruik gemaakt van het relatief nieuwe position: sticky;
waardoor de afbeeldingen niet meer regelmatig gedeeltelijk buiten het venster van de browser komen te staan.
In lage browservensters, zoals op smartphones, werkt dit niet echt lekker. Daarom wordt in lage vensters de afbeelding in het midden van het venster geplaatst.
Voor gebruikers van de Tab-toets is een extra (lege) <span> voor de afbeelding gezet. Door deze <span> tabindex="0"
te geven, kan de <span> focus krijgen, waardoor de erachter zittende afbeelding getoond kan worden. In principe zou je ook de afbeelding zelf tabindex="0"
kunnen geven, maar dan noemen sommige schermlezers de afbeelding. Wat bij 37 afbeeldingen dus wat bezwaarlijk is.
Als de <span> met de gemarkeerde woorden een tabindex krijgt, melden sommige schermlezers iets als 'klikbaar'. Alleen een lege <span> wordt bij het voorlezen door alle geteste schermlezers volledig genegeerd.
Als een afbeelding wordt geopend door hoveren over of aanraken van een gemarkeerd woord, is duidelijk bij welk woord de afbeelding hoort. Maar bij gebruik van de Tab-toets is dat niet duidelijk. Normaal genomen is een element dat de focus heeft te herkennen aan een kadertje. Hier ontbreekt dat kadertje echter, want de <span> met focus is leeg.
Daarom staan de gemarkeerde woorden, de lege <span> en de afbeelding in een gezamenlijke buitenste <span>. Nieuwere browsers ondersteunen de pseudo-class :focus-within
: als een nakomeling van een element focus heeft, kun je het element met behulp van css aanpassen. Zodra de lege <span> focus heeft, kan de buitenste <span> een kadertje krijgen.
Voor browsers die :focus-within
niet ondersteunen wordt een klein beetje JavaScript gebruikt om hetzelfde effect te krijgen.
Dan zijn er nog wat aanpassingen voor verschillende browsers en systemen nodig. Deze worden bij de uitleg van de code besproken.
Voorwaarden waaraan html en css moeten voldoen
Voor gebruikers van de Tab-toets is niet duidelijk, bij welke gemarkeerde tekst een afbeelding hoort. Daarom wordt met behulp van de pseudo-class :focus-within
de bij een afbeelding horende gemarkeerde tekst voorzien van een kadertje, zodra de afbeelding wordt getoond.
Voor browsers die dit niet ondersteunen, wordt gebruik gemaakt van een beetje JavaScript. Om dit script goed te laten werken, moet de html aan twee simpele voorwaarden voldoen.
Structuur
De gemarkeerde tekst staat in een <span> met class="markeer". Die <span> moet altijd direct voor de <span> met class="pict" staan (de <span> die focus kan krijgen).
Als je dit verandert, moet je ook het script (en de css) aanpassen.
Id's en classes
De <span> die focus kan krijgen, moet een class="pict" hebben. Als je dit wilt aanpassen, moet je dat ook in het script (en in de css) aanpassen.
De voorvoegsels -moz-, -ms- en -webkit-
Voordat een nieuwe css-eigenschap wordt ingevoerd, is er in de regel een experimentele fase. Browsers passen het dan al toe, maar met een aangepaste naam. Tijdens deze fase kunnen problemen worden opgelost en worden veldslagen uitgevochten, over hoe de standaard precies moet worden toegepast.
Als iedereen het overal over eens is en alle problemen zijn opgelost, wordt de officiële naam uit de standaard gebruikt.
De belangrijkste browsers hebben elk een eigen voorvoegsel:
Firefox: -moz-
, naar de maker: Mozilla.
Op webkit gebaseerde browsers, zoals Google Chrome, Opera, Safari en Android browser: -webkit-
.
(Google Chrome is van webkit overgestapt op een eigen weergave-machine: Blink. Blink gaat geen voorvoegsels gebruiken. Het is echter een aftakking van webkit, dus het zal nog wel even duren voor -webkit-
hier helemaal uit is verdwenen. Ook Opera gebruikt Blink.)
Internet Explorer: -ms-
, naar de maker: Microsoft. (Edge gebruikt geen voorvoegsels, maar vanwege compatibiliteit met oudere sites kunnen er nog wat aanwezig zijn.)
Zodra de experimentele fase voorbij is, wordt het voorvoegsel weggelaten. Omdat dat moment niet bij alle browsers hetzelfde is, zet je nu ook al de officiële naam erbij. Deze wordt als laatste opgegeven. Bijvoorbeeld Android browser herkent -webkit-linear-gradient
. Zodra Android browser linear-gradient
gaat herkennen, zal dit -webkit-linear-gradient
overrulen, omdat het er later in staat. Dat ze er beide in staan, is dus geen enkel probleem.
In dit voorbeeld worden user-select
en position: sticky;
gebruikt.
user-select
Op dit moment moet je nog het volgende schrijven:
{-moz-user-select: ...; -ms-user-select: ...; -webkit-user-select: ...; user-select: ...;}
In de toekomst kun je volstaan met:
{user-select: ...;}
position: sticky;
Op dit moment moet je nog het volgende schrijven:
position: -webkit-sticky; position: sticky;
In de toekomst kun je volstaan met:
position: sticky;
Inmiddels is de algemene mening dat 'vendor prefixes', zoals deze voorvoegsels in het Engels heten, geen groot succes zijn. Eén van de grootste problemen: veel sitemakers gebruiken alleen de -webkit-
variant. Daar kwamen ze in het verleden nog mee weg, omdat Apple op mobiel zo'n beetje 'n monopolie had. Inmiddels is dat niet meer zo, maar deze gewoonte bestaat nog steeds. Waardoor 'n site alleen in op webkit georiënteerde browsers goed is te bekijken.
Dit is zo'n groot probleem dat andere browsers soms de variant met -webkit-
ook maar zijn gaan implementeren, naast de standaard. Want als 'n site het niet goed doet in 'n bepaalde browser, krijgt in de regel niet de site maar de browser de schuld.
Vanwege alle problemen met 'vendor prefixes' worden deze door steeds meer browsers niet meer gebruikt. Nieuwe, experimentele css-eigenschappen zitten inmiddels in bijvoorbeeld Firefox, Google Chrome en Safari achter een zogenaamde vlag: de gebruiker moet iets veranderen in de instellingen, waarna de eigenschap gebruikt (en getest) kan worden. Als alles werkt, zoals het hoort te werken, schakelt de browsermaker de vlag standaard in.
Voorlopig zijn we echter nog niet van deze voorvoegsels af. Als je ze gebruikt, gebruik dan álle varianten, en eindig met de variant zonder voorvoegsel, zoals die uiteindelijk ooit gebruikt gaat worden. Als je alleen de -webkit-
variant gebruikt, ben je in feite 'n onbetaalde reclamemaker voor Apple.
Semantische elementen en WAI-ARIA
Deze twee onderwerpen zijn samengevoegd, omdat ze veel met elkaar te maken hebben.
Semantische elementen
De meeste elementen die in html worden gebruikt, hebben een semantische betekenis. Dat wil zeggen dat je aan de gebruikte tag al (enigszins) kunt zien, wat voor soort inhoud er in het element staat. In een <h1> staat een belangrijke kop. In een <h2> staat een iets minder belangrijke kop. In een <p> staat een alinea. In een <table> staat een tabel (en geen lay-out, als het goed is!). Enzovoort.
Door het op de goede manier gebruiken van semantische elementen, kunnen zoekmachines, schermlezers, enzovoort de structuur van een pagina begrijpen. De spider van een zoekmachine is redelijk te vergelijken met een blinde. Het is dus ook in je eigen belang om semantische elementen zo goed mogelijk te gebruiken. Een site die toegankelijk is voor mensen met een handicap, is in de regel ook goed te verwerken door een zoekmachine en maakt dus een grotere kans gevonden en bezocht te worden.
Als het goed is, wordt het uiterlijk van de pagina bepaald met behulp van css. Het uiterlijk staat hierdoor (vrijwel) los van de semantische inhoud van de pagina. Met behulp van css kun je een <h1> heel klein weergeven en een <h6> heel groot, terwijl schermlezers, zoekmachines, en dergelijke nog steeds weten dat de <h1> een belangrijke kop is.
Slechts enkele elementen, zoals <div> en <span>, hebben geen semantische betekenis. Daardoor zijn deze elementen uitstekend geschikt om met behulp van css het uiterlijk van de pagina aan te passen: de semantische betekenis verandert niet, maar het uiterlijk wel. Voor een schermlezer of zoekmachine verandert er (vrijwel) niets, voor de gemiddelde bezoeker krijgt het door de css een heel ander uiterlijk.
(De derde laag, naast html voor de inhoud en css voor het uiterlijk, is JavaScript. Die zorgt voor de interactie tussen site en bezoeker. De min of meer strikte scheiding tussen css en html aan de ene kant en JavaScript aan de andere kant is met de komst van css3 en html5 veel vager geworden. Je kunt nu bijvoorbeeld ook met css dingen langzaam verplaatsen en met html deels de invoer in formulieren controleren.)
Html5 heeft een aantal nieuwe elementen, die speciaal zijn bedoeld om de opbouw van een pagina aan te geven. In dit voorbeeld wordt hiervan alleen <main> gebruikt. <main> gedraagt zich als een gewone <div>, maar dan een <div> met een semantische betekenis. Hierdoor kunnen schermlezers, zoekmachines, en dergelijke beter zien, hoe de pagina is samengesteld. De meeste schermlezers kunnen dit soort elementen ook gebruiken om snel over de pagina te navigeren.
<main>
Hierbinnen staat de belangrijkste inhoud van de pagina. In dit voorbeeld is dat alleen de tekst met de illustraties.
Met behulp van dit soort nieuwe semantische elementen kan bijvoorbeeld een schermlezer in één keer een heel menu passeren en gelijk naar de echte inhoud gaan. Alleen hadden deze nieuwe elementen tot voor kort één probleem: ze hadden in de praktijk nog weinig nut, omdat schermlezers en dergelijke ze nog niet herkenden. Daarom werd een zogenaamde WAI-ARIA-code toegevoegd aan deze elementen. Dat is een al veel langer bestaande code, die schermlezers en dergelijke wel herkennen. Voor <main> ziet dat er zo uit:
<main role="main">
Inmiddels is dit behoorlijk veranderd. Het advies is nu om deze speciale toevoeging niet meer te gebruiken, omdat de meeste schermlezers en dergelijke dit soort nieuwe elementen inmiddels herkennen.
WAI-ARIA-codes
WAI-ARIA wordt vaak ingekort tot ARIA. Voluit betekent het Web Accessibility Initiative – Accessible Rich Internet Applications.
Er word in dit voorbeeld één WAI-ARIA-code gebruikt: aria-haspopup
.
aria-haspopup
In de <span> met de gemarkeerde woorden wordt aria-haspopup
gebruikt:
<span class="markeer" aria-haspopup="true">
In Internet Explorer 11 en Edge op touchscreens opent de pop-up bij aanraking niet. Of hij opent pas na een hele tijd. Of het contextuele menu wordt geopend. 'n Soort loterij. Kortom: enorme kommer en kwel. Door het toevoegen van aria-haspopup="true"
opent de pop-up gewoon.
Volgens de WAI-ARIA-specificatie 1.0 kan met aria-haspopup="true"
worden aangegeven dat het element een contextueel menu of een submenu heeft. Microsoft gebruikt dit attribuut dus voor iets, waar het niet voor is bedoeld.
In versie 1.1 van de specificatie is de waarde 'true' bij aria-haspopup
vervallen, maar wordt vanwege terugwaartse compatibiliteit met versie 1.0 nog wel gedefinieerd op eenzelfde wijze als in versie 1.0. Hiermee lijken mogelijke toekomstige problemen voor dit oneigenlijke gebruik te worden voorkomen. Versie 1.2 is nog een ontwerp-specificatie, maar ook hierin is dit hetzelfde.
Tabindex en Tab-toets
Links, invoervelden in formulieren, en dergelijke kunnen met behulp van de Tab-toets (of een soortgelijke toets) één voor één worden bezocht, in de volgorde waarin ze in de html voorkomen. Shift+Tab-toets keert de volgorde van de Tab-toets om. Dit is een belangrijk hulpmiddel voor mensen die om een of andere reden de muis niet kunnen of willen gebruiken. (En het is vaak ook veel sneller dan de muis, vooral in formulieren.)
In sommige browsers en/of besturingssystemen is dit vreemd genoeg standaard uitgeschakeld en is een zoektocht in de instellingen nodig om dit aan te zetten. Maar gebruikers van de Tab-toets zullen dit al hebben gedaan.
Als je met behulp van de Tab-toets een element hebt bereikt, heeft dit 'focus': als het een link is en je drukt op Enter, wordt de link gevolgd. Bij een tekstveld kun je tekst gaan invoeren. Enzovoort.
De Tab-toets volgt normaal genomen de volgorde van de elementen in de html. Het maakt niet uit, in welke volgorde ze op het scherm staan. Als je met behulp van css de elementen van plaats verwisselt op het scherm, wordt toch gewoon de volgorde in de html gevolgd.
De volgorde van de Tab-toets kan worden veranderd met behulp van het tabindex
-attribuut: <div tabindex="3">
. Deze <div> zal nu als derde worden bezocht, ook al krijgt een simpele <div> normaal genomen nooit bezoek van de Tab-toets.
Normaal genomen is het gebruik van een tabindex niet nodig. Het is zeker niet bedoeld om de bezoeker als een kangoeroe op een hindernisbaan van onder via links over rechts naar boven te laten springen. Maar soms kan het handig zijn voor kleinere correcties, als de normale volgorde in de html niet optimaal is. Of om een element bereikbaar te maken voor de Tab-toets, zoals de hierboven genoemde <div>.
Schermlezers blijven altijd de volgorde van de html volgen, dus als de tabindex sterk afwijkt van de volgorde in de html, kan dat behoorlijk verwarrend zijn.
De tabindex kan drie verschillende waarden hebben: -1, 0 of een positief getal.
In principe is de volgorde bij gebruik van de Tab-toets als volgt: eerst worden alle positieve getallen in volgorde afgewerkt. Als twee tabindexen dezelfde waarde hebben, wordt de volgorde in de html aangehouden. Een waarde van '0' wordt, afhankelijk van browser en besturingssysteem, verschillend behandeld, waarover iets hieronder bij Tabindex="0" meer.
tabindex="-1"
Een negatieve waarde van -1 zorgt ervoor dat het element volledig wordt genegeerd door de Tab-toets. Zelfs een link met een negatieve tabindex wordt volledig genegeerd. Normaal genomen heeft een tabindex="-1"
maar één nut: je kunt dan met behulp van JavaScript toch focus aan het element geven, zonder dat gebruikers van de Tab-toets erdoor worden gehinderd.
In dit voorbeeld wordt tabindex="-1"
niet gebruikt.
tabindex="0"
Volgens de specificatie van html 4.01 moest een tabindex="0"
pas worden bezocht, nadat tabindexen met een positief nummer waren bezocht. Sommige browsers hielden zich hier echter niet aan: een tabindex="0"
werd gewoon tussen de positieve tabindexen gezet.
In html5 is de situatie nog fijner. Nu staat er alleen dat, wat betreft de volgorde, de gewoonte van het platform wordt gevolgd. Oftewel: doe maar raak. Maar hoe dan ook: als je tabindex="0"
gebruikt, kan een element focus krijgen met behulp van de Tab-toets. Ook als dat element normaal genomen geen focus kan krijgen.
In dit voorbeeld wordt tabindex="0"
gebruikt om te zorgen dat een <span> focus kan krijgen:
<span class="pict" tabindex="0">
Hierdoor kunnen gebruikers van de Tab-toets deze <span> focus geven, waarna de bijbehorende afbeelding kan worden getoond.
tabindex="..."
Op de plaats van de puntjes moet een positief getal worden ingevuld: het volgnummer. Positieve tabindexen worden in dit voorbeeld niet gebruikt.
Muis, toetsenbord, touchpad en touchscreen
Vroeger, toen het leven nog mooi was en alles beter, waren er alleen monitors. Omdat kinderen daar niet af konden blijven met hun tengels, besloten fabrikanten dan maar touchscreens te gaan maken, omdat je die mag aanraken. Het bleek makkelijker te zijn om volwassenen ook te leren hoe je 'n scherm vies maakt, dan om kinderen te leren met hun vingers van de monitor af te blijven.
Zo ontstonden touchscreens en kreeg het begrip ellende een geheel nieuwe lading. In de perfecte wereld van vroeger, waarin alleen desktops bestonden, werkten dingen als hoveren, klikken en slepen gewoon. Zonder dat je eerst 'n cursus hogere magie op Zweinstein hoefde te volgen. Zelfs in JavaScript was het nog wel te behappen, ook voor mensen zoals ik die toevallig niet Einstein heten.
Op dit moment kun je computerschermen ruwweg in twee soorten indelen: schermen die worden aangeraakt, en schermen die worden bediend met hulpmiddelen als een toetsenbord, muis of touchpad. Omdat ook computerschermen zich kennelijk vermengen, bestaan er inmiddels ook schermen die zowel van aanraken als van muizen houden.
Hieronder staat een lijstje met dingen die zijn aangepast voor de verschillende soorten schermen, zodat dit voorbeeld overal werkt. Een touchpad werkt ongeveer hetzelfde als een muis. Als hieronder iets over een muis staat, geldt dit ook voor een touchpad.
:hover
Omdat :hover
mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :hover
tonen.
In dit voorbeeld is dit niet van belang, want de afbeeldingen geven alleen maar wat aanvullende informatie. Bovendien worden de afbeeldingen allemaal getoond, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd.
Je hovert over een element, als je met behulp van muis of touchpad de cursor boven dat element brengt. Hoveren kan over álle elementen. Het wordt veel gebruikt om iets van uiterlijk te laten veranderen, een pop-up te laten verschijnen, en dergelijke.
Bij gebruik van een muis is er een verschil tussen hoveren en klikken, maar op een touchscreen is dat verschil er niet: je raakt een touchscreen aan of niet. Dat levert vooral soms problemen op, als bij een element :hover
én klikken worden gebruikt, zoals bij een link die bij hoveren erover verkleurt. Omdat deze combinatie niet wordt gebruikt in dit voorbeeld, spelen deze problemen niet. Een aanraking op een touchscreen werkt in dit geval hetzelfde als hoveren met een muis.
Alleen op iOS levert dit problemen op. Als je een gemarkeerd woord aanraakt, worden de illustraties alleen gewoond in Firefox, Opera Mini en Microsoft Edge. In andere browsers worden de illustraties stomweg niet getoond. Om dit op te lossen, wordt een klein stukje JavaScript gebruikt.
Omdat een iPad of iPhone zonder JavaScript weinig meer is dan een duur en groot uitgevallen horloge, zal JavaScript vrijwel nooit uitstaan. In steeds meer mobiele browsers kan JavaScript bovendien helemaal niet worden uitgezet.
:focus
Omdat :focus
mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :focus
tonen.
In dit voorbeeld is dit niet van belang, want de afbeeldingen geven alleen maar wat aanvullende informatie. Bovendien worden de afbeeldingen allemaal getoond, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd.
De meeste mensen gaan met een muis naar een link, invoerveld, en dergelijke. Waarna ze vervolgens klikken om de link te volgen, tekst in te voeren, of wat ze ook maar willen doen.
Er is echter 'n tweede manier om naar links, invoervelden, en dergelijke te gaan: met behulp van de Tab-toets kun je naar links, invoervelden, en dergelijke 'springen'. (Over het gebruik van de Tab-toets staat meer bij Tabindex en Tab-toets.)
Waar je staat, wordt door alle browsers aangegeven met een of ander kadertje. De link en dergelijke met het kadertje eromheen 'heeft focus'. Dat wil zeggen dat je die link volgt, als je op de Enter-toets drukt, of dat je in dat veld tekst kunt gaan invoeren, enzovoort.
Het kadertje dat de focus aangeeft, moet nooit zonder meer worden weggehaald. Gebruikers van de Tab-toets hebben dan geen idee meer, waar ze zijn.
In dit voorbeeld is voor gebruikers van de Tab-toets een lege <span> aangebracht tussen elke gemarkeerde tekst en de bijbehorende afbeelding:
<span class="pict" tabindex="0">
Hierdoor kunnen de afbeeldingen ook bij gebruik van de Tab-toets worden getoond. Maar omdat deze <span> leeg is, staat er geen kadertje rondom de <span>, als deze focus heeft. Het is daardoor niet duidelijk, bij welk gemarkeerd woord een afbeelding hoort.
Daarom wordt met behulp van de pseudo-class :focus-within
een kadertje rondom de bij de afbeelding horende gemarkeerde woorden getekend. Voor browsers die :focus-within
niet ondersteunen, wordt dat kadertje met behulp van wat JavaScript getekend.
:active
Omdat :active
mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :active
tonen.
Een element is actief, als de muis wordt ingedrukt boven dat element. Op sommige touchscreens is het element actief, als het wordt aangeraakt. :active
wordt niet gebruikt in dit voorbeeld.
Gegenereerde code
Het onderstaande geldt alleen voor desktopbrowsers. In browsers op mobiele systemen is het vaak ook mogelijk gegenereerde code te bekijken, maar dat is veel ingewikkelder. Bovendien verandert de manier, waarop dat kan, nogal snel.
Als je html schrijft, kan dat (hopelijk) in de browser worden weergegeven. Vanuit de browser kun je die html bekijken, precies zoals je hem hebt ingevoerd. Alsof je het in een editor ziet. In Firefox bijvoorbeeld kan dat door in het menu te kiezen voor Extra → Webontwikkelaar → Paginabron. (Of door de veel snellere sneltoets Ctrl+U.) Elke browser heeft dit soort mogelijkheden.
Wat je dan te zien krijgt, is exact de code, zoals jij die hebt ingetypt. Inclusief alle fouten, hoofd- en kleine letters, noem maar op. Als je zo slordig bent om een <p> niet af te sluiten, zit er niet plotsklaps een afsluitende </p> in de code. Als er css wordt gebruikt, html wordt ingevoegd via JavaScript, noem maar op, zie je daar niets van, want dat heb jij niet ingetypt.
Daar heb je dus eigenlijk vrij weinig aan, want die code kende je al. Die heb je zelf 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 is te werken.
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 Edge open je dit door op F12 te drukken, en het kan vast ook via het menu.
Houdt er wel rekening mee dat elke browser de door jou ingetypte code iets zal aanpassen. In Firefox bijvoorbeeld wordt een <P> veranderd in een <p>. Als er 'n </p> mist, is die opeens wel aanwezig in de gegenereerde code. Wat elke browser precies aanpast, zal iets verschillen en kan ook nog veranderen. In het verleden veranderde Internet Explorer bijvoorbeeld een <p> juist in een <P>, nu is dat niet meer zo.
De code aanpassen aan je eigen ontwerp
- Als je dit voorbeeld gaat aanpassen voor je eigen site, houd het dan in eerste instantie zo eenvoudig mogelijk. Ga vooral geen details invullen.
-
Gebruik geen FrontPage, Publisher of Word (alle drie van Microsoft). Deze programma's maken niet-standaard code die alleen goed te bekijken is in Internet Explorer. In alle andere browsers zie je grotendeels bagger, áls je al iets ziet.
Publisher en Word zijn niet bedoeld om websites mee te maken. FrontPage is zwaar verouderd en wordt al jaren niet meer onderhouden door Microsoft.
Ook OpenOffice en LibreOffice leveren een uiterst beroerd soort html af. Tekstverwerkers met al hun toeters en bellen zijn gewoon niet geschikt om websites mee te bouwen.
Je kunt beter een goed (gratis) programma gebruiken. Links naar dat soort programma's vind je op de pagina met links onder Gereedschap → wysiwyg-editor..
Maar het allerbeste is om gewoon zelf html, css, enzovoort te leren, omdat zelfs het allerbeste programma het nog steeds zwaar verliest van 'n op de juiste manier met de hand gemaakte pagina.
-
Als je in een desktopbrowser met behulp van zoomen het beeld vergroot, heeft dit hetzelfde effect, als wanneer de pagina in een kleiner browservenster wordt getoond. Je kunt hiermee dus kleinere apparaten zoals een tablet of een smartphone simuleren. Maar het blijft natuurlijk wel een simulatie: het is nooit hetzelfde als testen op een écht apparaat. Zo kun je bijvoorbeeld aanrakingen alleen echt testen op een echt touchscreen.
Inmiddels hebben veel browsers in de ontwikkelgereedschappen mogelijkheden voor het simuleren van weergave op een kleiner scherm ingebouwd. Ook dit blijft een simulatie, maar geeft vaak wel een beter beeld dan zoomen.
-
Ik maak zelf het liefst een site in Firefox. Als je 'n site maakt in Firefox, Opera, Safari, Google Chrome of Edge, is er 'n hele grote kans dat hij in alle browsers werkt. Ik geef de voorkeur aan Firefox, omdat het de enige grote browser is die niet bij een bedrijf hoort dat vooral op je centen of je data uit is.
Google Chrome wordt ook door veel mensen gebruikt, maar ik heb dus wat moeite met hoe Google je hele surfgedrag, je schoenmaat en de kleur van je onderbroek vastlegt. Daarom gebruik ik Google Chrome zelf alleen om in te testen.
-
Het allereerste dat je moet invoeren, is het doctype, vóór welke andere code dan ook. Een lay-out met een missend of onvolledig doctype ziet er totaal anders uit dan een lay-out met een geldig doctype. Wát er anders is, verschilt ook nog 'ns tussen de diverse browsers. Als je klaar bent en dan nog 'ns 'n doctype gaat invoeren, weet je vrijwel zeker dat je van voren af aan kunt beginnen met de lay-out.
Geldige doctypes vind je op www.w3.org/QA/2002/04/valid-dtd-list.
Gebruik het volledige doctype, inclusief de eventuele url, anders werkt het niet goed.
-
Gebruik een 'strict' doctype of (beter!) het doctype voor html5. Deze zijn bedoeld voor nieuwe sites. Het transitional doctype is bedoeld voor al bestaande sites, niet voor nieuwe.
Het transitional doctype staat talloze tags toe, die in html5 zijn verboden. Deze tags worden al zo'n tien jaar afgeraden. Het transitional doctype is echt alleen bedoeld om de puinhoop van vroeger, toen niet volgens standaarden werd gewerkt, enigszins te herstellen.
Het strict doctype staat verouderde tags niet toe. Daardoor kan met 'n strict doctype, of het nu html of xhtml is, probleemloos worden overgestapt naar html5. Met een transitional doctype en het gebruik van afgekeurde tags kun je niet overstappen naar html5. Je moet dan eerst alle verouderde tags verwijderen, wat echt ontzettend veel werk kan zijn.
Het doctype voor html5 is uiterst simpel:
<!doctype html>
. Omdat het doctype voor html5 in alle browsers werkt, zelfs in de gelukkig vrijwel uitgestorven nachtmerrie Internet Explorer 6, is er geen enkele reden dit uiterst simpele doctype niet te gebruiken. - Als tweede voer je de charset in. Dit vertelt de browser, welke tekenset er gebruikt moet worden, zodat letters met accenten en dergelijke overal goed worden weergegeven. Het beste kun je utf-8 nemen. Als je later van charset verandert, loop je 'n grote kans dat je alle aparte tekens als letters met accenten weer opnieuw moet gaan invoeren. In html5 is het simpele
<meta charset="utf-8">
voldoende. -
Test vanaf het allereerste begin in zoveel mogelijk verschillende browsers in 'n aantal resoluties (schermgroottes). Onder het kopje Getest in kun je in deze uitleg vinden, waar dit voorbeeld in is getest. Ook van Internet Explorer kun je meerdere versies naast elkaar draaien. Op de pagina met links staan onder het kopjes Gereedschap → Weergave en dergelijke testen 'n aantal links die daarbij kunnen helpen. De compatibiliteitsweergave in Internet Explorer is niet geschikt om in te testen, omdat deze enigszins verschilt van de weergave in échte browsers.
(Overigens wordt op deze site alleen nog in Internet Explorer 11 getest. Oudere versies van Internet Explorer worden niet meer ondersteund en zijn daardoor per definitie uiterst onveilig. In Edge, de opvolger van Internet Explorer, wordt wel gewoon getest.)
- Voor alle voorbeelden geldt: breng veranderingen stapsgewijs aan. Als je bijvoorbeeld foto's wilt laten weergeven, begin dan met het alleen veranderen van de namen van de foto's, zodat je eigen foto's worden weergegeven. Maakt niet uit als de maten niet kloppen en de teksten fout zijn. Als dat werkt, ga dan bijvoorbeeld de maten aanpassen. Dan de teksten. En controleer steeds, of alles nog goed werkt.
-
Als het om een lay-out of iets dergelijks gaat: zorg eerst dat header, kolommen, s, menu, en dergelijke staan en bewegen, zoals je wilt. Ga daarna pas details binnen die blokken invullen. In eerste instantie gebruik je dus bijvoorbeeld 'n leeg blok op de plaats, waar uiteindelijk het menu komt te staan.
Als je begint met allerlei details, is er 'n heel grote kans dat die de werking van de blokken gaan verstoren. Bouw eerst het huis, en ga dan pas de kamers inrichten. Zorg eerst dat de blokken werken, zoals je wilt. Dan zul je het daarna gelijk merken, als 'n toegevoegd detail als tekst of 'n afbeelding iets gaat verstoren. Daarvoor moet je natuurlijk wel regelmatig controleren in verschillende browsers, of alles nog wel goed werkt.
Je kunt de blokken tijdens het aanpassen opvullen met bijvoorbeeld <br>1<br>2<br>3 enzovoort, tot ze de juiste hoogte hebben. Het is handig om aan het einde even iets toe te voegen als 'laatste', zodat je zeker weet dat er niet ongemerkt drie regels onderaan naar 't virtuele walhalla zijn verhuisd.
Om de breedte te vullen, kun je het best 'n kort woord als 'huis' duizend keer of zo herhalen. Ook hier is het handig om aan 't eind (en hier ook aan 't begin) 'n herkenningsteken te maken, zodat je zeker weet dat je de hele tekst ziet.
- Zolang je in grotere dingen zoals 'n lay-out aan 't wijzigen bent, kan het helpen de verschillende delen een achtergrondkleur te geven. Je ziet dan goed, waar 'n deel precies staat. Een achtergrondkleur heeft – anders dan bijvoorbeeld een border – verder geen invloed op de lay-out, dus die is hier heel geschikt voor.
- Als je eigenschappen verandert in de css, verander er dan maar één, hooguit twee tegelijk. Als je er zeventien tegelijk verandert, is de kans groot dat je niet meer weet, wat je hebt gedaan. En dat je 't dus niet meer terug kunt draaien.
-
margin
,padding
enborder
worden bij de hoogte en breedte van het element opgeteld. Hier worden vaak fouten mee gemaakt. Als je bijvoorbeeld in een lay-out 'n border toevoegt aan een van de 'hoofdvakken' (header, footer, kolommen), dan wordt deze er bij opgeteld. Bij 'n border van 2 px rondom de linkerkolom wordt deze dus plotseling 4 px breder (2 aan beide kanten), en 4 px hoger. Zoiets kan je hele lay-out verstoren, omdat iets net te breed of te hoog wordt. Je moet dan elders iets 4 px kleiner maken. Dat zal vaak zo zijn: als je één maat verandert, zul je vaak ook 'n andere moeten aanpassen.Css geeft de mogelijkheid om met behulp van
box-sizing
de padding en border bínnen de breedte en hoogte van de inhoud te zetten, als je dat handiger vindt.Met nieuwere css-eigenschappen als grid en flexbox, die speciaal zijn gemaakt om een lay-out mee te maken, spelen dit soort problemen veel minder. Maar hier moet je weer goed op de ondersteuning door browsers letten, want niet elke browser ondersteunt al alles van deze eigenschappen, en zeker niet foutloos.
-
In plaats van een absolute eenheid als
px
kun je ook een relatieve eenheid gebruiken, met nameem
enrem
. Voordeel vanem
enrem
is dat een lettergrootte, regelhoogte, en dergelijke inem
enrem
in alle browsers kan worden veranderd. Nadeel is dat het de lay-out sneller kan verstoren dan bijvoorbeeldpx
. Dit moet je gewoon van geval tot geval bekijken. Voor weergave in mobiele apparaten zijn relatieve eenheden alsem
enrem
vrijwel altijd beter dan absolute eenheden alspx
.(De minder bekende
rem
is ongeveer hetzelfde als deem
. Alleen is de lettergrootte bijrem
gebaseerd op de lettergrootte van het <html>-element, waardoor derem
overal op de pagina precies even groot is. Bij deem
kan de lettergrootte worden beïnvloed door de voorouders van het element, bij derem
niet.)Zoomen kan trouwens altijd, ongeacht welke eenheid je gebruikt.
-
Valideren, valideren, valideren en dan voor 't slapen gaan nog 'ns valideren.
Valiwie???
Valideren is het controleren van je html en css op 'n hele serie fouten. Computers zijn daar vaak veel beter in dan mensen. Als je 300 keer <h2> hebt gebruikt en 299 keer </h2> vindt 'n computer die ene missende </h2> zonder enig probleem. Jij ook wel, maar daarna ben je misschien wel aan vakantie toe.
Valideren kan helpen om gekmakende fouten te vinden. Valide code garandeert ook dat de weergave in verschillende browsers (vrijwel) hetzelfde is. En valide code is over twintig jaar ook nog te bekijken.
Valideren moet trouwens ook niet worden overdreven. Het is een hulpmiddel om echte fouten te vinden, meer niet. Het gaat erom dat je site goed werkt, niet dat je het braafste kind van de klas bent. Als de code niet valideert, maar daar is een goede reden voor, is daar niets op tegen. Zeker met nieuwere html en css wil de validator nog wel eens achterlopen, terwijl dat al prima is te gebruiken.
Op deze site is alle css en html gevalideerd. Als de code niet helemaal valide is (wat regelmatig voorkomt), staat daar onder Bekende problemen (en oplossingen) de reden van.
Je kunt je css en html valideren als 't online staat, maar ook als het nog in je computer staat.
Html kun je valideren op: validator.w3.org/nu.
Css kun je valideren op: jigsaw.w3.org/css-validator.
Toegankelijkheid en zoekmachines
De tekst in dit hoofdstukje is een algemene tekst, die voor elke pagina geldt. Eventueel specifiek voor dit voorbeeld geldende problemen en eventuele aanpassingen om die problemen te voorkomen staan bij Bekende problemen (en oplossingen).
Toegankelijkheid (in het Engels 'accessibility') is belangrijk voor bijvoorbeeld blinden die een schermlezer gebruiken, of voor motorisch gehandicapte mensen die moeite hebben met het bedienen van een muis. Een spider van een zoekmachine (dat is het programmaatje dat de site indexeert voor de zoekmachine) is te vergelijken met een blinde. Als je je site goed toegankelijk maakt voor gehandicapten, is dat gelijk goed voor een hogere plaats in een zoekmachine. Dus als je 't niet uit sociale motieven wilt doen, kun je 't uit egoïstische motieven doen.
(Op die plaats in de zoekmachine heb je maar beperkt invloed. De toegankelijkheid van je site is maar één van de factoren, maar zeker niet onbelangrijk.)
Als je bij het maken van je site al rekening houdt met toegankelijkheid, is dat nauwelijks extra werk. 't Is ongeveer te vergelijken met inbraakbescherming: doe dat bij 'n nieuw huis en 't is nauwelijks extra werk, doe 't bij 'n bestaand huis en 't is al snel 'n enorme klus.
Enkele tips die helpen bij toegankelijkheid:
-
Gebruik altijd een alt-beschrijving bij een afbeelding. De alt-tekst wordt gebruikt, als afbeeldingen niet kunnen worden getoond of gezien (dat geldt dus ook voor zoekmachines). Als je iets wilt laten zien, als je over de afbeelding hovert, gebruik daar dan het title-attribuut voor, niet de alt-beschrijving.
Als een afbeelding alleen maar voor de sier wordt gebruikt, zet je daarbij
alt=""
, om aan te geven dat de afbeelding niet belangrijk is voor het begrijpen van de tekst of zo. - Als uit de tekst in een link niet duidelijk wordt, waar de link naartoe leidt, gebruik dan een title bij de link. Een tekst als 'pagina met externe links' is waarschijnlijk duidelijk genoeg, een tekst als alleen 'links' mogelijk niet. Een duidelijke zwart-witregel is niet te geven, omdat dit ook van tekst en dergelijke in de omgeving van de link afhangt.
-
Accesskeys (sneltoetsen) kun je beter niet gebruiken, deze geven te veel problemen, omdat ze vaak dubbelop zijn met sneltoetsen voor de browser of andere al gebruikte sneltoetsen. Bovendien is voor de gebruiker meestal niet duidelijk, welke toetsen het zijn.
Op zichzelf zijn accesskeys een heel goed idee. Maar helaas zijn ze ook in html5 volstrekt onvoldoende gedefinieerd. Er is nog steeds geen standaard voor de meest gebruikelijke accesskeys, zoals Zoek of Home.
Er is nog steeds niet vastgelegd, hoe accesskeys zichtbaar gemaakt kunnen worden. Voor de makers van browsers zou dit 'n relatief kleine moeite zijn, voor de makers van 'n site is het bergen extra werk.
Hierdoor zijn accesskeys (vrijwel) niet te gebruiken. Misschien kunnen ze nog enig nut hebben op sites, die gericht zijn op 'n specifieke groep gebruikers. Maar voor algemene sites is het advies: normaal genomen niet gebruiken.
-
Met behulp van de Tab-toets (of op 'n soortgelijke manier) kun je in de meeste browsers door links, invoervelden, en dergelijke lopen. Elke tab brengt je één link, invoerveld, en dergelijke verder, Shift+Tab één plaats terug. Met behulp van het attribuut
tabindex
kun je de volgorde aangeven, waarin de Tab-toets werkt. Zondertabindex
wordt de volgorde van de html aangehouden bij gebruik van de Tab-toets, maar soms is een andere volgorde logischer.In principe is het beter, als
tabindex
niet nodig is, maar gewoon de volgorde van de html wordt aangehouden. Bij verkeerd gebruik kantabindex
heel verwarrend zijn. Het is niet bedoeld om van de pagina een hindernisbaan voor kangoeroes te maken, waarop van beneden via links over rechts naar boven wordt gesprongen. - Als, zoals hierboven beschreven, een gebruiker van de Tab-toets bij een link, invoerveld, en dergelijke is aangekomen, heeft dit element 'focus'. Dit wordt aangegeven door de link, invoerveld, en dergelijke extra te markeren met een kadertje. Dat kadertje mag je alleen weghalen, als op een andere manier wordt duidelijk gemaakt, welk element focus heeft. Een gebruiker van de Tab-toets kan anders niet zien, waar zij of hij zit, en welk element gaat reageren op bijvoorbeeld een Enter.
- In het verleden werd vaak aangeraden de volgorde van de code aan te passen. Een menu bijvoorbeeld kon in de html onderaan worden gezet, terwijl het op het scherm met behulp van css bovenaan werd gezet. Inmiddels zijn schermlezers en dergelijke zo sterk verbeterd dat dit niet meer wordt aangeraden. De volgorde in de html kan tegenwoordig beter hetzelfde zijn als die op het scherm, omdat het anders juist verwarrend kan werken.
-
Een zogenaamde skip-link is vaak nog wel zinvol. Dat is een link die je buiten het scherm parkeert met behulp van css, zodat hij normaal genomen niet te zien is. Zo'n link is wel gewoon zichtbaar in speciale programma's zoals tekstbrowsers en schermlezers, want die kijken gewoon naar wat er in de broncode staat. (Alleen in de schermlezer TalkBack op Android werkt zo'n buiten het scherm geplaatste link niet. TalkBack leest zo'n link wel voor, maar de link kan niet worden gevolgd, als deze buiten het scherm staat.)
Een skip-link staat bovenaan de pagina, nog boven menu, header, en dergelijke, en linkt naar de eigenlijke inhoud van de pagina. Hierdoor kunnen mensen met één toetsaanslag naar de eigenlijke inhoud van de pagina gaan.
Een skip-link is vooral nuttig voor gebruikers van de Tab-toets. Zodra de normaal genomen onzichtbare link door het indrukken van de Tab-toets focus krijgt, kun je hem op het scherm plaatsen, waardoor hij zichtbaar wordt. Bij een volgende tab wordt hij dan weer buiten het scherm geplaatst en is dus niet meer zichtbaar, zodat de lay-out niet wordt verstoord.
Op pagina's en in voorbeelden waar dat nuttig is, wordt op deze site een skip-link gebruikt. (Althans: nog niet in alle voorbeelden die daarvoor in aanmerking komen, zit een skip-link. Maar geleidelijk aan worden dat er steeds meer.)
-
Van oorsprong is html een taal om wetenschappelijke documenten weer te geven, pas later is hij gebruikt voor lay-out. Maar daar is hij dus eigenlijk nooit voor bedoeld geweest. Het gebruiken van html voor lay-out leidt tot enorme problemen voor gehandicapten en tot een lage plaats in zoekmachines.
De html hoort alleen inhoud te bevatten, lay-out doe je met behulp van css. Die css moet in een externe stylesheet staan of, als hij alleen voor één bepaalde pagina van toepassing is, in de <head> van die pagina.
-
Breng een logische structuur aan in je document. Gebruik een <h1> voor de belangrijkste kop, een <h2> voor een subkop, enzovoort. Schermlezers en dergelijke kunnen van kop naar kop springen. En een zoekmachine gaat ervan uit dat <h1> belangrijke tekst bevat.
Dit geldt voor al dit soort structuurbepalende tags.
Als een <h1> te grote letters geeft, maak daar dan met behulp van je css 'n kleinere letter van, maar blijf die <h1> gewoon gebruiken. Op dezelfde manier kun je al dit soort dingen oplossen.
- <table> is fantastisch, maar alleen als die wordt gebruikt om een echte tabel weer te geven, niet als hij voor opmaak wordt misbruikt. In het verleden is dat op grote schaal gebeurd bij gebrek aan andere mogelijkheden. Een tabel is, als je niet heel erg goed oplet, volstrekt ontoegankelijk voor gehandicapten en zoekmachines. Het lezen van een tabel is ongeveer te vergelijken met het lezen van een krant van links naar rechts: niet per kolom, maar per regel. Dat gaat dus alleen maar goed bij een echte tabel, zoals een spreadsheet. In alle andere gevallen garandeert 'n tabel volstrekte ontoegankelijkheid voor schermlezers en dergelijke en als extra bonus vaak 'n lagere plaats in een zoekmachine.
-
Frames horen bij een volstrekt verouderde techniek, die heel veel nadelen met zich meebrengt. <iframe>'s hebben voor een deel dezelfde nadelen. Eén van die nadelen is dat de verschillende frames voor zoekmachines, schermlezers, en dergelijke als los zand aan elkaar hangen, omdat ze los van elkaar worden weergegeven. Ze staan wel naast elkaar op het scherm, maar er zit intern geen verband tussen.
Als je 'n stuk code vaker wilt gebruiken, zoals 'n menu dat op elke pagina hetzelfde is, voeg dat dan in met PHP. Dan wordt de pagina niet pas in de browser, maar al op de server samengesteld. Hierdoor zien zoekmachines, schermlezers, en dergelijke één pagina, net zoals wanneer je maar één pagina met html zou hebben geschreven.
(Je kunt ook invoegen met behulp van SSI (Server Side Includes). Maar tegenwoordig kun je beter PHP dan SSI gebruiken, omdat SSI min of meer aan het uitsterven is en PHP veel meer mogelijkheden heeft. Op deze site wordt in enkele voorbeelden nog SSI gebruikt, maar zodra die worden bijgewerkt, gaat dat vervangen worden door PHP.)
- Geef de taal van het document aan, en bij woorden en dergelijke die afwijken van die taal de afwijkende taal met behulp van
lang="..."
. Op deze site gebeurt dat maar af en toe, omdat de tekst (en vooral de code) een mengsel is van Engels, Nederlands en eigengemaakte namen. Dat soort teksten is gewoon niet goed in te delen in een taal. Maar bij enigszins 'normale' teksten hoor je een taalwisseling aan te geven. - Gebruik de tag <abbr> bij afkortingen. Doe dat de eerste keer op een pagina samen met de title-eigenschap:
<abbr title="ten opzichte van">t.o.v.</abbr>
. Daarna kun je op dezelfde pagina volstaan met<abbr>t.o.v.</abbr>
. Doe je dit niet, dan is er 'n grote kans dat 'n schermlezer 't.o.v.' uit gaat spreken als 'tof', en 'n zoekmachine kan er ook geen chocola van maken. - Geef een verandering niet alleen door kleur aan. Een grote groep mensen heeft moeite met het onderscheiden van kleuren en/of het herkennen van kleuren. Verander bijvoorbeeld een ronde rode knop niet in een ronde groene knop, maar in een vierkante groene knop. Door ook de vorm te veranderen, is het herkennen van de verandering niet alleen van een kleur afhankelijk.
- Zorg voor voldoende contrast tussen achtergrond- en voorgrondkleur, tussen
background-color
encolor
. Soms zie je heel lichtgrijze tekst op een donkergrijze achtergrond, en dan ook nog in een mini-formaat. Dat is dus voor heel veel mensen stomweg volledig onleesbaar. Een uitstekende online contrastchecker is bijvoorbeeld te vinden op snook.ca. -
De spider van 'n zoekmachine, schermlezers, en dergelijke kunnen geen plaatjes 'lezen'. Het is soms verbazingwekkend om te zien hoe veel, of eigenlijk: hoe weinig tekst er overblijft op een pagina, als de plaatjes worden weggehaald. Hetzelfde geldt voor die fantastisch mooie flash-pagina's, als daarbij geen voorzieningen voor dit soort programma's zijn aangebracht. (Omdat flash wordt uitgefaseerd en op steeds minder machines is te bekijken, zijn flash-pagina's hoe dan ook geen goed idee meer.)
Op Linux kun je met Lynx kijken, hoe je pagina eruitziet zonder plaatjes en dergelijke, als echt alleen de tekst overblijft. Een installatie-programma voor Lynx op Windows is te vinden op invisible-island.net/lynx.
Ook kun je in Windows het gratis programma WebbIE installeren. WebbIE laat de pagina zien, zoals een tekstbrowser en dergelijke hem zien. WebbIE is te downloaden vanaf www.webbie.org.uk. (LET OP: kies voor 'Install WebbIE 4 Web Browser Now'. Dat is – op het moment van schrijven – de een na bovenste knop. Als je voor de bovenste download kiest, krijg je 'n hele berg hulpprogramma's erbij, waar je voor het testen niets aan hebt.)
-
Ten slotte kun je je pagina nog online op toegankelijkheid laten controleren op 'n behoorlijk aantal sites, zoals:
lowvision.support: laat zien hoe een kleurenblinde de site ziet. Engelstalig.
wave.webaim.org: deze laat grafisch zien, hoe de toegankelijkheid is. Engelstalig. Deze tester is ook als extensie in Firefox en Google Chrome te installeren.
Op de pagina met links kun je onder Toegankelijkheid links naar meer tests en dergelijke vinden.
Getest in
Laatst gecontroleerd op 28 mei 2019.
Onder dit kopje staat alleen maar, hoe en waarin is getest. Alle eventuele problemen, ook die met betrekking tot zoomen, lettergroottes, toegankelijkheid, uitstaan van JavaScript en/of css, enzovoort staan iets hieronder bij Bekende problemen (en oplossingen). Het is belangrijk dat deel te lezen, want uit een test kan ook prima blijken dat iets totaal niet werkt!
Dit voorbeeld is getest op de volgende systemen:
Desktopcomputers
Windows 7 (1280 x 1024 px, resolution 96 ppi):
Firefox, UC Browser, Google Chrome, Opera en Internet Explorer 11, in grotere en kleinere browservensters.
OS X 10.11.6 ('El Capitan') (1680 x 1050 px, resolution: 96: ppi, device-pixel-ratio: 1):
Firefox, Safari, Opera en Google Chrome, in grotere en kleinere browservensters.
Linux (Kubuntu 18.04 LTS, 'Bionic Beaver') (2560 x 1080 px, resolution: 96 ppi):
Firefox, Opera en Google Chrome, in grotere en kleinere browservensters.
Laptops
Windows 8.1 (1366 x 768 px, resolution: 96 ppi):
Bureaublad-versie: Firefox, UC Browser, Google Chrome, Opera en Internet Explorer 11, in grotere en kleinere browservensters.
Startscherm-versie: Internet Explorer 11.
Windows 10 (1600 x 900 px, resolution: 96 ppi):
Firefox, UC Browser, Google Chrome, Opera, Internet Explorer 11 en Edge, in grotere en kleinere browservensters.
Tablets
iPad met iOS 9.3.5 (1024 x768 px, device-pixel-ratio: 1):
Safari, Chrome for iOS, UC Browser, Firefox (alle portret en landschap).
Opera Mini (Opera Turbo) portret en landschap.
iPad met iOS 12.3.1 (2048 x 1536 px, device-pixel-ratio: 2 ('retina'):
Safari, Chrome for iOS, Firefox, Microsoft Edge (alle portret en landschap).
Opera Mini (Opera Turbo) portret en landschap.
Android 4.4.2 ('Kitkat') (1280 x 800 px, resolution: 96 ppi):
UC Browser, Firefox en Chrome (alle portret en landschap).
Android 4.4.2 ('Kitkat') (2560 x 1600 px, resolution: 192 ppi):
Android browser, UC Browser, Firefox en Chrome (alle portret en landschap).
Android 6.0 ('Marshmallow') (1920 x 1200 px, resolution: 144 ppi):
Dolphin, Samsung Internet, UC Browser, Firefox en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Android 8.1.0 ('Oreo') (1920 x 1200 px, resolution: 144 ppi):
Dolphin, Samsung Internet, UC Browser, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Smartphones
Windows 10 Mobile (1280 x 720 px, resolution: 192 ppi):
Edge en UC browser (portret en landschap).
Android 4.1.2 ('Jelly Bean') (800 x 480 px, resolution: 144 ppi):
Chrome, UC Browser, Firefox en Opera for Android (alle portret en landschap).
Android 8.1.0 ('Oreo') (1280 x 720 px, resolution: 192 ppi):
Dolphin, Samsung Internet, UC Browser, Firefox, Microsoft Edge en Chrome (alle portret en landschap).
Opera Mini (besparingen uitgeschakeld) portret en landschap.
Er is op de aan het begin van dit hoofdstukje genoemde controledatum getest in de meest recente versie van de browser, die op het betreffende besturingssysteem kon draaien. Het aantal geteste browsers en systemen is al tamelijk fors, en als ook nog rekening gehouden moet worden met (zwaar) verouderde browsers, is het gewoon niet meer te doen. Surfen met een verouderde browser is trouwens vragen om ellende, want updates van browsers hebben heel vaak met beveiligingsproblemen te maken.
In- en uitzoomen en – voor zover de browser dat kan – een kleinere en grotere letter zijn ook getest. Er is ingezoomd en vergroot tot zover de browser kan, maar niet verder dan 200%.
Er is getest met behulp van muis en toetsenbord, behalve op iOS, Android en Windows 10 Mobile, waar een touchscreen is gebruikt. Op Windows 8.1 en 10 is getest met touchscreen, touchpad, toetsenbord, muis, en – waar dat zinvol was – op een combinatie daarvan.
Als JavaScript is gebruikt, is op de desktop ook getest zonder JavaScript. Op iOS, Android en Windows 10 Mobile is niet getest zonder JavaScript, omdat je JavaScript in een toenemend aantal mobiele browsers niet uit kunt zetten. Bovendien is een mobiel apparaat zonder JavaScript niet veel meer dan een duur en groot uitgevallen horloge. Ook in Edge is niet getest zonder JavaScript, omdat Microsoft het onmogelijk heeft gemaakt dit uit te zetten. Ten slotte is getest zonder css en – als afbeeldingen worden gebruikt – zonder afbeeldingen.
Schermlezers en dergelijke.
Naast deze 'gewone' browsers is ook getest in Lynx, WebbIE, NVDA, TalkBack, VoiceOver, ChromeVox en Verteller.
Lynx is een browser die alleen tekst laat zien en geen css gebruikt. Er is getest op Linux.
WebbIE. is een browser die gericht is op mensen met een handicap. Er is getest op Windows7. (LET OP: kies voor 'Install WebbIE 4 Web Browser Now'. Dat is – op het moment van schrijven – de een na bovenste knop. Als je voor de bovenste download kiest, krijg je 'n hele berg hulpprogramma's erbij, waar je voor het testen niets aan hebt.)
NVDA is een schermlezer, zoals die door blinden wordt gebruikt. Er is getest op Windows 7 en Windows 10 in combinatie met Firefox.
TalkBack is een in Android ingebouwde schermlezer. Er is getest in combinatie met Chrome op Android 4.4,2, 6.0, 7.0 en 8.1.0.
VoiceOver is een in iOS en OS X ingebouwde schermlezer. Er is getest in combinatie met Safari op iOS (9.3.5 en 12.3) en OS X 10.11.6.
ChromeVox is een schermlezer in de vorm van een extensie bij Google Chrome. Er is getest op een systeem met Kubuntu Linux 18.04.
Verteller (Narrator) is een in Windows 10 ingebouwde schermlezer. Er is getest in combinatie met Edge.
(Voor de bovenstaande programma's zijn links naar sites met uitleg en dergelijke te vinden op de pagina met links onder Toegankelijkheid → Schermlezers, tekstbrowsers, en dergelijke.)
Als het voorbeeld in deze programma's toegankelijk is, zou het in principe toegankelijk moeten zijn in alle aangepaste browsers en dergelijke. En dus ook voor zoekmachines, want een zoekmachine is redelijk vergelijkbaar met een blinde.
Eventuele problemen in schermlezers (en eventuele aanpassingen om die te voorkomen) staan iets hieronder bij Bekende problemen (en oplossingen).
Alleen op de hierboven genoemde systemen en browsers is getest. Er is dus niet getest op bijvoorbeeld 'n Blackberry. Er is een kans dat dit voorbeeld niet (volledig) werkt op niet-geteste systemen en apparaten. Om het wel (volledig) werkend te krijgen, zul je soms (kleine) wijzigingen en/of (kleine) aanvullingen moeten aanbrengen, bijvoorbeeld met JavaScript.
Er is ook geen enkele garantie dat iets werkt in een andere tablet of smartphone dan hierboven genoemd, omdat fabrikanten in principe de software kunnen veranderen. Dit is anders dan op de desktop, waar browsers altijd (vrijwel) hetzelfde werken, zelfs op verschillende besturingssystemen. Iets wat in Samsung Internet op Android werkt, zal in de regel overal werken in die browser, maar een garantie is er niet. De enige garantie is het daadwerkelijk testen op een fysiek apparaat. En aangezien er duizenden mobiele apparaten zijn, is daar geen beginnen aan.
De html is gevalideerd met de validator van w3c, de css ook. Als om een of andere reden niet volledig gevalideerd kon worden, wordt dat bij Bekende problemen (en oplossingen) vermeld.
Nieuwe browsers worden pas getest, als ze uit het bèta-stadium zijn. Anders is er 'n redelijke kans dat je tegen 'n bug zit te vechten, die voor de uiteindelijke versie nog gerepareerd wordt. Dit voorbeeld is alleen getest in de hierboven met name genoemde browsers. Vragen over niet-geteste browsers kunnen niet worden beantwoord, en het melden van fouten in niet-geteste browsers heeft ook geen enkel nut. (Melden van fouten, problemen, enzovoort in wel geteste browsers: graag! Dat kan op het forum.)
Bekende problemen (en oplossingen)
Waarop en hoe is getest, kun je gelijk hierboven vinden bij Getest in.
Als je hieronder geen oplossing vindt voor een probleem dat met dit voorbeeld te maken heeft, kun je op het forum proberen een oplossing te vinden voor je probleem. Om forumspam te voorkomen, moet je je helaas wel registreren, voordat je op het forum een probleem kunt aankaarten.
Bij toegankelijkheid is er vaak geen goed onderscheid te maken tussen oplossing en probleem. Zonder (heel simpele) aanpassingen heb je vaak 'n probleem, en omgekeerd. Daarom staan wat betreft toegankelijkheid aanpassingen en problemen hier bij elkaar in dit hoofdstukje.
Voor zover van toepassing wordt eerst het ontbreken van JavaScript, css en/of afbeeldingen besproken. Vervolgens problemen en aanpassingen met betrekking tot toegankelijkheid voor specifieke groepen bezoekers, zoals zoomen en andere <lettergrootte, Tab-toets, tekstbrowsers en schermlezers. Als laatste volgen algemene problemen in alle of in specifieke browsers.
Als in een onderdeel één of meer problemen worden besproken, staat in een breed rood kadertje een korte samenvatting daarvan. Bij een onderwerp over toegankelijkheid zijn er soms geen problemen, maar alleen aanpassingen. In dat geval staat in een smal groen kadertje 'Geen problemen'.
Zonder JavaScript
Probleem: zonder JavaScript worden de afbeeldingen niet getoond op iOS.
Op iOS worden bij aanraken van het scherm de afbeeldingen alleen getoond in Firefox, Opera Mini en Microsoft Edge. In andere browsers worden de afbeeldingen niet getoond.
Om dit op te lossen wordt een klein stukje JavaScript gebruikt. Een groot probleem is dit niet, want zonder JavaScript is een iPad of iPhone weinig meer dan een groot en duur uitgevallen horloge. In steeds meer mobiele browsers kan JavaScript bovendien helemaal niet worden uitgeschakeld.
Probleem: in UC browser, Internet Explorer en Edge is zonder JavaScript voor gebruikers van de Tab-toets niet te zien, bij welke woorden een afbeelding hoort.
Voor gebruikers van de Tab-toets is niet duidelijk, welke afbeelding bij welke gemarkeerde woorden hoort. Dit wordt opgelost door het gebruik van pseudo-class :focus-within
, met behulp waarvan een kadertje wordt getekend om de woorden die bij de getoonde afbeelding horen.
UC browser, Internet Explorer en Edge ondersteunen :focus-within
niet. Daarom wordt dit geïmiteerd met behulp van wat JavaScript. Zonder JavaScript werkt alles gewoon, maar het kadertje ontbreekt in de genoemde browsers.
Zonder css
Geen problemen.
De afbeeldingen zijn gewone <img>'s, die worden verborgen met behulp van css. Zonder css staan de afbeeldingen gewoon in de tekst. Het ziet er niet uit, maar dat is logisch zonder css.
Zonder afbeeldingen
Geen problemen.
Het zal je verbazen, maar zonder afbeeldingen zijn er geen afbeeldingen.
Omdat de <img>'s een witte achtergrond hebben gekregen, wordt bij hoveren en dergelijke de alt-tekst getoond boven een witte achtergrond, op de plaats waar anders de afbeelding zou komen te staan.
Je zou de alt-tekst ook weg kunnen laten. Maar als een schermlezer dan op een of andere manier toch een afbeelding tegenkomt, gaat die vaak de naam van het bestand voorlezen. Als er een alt-tekst staat, wordt de alt-tekst voorgelezen.
Gebruikers Tab-toets
Probleem: in UC browser, Internet Explorer en Edge is zonder JavaScript voor gebruikers van de Tab-toets niet te zien, bij welke woorden een afbeelding hoort.
Voor gebruikers van de Tab-toets is niet duidelijk, welke afbeelding bij welke gemarkeerde woorden hoort. Dit wordt opgelost door het gebruik van pseudo-class :focus-within
, met behulp waarvan een kadertje wordt getekend om de woorden die bij de getoonde afbeelding horen.
UC browser, Internet Explorer en Edge ondersteunen :focus-within
niet. Daarom wordt dit geïmiteerd met behulp van wat JavaScript. Zonder JavaScript werkt alles gewoon, maar het kadertje ontbreekt in de genoemde browsers.
Tekstbrowsers
Geen problemen.
Lynx zet de alt-tekst bij de <img>'s binnen de gewone tekst.
WebbIE toont alleen de tekst, zonder alt-tekst.
Schermlezers
Alle geteste schermlezers lezen de tekst zonder onderbrekingen voor.
Daarvoor is wel een lege <span class="pict" tabindex="0"></span>
nodig.
In principe zou je de afbeelding ook kunnen laten openen door gebruikers van de Tab-toets, door de tabindex="0"
bij de <img> te zetten. Maar dan kondigt TalkBack op Android 8 (en mogelijk ook latere versies, maar daar wordt nog niet op getest) bij elke <img> aan: "Dubbelklik om te activeren". Als je dat 37 keer hoort tijdens het voorlezen van de tekst, wordt je daar vermoedelijk niet heel vrolijk van. Door de tabindex="0"
in een volledig lege <span> te zetten, wordt dit voorkomen.
In dit geval leveren de <img>'s nauwelijks echte informatie. Als dat wel zo zou zijn, is deze constructie volkomen ongeschikt, omdat schermlezers dan informatie gaan missen. De <img>'s hebben weliswaar een alt-tekst, maar die wordt in deze constructie niet voorgelezen. Maar ook als die alt-tekst wel zou worden voorgelezen, is dat geen goed idee, want dan wordt het voorlezen van de tekst 37 keer onderbroken.
(Er zijn twee redenen om die hele korte alt-tekst te laten staan: als de afbeeldingen niet worden geladen, wordt de alt-tekst weergegeven. En in bepaalde situaties kan een schermlezer toch de <img> noemen. Zonder alt-tekst wordt dan vaak de naam van het bestand voorgelezen.)
Zoomen en lettergroottes
Probleem: in browservensters lager dan 630 px kan de afbeelding bij inzoomen buiten het venster komen te staan.
Apparaten met zulke lage browservensters zullen voornamelijk smartphones zijn.
In browservensters lager dan 630 px worden de afbeeldingen in het midden van het venster weergegeven. Bij inzoomen (vergroten) kan tekst, en daardoor ook de afbeelding, buiten het venster komen te staan. Door te scrollen kan de afbeelding alsnog gewoon worden bekeken.
In sommige browsers kan de tekst worden vergroot. In dat geval blijft de tekst, en daarmee ook de afbeelding, gewoon binnen het browservenster staan.
Probleem: op mobiele apparaten met browservensters minimaal 630 px hoog kan bij inzoomen de afbeelding buiten het venster komen te staan.
Dit soort apparaten zullen voornamelijk tablets zijn. Als op een desktop wordt ingezoomd (vergroot), wordt bij een bepaalde vergroting overgeschakeld naar de weergave voor browservensters lager dan 630 px. Op een tablet gebeurt dit echter niet.
De afbeelding wordt altijd binnen het browservenster weergegeven met behulp van position: sticky;
. Bij inzoomen werkt dat niet meer en kan de afbeelding (gedeeltelijk) buiten het venster komen te staan. Door te scrollen kan de afbeelding alsnog gewoon worden bekeken.
Android browser en UC browser op de tablet met Android 4.12 met gewone resolutie
Probleem: de afbeeldingen worden niet getoond.
Ze weigeren gewoon iets te doen. Ook dreigen met acuut en grof geweld hielp niet. Vreemd genoeg werkt UC browser op dezelfde versie van Android wel gewoon op de tablet met dubbele resolutie.
Omdat deze versie van Android heel snel aan het uitsterven is, is hier verder niets aan geprobeerd te doen. Hierbij speelde ook een rol dat de afbeeldingen geen wezenlijke informatie toevoegen.
In het verleden werd dit op deze site vaak opgelost met een beetje extra css. Android browser en oudere versies van UC browser hadden vaak problemen met selectors waarin een +
en/of een ~
zaten. Bovenin de stylesheet werd dan de flauwekulregel
@-webkit-keyframes bugfix-0 {from {padding-left: 0;} to {padding-left: 0;}}
neergezet. Een flauwekulregel, omdat padding-left
van 0 px naar 0 px wordt veranderd.
Elders in de css stond dan de regel:
-webkit-animation: bugfix-0 infinite 1s;
Voer deze animatie eindeloos één keer per seconde uit. Door deze twee regels werkte de selector dan plotsklaps wel. Wel even zoeken naar het element, waar deze regel moet staan, want niet altijd was dat het meest voor de hand liggende element.
Dit kun je dus eventueel nog steeds doen. Op deze site wordt dit niet meer gedaan, omdat browsers met dit probleem nog nauwelijks worden gebruikt. (In oudere voorbeelden staat het vaak nog wel.)
Het vervelende van deze extra css is dat élke browser die eigenschappen met de prefix -webkit-
kan lezen deze code gebruikt. Ook browsers als Firefox, Google Chrome, Microsoft Edge en Safari voeren deze code uit, terwijl dat helemaal niet nodig is.
:focus-within valideert niet
Probleem: de css-validator van w3c geeft een foutmelding bij :focus-within
.
De pseudo-class :focus-within
is relatief nieuw. De specificatie, waarin deze pseudo-class staat, is nog pas in een ontwerpfase. In theorie zou de werking van :focus-within
daardoor nog (meer of minder) kunnen veranderen. Die kans is echter vrij klein.
In browsers die :focus-within
niet ondersteunen, wordt dit geïmiteerd met behulp van wat JavaScript. Als je alle risico's wilt uitsluiten, kun je dit script voor alle browsers laten werken:
- Verwijder uit de css de regel
.buiten:focus-within .markeer {outline: green dotted 3px;}
-
Verander in het script de regel
var focusWithin = probeer(), picts, len, x;
in
var picts, len, x;
- Verwijder uit het script de regel if
(focusWithin) return;
-
Verwijder uit het script het hele deel
function probeer() {
try {
document.querySelector(":focus-within");
} catch (error) {
return false;
}
return true;
}
Nu werkt het script in alle browsers, omdat niet meer wordt getest of :focus-within
wordt ondersteund.
UC browser op Windows en iOS en Internet Explorer
Probleem: de afbeeldingen kunnen (iets) buiten het browservenster komen te staan.
Omdat deze browsers position: sticky;
niet ondersteunen, kunnen de afbeeldingen (gedeeltelijk) buiten het browservenster komen te staan. Door scrollen kunnen ze weer binnen het venster worden gezet.
Wijzigingen
Alleen grotere wijzigingen worden hier vermeld, geen dingen als een link die is geüpdatet.
:
Nieuw opgenomen.
10 april 2009:
Tekst aangepast aan de nieuw verschenen Internet Explorer 8. De code is niet veranderd.
28 mei 2019:
- Met bijzonder groot genoegen alle aanpassingen voor Internet Explorer 10 en eerder eruit gegooid.
- xhtml omgezet naar html5.
- Afbeeldingen worden nu ook getoond bij gebruik van de Tab-toets.
- Werkt nu ook op touchscreens.
- Regelafstand vergroot voor gebruik op touchscreens (anders staan de gemarkeerde woorden te dicht op elkaar).
- Werkt nu ook in kleine browservensters zoals die op smartphones.
- Negatieve marges bij de <img>'s gecorrigeerd (breedte en hoogte waren omgewisseld).
- Afbeeldingen staan nu altijd binnen het venster van de browser.
- Alt-tekst ingekort ('Thumbnail van' overal weggehaald).
- Afbeeldingen duidelijker naam gegeven (bijvoorbeeld '001.jpg' is nu 'lay-out-1.jpg').
- Aantal selectors wat ingekort.
- Aantal nieuwe hoofdstukken, voornamelijk over toegankelijkheid en touchscreens.
- Tig kleinere wijzigingen in de tekst en de code.
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 ode en dergelijke zitten. Voor eventuele schade die door gebruik van materiaal uit deze download ontstaat, in welke vorm dan ok, 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 oorbeeld (en de bijbehorende uitleg en dergelijke) op welke manier dan ook te verspreiden, zonder daarbij duidelijk te ermelden dat voorbeeld, uitleg, en dergelijke afkomstig zijn van www.css-voorbeelden.nl en dat daar altijd de nieuwste versie s te vinden. Dit is om te voorkomen dat er verouderde versies worden verspreid.
En link naar www.css-voorbeelden.nl wordt trouwens altijd op prijs gesteld.
tekst-037-dl.html: de pagina met het voorbeeld.
tekst-037.pdf: deze uitleg (aangepast aan de inhoud van de download).
tekst-037-inhoud-download-en-licenties.txt: een kopie van de tekst onder dit kopje (Inhoud van de download en licenties).
037-css-dl:
tekst-037-dl.css: stylesheet voor tekst-037-dl.html.
037-pics:
De 36 in het voorbeeld gebruikte thumbnails.
HTML
De code is geschreven in een afwijkende
lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code), is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)
In de html hieronder wordt alleen de html besproken, waarover iets meer is te vertellen. Een <h1> bijvoorbeeld wordt in de regel niet genoemd, omdat daarover weinig interessants valt te melden. (Als bijvoorbeeld het uiterlijk van de <h1> wordt aangepast met behulp van css, staat dat verderop bij de bespreking van de css.)
Zaken als een doctype
en charset
hebben soms wat voor veel mensen onbekende effecten, dus daarover wordt hieronder wel een en ander geschreven.
<!doctype html>
Een document moet met een doctype beginnen om weergaveverschillen tussen browsers te voorkomen. Zonder doctype is de kans op verschillende (en soms volkomen verkeerde) weergave tussen verschillende browsers heel erg groot.
Geldige doctypes vind je op www.w3.org/QA/2002/04/valid-dtd-list.
Gebruik het volledige doctype, inclusief de eventuele url, anders werkt het niet goed.
Het hier gebruikte doctype is dat van html5. Dit kan zonder enig probleem worden gebruikt: het werkt zelfs in Internet Explorer 6.
<html lang="nl">
De toevoeging lang="nl"
bij <html> geeft aan dat de pagina in het Nederlands is. De taal is van belang voor schermlezers, automatisch afbreken, automatisch genereren van aanhalingstekens, juist gebruik van decimale punt of komma, en dergelijke.
<meta charset="utf-8">
Zorgt dat de browser letters met accenten en dergelijke goed kan weergeven.
utf-8 is de beste charset (tekenset), omdat deze alle talen van de wereld (en nog heel veel andere extra tekens) bestrijkt, maar toch niet meer ruimte inneemt voor de code, dan nodig is. Als je utf-8 gebruikt, hoef je veel minder entiteiten (ä
en dergelijke) te gebruiken, maar kun je bijvoorbeeld gewoon ä gebruiken.
Deze regel moet zo hoog mogelijk komen te staan, als eerste regel binnen de <head>, omdat hij anders door sommige browsers niet wordt gelezen.
In html5 hoeft deze regel niet langer te zijn, dan wat hier staat.
<meta name="viewport" content="width=device-width, initial-scale=1">
Mobiele apparaten variëren enorm in grootte. En dat is een probleem. Sites waren, in ieder geval tot enkele jaren geleden, gemaakt voor desktopbrowsers. En die hebben, in vergelijking met bijvoorbeeld een smartphone, heel brede browservensters. Hoe moet je op 'n smartphone een pagina weergeven, die is gemaakt voor de breedte van een desktop? Je kunt natuurlijk wachten tot álle sites zijn omgebouwd voor smartphones, tablets, enzovoort, maar dan moet je waarschijnlijk heel erg lang wachten.
Mobiele browsers gokken erop dat een pagina een bepaalde breedte heeft. Safari voor mobiel bijvoorbeeld gaat ervan uit dat een pagina 980 px breed is. De pagina wordt vervolgens zoveel versmald dat hij binnen het venster van het apparaat past. Op een iPhone wordt de pagina dus veel smaller dan op een iPad. Vervolgens kan de gebruiker inzoomen op het deel van de pagina dat hij of zij wil zien.
Dit betekent ook dat bij het openen van de pagina de tekst meestal heel erg klein wordt weergegeven. (Meestal, want niet alle browsers en apparaten doen het op dezelfde manier.) Niet erg fraai, maar bedenk maar 'ns 'n betere oplossing voor bestaande sites.
Nieuwe sites of pagina's kunnen echter wel rekening houden met de veel kleinere vensters van mobiele apparaten. In dit voorbeeld bijvoorbeeld wordt de pagina nooit breder dan het venster en staan de afbeeldingen altijd binnen het venster.
Maar die stomme mobiele browser weet dat niet, dus die gaat ervan uit dat ook deze pagina 980 px breed is, en verkleint die dan. Dat is ongeveer even behulpzaam als de gedienstige kelner die behulpzaam de stoel naar achteren trekt, net als jij wilt gaan zitten.
Om de door de browser aangeboden hulp vriendelijk maar beslist te weigeren, wordt deze tag gebruikt. Hiermee geef je aan dat de pagina is geoptimaliseerd voor mobiele apparaten.
Een iPad in portretstand bijvoorbeeld is 768 px breed. De kreet width=device-width
zegt tegen de mobiele browser dat de breedte van de weer te geven pagina gelijk is aan de breedte van het apparaat. Voor een iPad in portretstand dus 768 px.
Er staat nog een tweede deel in de tag: initial-scale=1
. Sommige mobiele apparaten zoomen een pagina gelijk in of uit. Ook weer in een poging behulpzaam te zijn. Ook dat is hier niet nodig. Er is ook een instructie om zoomen helemaal onmogelijk te maken, maar die wordt niet gebruikt. De bezoeker kan zelf nog gewoon zoomen, wat belangrijk is voor mensen die wat slechter zien.
<link rel="stylesheet" href="037-css-dl/tekst-037-dl.css">
Dit is een koppeling naar een externe stylesheet (stijlbestand), waarin de css staat. In html5 is de toevoeging type="text/css"
niet meer nodig, omdat dit standaard al zo staat ingesteld. Je moet uiteraard de naam van en het pad naar de stylesheet aanpassen aan de naam en plaats, waar je eigen stylesheet staat.
Voordeel van een externe stylesheet is onder andere dat deze geldig is voor alle pagina's, waaraan deze is gelinkt. 'n Verandering in de lay-out hoef je dan maar in één enkele stylesheet aan te brengen, in plaats van in elke pagina apart. Op een grotere site kan dit ontzettend veel werk schelen. Bovendien hoeft de browser zo'n externe stylesheet maar één keer te downloaden, ongeacht hoeveel pagina's er gebruik van maken. Zou je de css in elke pagina opnieuw aanbrengen, dan worden de te downloaden bestanden veel groter.
In dit voorbeeld heeft een extern stylesheet eigenlijk geen nut, omdat er maar één pagina is die dit stylesheet gebruikt. In dit geval kun je de css beter in de <head> van de html-pagina zelf zetten. Voor de omvang maakt het hier niets uit, want de css wordt hoe dan ook altijd precies één keer gedownload, en nooit vaker. Voor het onderhoud maakt het ook geen verschil, want ook hier hoef je de css maar op één plaats te wijzigen. Maar het scheelt wel een extra aanroep naar de server, omdat geen apart stylesheet hoeft te worden gedownload.
Dat opnemen in de <head> gaat heel simpel: je kopieert gewoon het hele stylesheet en zet die bovenin de <head>, tussen <style> en </style>:
<style>
body {color: black;}
(...) rest van de css (...)
div {color: red;}
</style>
Maar zodra een stylesheet op meerdere pagina's wordt gebruikt, wat meestal het geval zal zijn, is een extern stylesheet beter.
(De reden dat er toch een extern stylesheet is, terwijl hierboven omstandig wordt beweerd dat dat in dit voorbeeld eigenlijk geen nut heeft: overzichtelijkheid. Nu kun je html en css los van elkaar bekijken.)
<span class="buiten">
<span class="markeer" aria-haspopup="true">eerste lay-out</span>
<span class="pict" tabindex="0"></span>
<img src="037-pics/menu-1.jpg" alt="Lay-out 1">
</span>
Dit is de html voor het tonen van de eerste afbeelding. Voor de andere afbeeldingen is de code vrijwel hetzelfde: alleen de tekst in span.markeer
, de naam van de afbeelding en de alt-tekst zijn anders.
Anders dan in het voorbeeld zelf zijn de elementen hier over meerdere regels neergezet. Dat is hier duidelijker. In het voorbeeld zou net nauwelijks duidelijker zijn, omdat daar ook nog veel meer gewone tekst in staat. Bovendien zou het heel erg veel extra regels opleveren.
<span class="buiten">
: binnen deze <span> staat onder andere de gemarkeerde tekst, hier is dat 'eerste lay-out'. Zodra een element binnen span.buiten
focus heeft, komt rondom span.markeer
met de gemarkeerde tekst te staan een randje te staan. Hierdoor kunnen gebruikers van de Tab-toets zien, bij welke tekst de afbeelding hoort.
Omdat dit alleen gebeurt als een element binnen span.buiten
focus heeft, verschijnt het randje alleen bij gebruik van de Tab-toets. Bij hoveren over of aanraken van de gemarkeerde woorden is het ook niet nodig, want dan is duidelijk bij welke gemarkeerde tekst de getoonde afbeelding hoort.
Meer hierover is te vinden bij .buiten:focus-within .markeer.
<span class="markeer" aria-haspopup="true">eerste lay-out</span>
: binnen deze <span> staat de gemarkeerde tekst. Als over deze tekst wordt gehoverd of als deze wordt aangeraakt, verschijnt een bijbehorende afbeelding. De tekst in deze <span> is het enige altijd zichtbare deel van deze hele constructie.
aria-haspopup="true"
is een zogenaamde WAI-ARIA-code. Het is nodig voor Internet Explorer en Edge op touchscreens, omdat anders de afbeelding niet wordt getoond.
<span class="pict" tabindex="0"></span>
: met de Tab-toets kunnen links, tekstvelden, en dergelijke worden afgelopen. Dit is belangrijk voor mensen die de muis niet goed kunnen gebruiken (en soms werkt het ook veel sneller dan de muis).
Een <span> kan normaal genomen niet worden bezocht met de Tab-toets, maar door toevoeging van tabindex="0"
kan dit wel. Met behulp van de selector .pict:focus + img kan de afbeelding zichtbaar worden gemaakt, als span.pict
focus heeft.
Het zou nogal wat html en css uitsparen als tabindex="0"
gewoon bij de <img> gezet zou kunnen worden. TalkBack op Android 8 (en mogelijk ook in latere versies, maar daar wordt (nog) niet in getest) leest dan echter bij elke <img> 'Dubbelklik om te activeren' voor. (Andere schermlezers lezen de tekst zonder onderbrekingen voor.)
Als een tekst bij het voorlezen 37 keer wordt onderbroken met zo'n toch wat weinig opwindende tekst, leidt dat mogelijk tot een woedekoliek. Wat weer hogere zorgkosten, Kamervragen en een boze minister oplevert, dus het is beter dat te voorkomen.
Alleen als de <span> volledig leeg is, wordt deze door TalkBack genegeerd. Ook span.markeer
of span.buiten
waren daardoor niet te gebruiken, want ook deze zijn niet volledig leeg. De enige oplossing bleek een aparte, volledig lege <span> te zijn.
(In dit geval moeten de afbeeldingen worden verborgen voor schermlezers, omdat ze nauwelijks informatie opleveren. Als de afbeeldingen wel informatie bevatten, is deze techniek volledig ongeschikt.)
Het JavaScript gebruikt class 'pict' voor browsers die de pseudo-class :focus-within
niet ondersteunen. Als je de naam van deze class wijzigt, moet je dat ook in het script doen.
<img src="037-pics/menu-1.jpg" alt="Lay-out 1">
: dit is een gewone afbeelding, die alleen op verzoek wordt getoond.
Normaal genomen zou je alt=""
gebruiken om aan te geven dat de afbeelding door schermlezers genegeerd mag worden. Hier is toch een korte alt-tekst aangebracht, omdat in bepaalde omstandigheden een schermlezer de afbeelding toch noemt. Zonder alt-tekst wordt dan meestal de naam van het bestand voorgelezen.
CSS
De code is geschreven in een afwijkende
lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code) is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)
Technisch gezien is er geen enkel bezwaar om de css in de stylesheet allemaal achter elkaar op één regel te zetten:
div#header-buiten {position: absolute; right: 16px; width: 100%; height: 120px; background: yellow;} div p {margin-left 16px; height: 120px; text-align: center;}
Maar als je dat doet, garandeer ik je hele grote problemen, omdat het volstrekt onoverzichtelijk is. Beter is het om de css netjes in te laten springen:
div#header-buiten {
position: absolute;
right: 16px;
width: 100%;
height: 120px;
background: yellow;
}
div p {
margin-left: 16px;
height: 120px;
text-align: center;
}
Hiernaast is het heel belangrijk voldoende commentaar (uitleg) in de stylesheet te schrijven. Op dit moment weet je waarschijnlijk (hopelijk...), waarom je iets doet. Maar over vijf jaar kan dat volstrekt onduidelijk zijn. Op deze site vind je nauwelijks commentaar in de stylesheets, maar dat heeft een simpele reden: deze uitleg is in feite één groot commentaar.
Op internet zelf is het goed, als de stylesheet juist zo klein mogelijk is. Dus voor het uploaden kun je normaal genomen het beste het commentaar weer verwijderen. Veel mensen halen zelfs alles wat overbodig is weg, voordat ze de stylesheet uploaden. Inspringingen bijvoorbeeld zijn voor mensen handig, een computer heeft ze niet nodig.
Je hebt dan eigenlijk twee stylesheets. De uitgebreide versie waarin je dingen uitprobeert, verandert, enzovoort, met commentaar, inspringingen, en dergelijke. Dat is de mensvriendelijke versie. Daarnaast is er dan een stylesheet die je op de echte site gebruikt: een gecomprimeerde versie.
Dat comprimeren kun je met de hand doen, maar er bestaan ook hulpmiddelen voor. Op de pagina met links kun je onder het kopje Gereedschap → Snelheid, testen, gzip, comprimeren (inclusief theorie) links naar sites vinden, waar je bestanden kunt comprimeren.
(Stylesheets op deze site zijn niet gecomprimeerd. Omdat het vaak juist om de css gaat, kunnen mensen dan zonder al te veel moeite de css bekijken.)
css voor alle vensters
/* tekst-037-dl.css */
Om vergissingen te voorkomen is het een goede gewoonte bovenaan het stijlbestand even de naam neer te zetten. Voor je het weet, zit je anders in het verkeerde bestand te werken.
body
Het element waarbinnen de hele pagina staat. Veel instellingen die hier worden opgegeven, worden geërfd door de nakomelingen van <body>. Ze gelden voor de hele pagina, tenzij ze later worden gewijzigd. Dit geldt bijvoorbeeld voor de lettersoort, de lettergrootte en de voorgrondkleur.
background: #ff9;
Achtergrondkleurtje.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
font-family: Arial, Helvetica, sans-serif;
Als Arial is geïnstalleerd op de machine van de bezoeker, wordt deze gebruikt, anders Helvetica. Als die ook niet wordt gevonden, wordt in ieder geval een schreefloze letter (zonder dwarsstreepjes) gebruikt.
font-size: 110%;
Iets groter dan standaard. 't Zal de leeftijd zijn, maar ik vind de standaardgrootte wat te klein.
Als eenheid wordt de relatieve eenheid %
gebruikt, omdat bij gebruik van een absolute eenheid zoals px
niet alle browsers de lettergrootte kunnen veranderen. Zoomen kan wel altijd, ongeacht welke eenheid voor de lettergrootte wordt gebruikt.
margin: 0; padding: 0;
Slim om te doen vanwege verschillen tussen browsers.
(Mogelijk is padding
niet meer nodig, maar in het verleden verschilde de standaard-padding tussen browsers. Het is simpeler om dit gewoon te blijven gebruiken dan om een uitgebreide test uit te gaan voeren om te kijken, of dit nog wel nodig is.)
main
Alle <main>'s. Dat is er maar één: de belangrijkste inhoud van de pagina staat erin. (Hier is dat alleen de flauwekultekst met de afbeeldingen.)
background: white;
Witte achtergrond.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.
display: block;
Oudere browsers kennen <main> niet. Een onbekend element is standaard een inline-element, waardoor eigenschappen als breedte niet kunnen worden gebruikt. Nu weten alle browsers dat dit een blok-element is.
width: 800px;
Breedte. Een maximumbreedte voorkomt te lange, slecht leesbare regels.
max-width: 95%;
Hier gelijk boven is een breedte van 800 px opgegeven. Als het venster van de browser smaller is, moet je hierdoor horizontaal scrollen om alles te kunnen zien. Daarom wordt hier de breedte beperkt tot maximaal 95%.
Een breedte in procenten is normaal genomen ten opzichte van de ouder. Die ouder is hier <body>, een blok-element. Een blok-element wordt normaal genomen automatisch even breed als z'n ouder. Die ouder is <html>. Omdat <html> het buitenste element is, wordt dit normaal genomen even breed als het venster van de browser.
Hierdoor wordt <main> uiteindelijk nooit breder dan 95% van de breedte van het browservenster, ongeacht de breedte van het venster.
line-height: 2em;
Tamelijk grote regelafstand. In de tekst zitten gemarkeerde woorden, die moeten worden aangeraakt om een afbeelding te openen. Door een grotere regelafstand zijn deze gemarkeerde woorden op een touchscreen makkelijk te raken.
Als eenheid wordt de relatieve eenheid em
gebruikt, omdat bij gebruik van een absolute eenheid zoals px
de regelhoogte niet in alle browsers mee verandert met de lettergrootte. Zoomen kan wel altijd, ongeacht welke eenheid voor de regelhoogte wordt gebruikt.
margin: 20px auto 0;
Omdat voor links geen waarde is opgegeven, krijgt links automatisch dezelfde waarde als rechts. Hier staat dus eigenlijk 20px auto 0 auto
in de volgorde boven – rechts – onder – links. Boven een kleine afstand tot de bovenkant van het venster van de browser.
Links en rechts auto
, wat hier hetzelfde betekent als evenveel. Hierdoor staat <main> altijd horizontaal gecentreerd binnen z'n ouder <body>, ongeacht de breedte van <body>.
Zoals iets hierboven bij max-width
beschreven is <body> altijd even breed als het venster van de browser. Hierdoor staat <main>, en daarmee de tekst en dergelijke erin ook, altijd horizontaal gecentreerd binnen het venster, ongeacht de breedte van het venster.
border: black solid 1px;
Zwart randje.
padding: 5px;
Kleine afstand tussen buitenkant van en tekst in <main>.
h1
Alle <h1>'s. Dat is er maar één: de belangrijkste kopregel van de pagina staat erin.
font-size: 1.4em;
Van zichzelf is een <h1> wel heel enthousiast groot. Daarom wordt hier de lettergrootte iets verkleind.
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.
font-weight: normal;
Standaard is een <h1> vet. Hier wordt dat veranderd naar normaal.
text-align: center;
Tekst horizontaal centreren.
.buiten
Alle elementen met class="buiten". In elke span.buiten
staat onder andere een stukje gemarkeerde tekst en de daarbij horende afbeelding.
border: transparent solid 1px;
Onzichtbaar randje rondom de <span>. Dit is geen onderdeel van een goocheltruc of zoiets, maar lost een probleem in Google Chrome en Opera op.
Als een nieuwe regel toevallig binnen een stuk gemarkeerde tekst begint, staat een deel van de tekst aan het eind van de bovenste regel. Als over dat deel van de tekst wordt gehoverd, moet de bijbehorende afbeelding gewoon worden getoond.
In Google Chrome en Opera echter wordt de afbeelding wel getoond, maar verdwijnt gelijk weer. En dat in een tempo van tientallen keren per seconde. Bij hoveren over de gemarkeerde tekst in de onderste regel gaat het wel goed.
Een doorzichtige rand rondom de hele constructie blijkt dit op te lossen. Mogelijk zijn er nog wel meer oplossingen mogelijk, maar omdat span.buiten
toch al aanwezig is, kan deze worden gebruikt voor deze simpele oplossing.
.markeer
Alle elementen met class="markeer". Dit zijn de <span>'s, waarin de gemarkeerde tekst zit.
background: #fe8;
Afwijkende achtergrondkleur.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.
border: black dotted 1px;
De tekst die een afbeelding tevoorschijn doet komen, heeft hierboven een afwijkende kleur gekregen. Voor mensen die moeite hebben met kleuren, is dit mogelijk niet duidelijk genoeg. Daarom wordt rondom de tekst ook nog een stippellijntje gezet.
padding: 2px;
Door de <span> een kleine padding te geven, wordt deze wat breder en hoger. Hierdoor wordt de markering wat duidelijker.
img
Alle afbeeldingen.
background: white;
Witte achtergrond.
Normaal genomen zie je de achtergrondkleur van de afbeelding niet. Maar elke <img> heeft een korte alt-tekst. Deze wordt getoond, als de afbeelding om een of andere reden niet wordt weergegeven. Door de afbeelding een witte achtergrond te geven, is de tekst altijd goed leesbaar.
color: black;
Voorgrondkleur zwart. Dit is onder andere de kleur van de alt-tekst.
Hoewel dit de standaardkleur is, wordt deze toch specifiek opgegeven. Hierboven is een achtergrondkleur opgegeven. Sommige mensen hebben zelf de voorgrond‑ en/of achtergrondkleur veranderd, bijvoorbeeld omdat ze slecht kleuren kunnen onderscheiden. Als nu de achtergrondkleur wordt veranderd, maar niet de voorgrondkleur, loop je het risico dat tekstkleur en achtergrondkleur te veel op elkaar gaan lijken.
Door beide op te geven, is redelijk zeker dat achtergrond- en tekstkleur genoeg van elkaar blijven verschillen. Als de gebruiker !important
heeft gebruikt in een eigen stylesheet, is er nog niets aan de hand, want dan veranderen achtergrond- en voorgrondkleur geen van beide.
Dit is ook al bij <body> opgegeven, maar sommige mensen hebben bij álle elementen de kleuren veranderd. Het heeft immers weinig zin, als ze dat alleen bij de body doen, terwijl de sitebouwer de kleuren ook bij bijvoorbeeld de paragrafen heeft aangepast.
display: none;
Afbeelding verbergen. Door display: none;
te gebruiken is de afbeelding volledig verborgen voor schermlezers. In dit geval is dat prima, omdat de kleine thumbnails nauwelijks informatie geven. Als de afbeelding wel informatief is, is het geen goed idee deze te verbergen voor schermlezers.
width: 119px; height: 106px;
Alle afbeeldingen hebben dezelfde breedte en hoogte. Het spaart behoorlijk wat html uit, als je die breedte en hoogte één keer opgeeft in de css. Omdat de afbeeldingen normaal genomen niet worden getoond, is het ook niet nodig om er ruimte voor te reserveren bij het opbouwen van de pagina.
margin: -53px 0 0 -60px;
Iets hieronder wordt de linkerbovenhoek van de afbeeldingen met position: fixed;
, top: 50%;
en left: 50%;
precies in het midden van het venster van de browser geplaatst.
De afbeelding is 106 px hoog. Als de afbeelding met een negatieve marge van -53 px naar boven wordt gezet, komt de afbeelding verticaal precies in het midden van het venster van de browser te staan.
De afbeelding is 119 px breed, dus met een negatieve marge naar links van -60 px komt de afbeelding ook horizontaal in het midden van het browservenster te staan.
In browservensters minimaal 630 px hoog wordt de positie van de afbeelding later op een andere manier bepaald. Die manier werkt echter niet in kleinere vensters, omdat de afbeelding dan heel vaak (grotendeels) buiten het venster zou komen te staan.
border: black solid 1px;
Zwart randje rondom de afbeelding.
pointer-events: none;
Deze css-eigenschap moet niet worden verward met Pointer Events uit JavaScript. Hier is heel handig dezelfde naam voor gekozen, maar dit heeft helemaal niets te maken met deze css-eigenschap.
Deze eigenschap zorgt ervoor dat aanraken van of hoveren over de <img> volledig wordt genegeerd. Als de <img> wordt aangeraakt of als erover wordt gehoverd, wordt dit doorgegeven aan het element onder de <img>. Dit is nodig voor Microsoft Edge op een touchscreen.

Op de illustratie is het gemarkeerde woord 'imagemap' te zien met de bijbehorende afbeelding. De afbeelding staat gedeeltelijk over het gemarkeerde woord heen. Omdat de afbeelding doorzichtig is gemaakt, is het hele gemarkeerde woord toch te zien.
Als je op Edge het gemarkeerde woord aanraakt op een plaats, waar later de afbeelding boven komt te staan, sluit de afbeelding gelijk weer. Op de illustratie staat 'ima' niet onder de afbeelding. Als je 'ima' aanraakt, blijft ook op Microsoft Edge de afbeelding geopend. Maar als je 'gemap' aanraakt, het deel waarover de afbeelding komt te staan, sluit de afbeelding gelijk weer.
Het gemarkeerde woord 'imagemap' reageert op :hover
. Dat wordt op een touchscreen omgezet naar een aanraking. Als de afbeelding wordt geopend, raak je het gemarkeerde woord onder de afbeelding niet langer aan, want daar raak je nu de afbeelding aan. Dit is precies zoals het hoort en gebeurt in alle browsers.
Oorspronkelijk werd dit opgevangen met img:hover {display: block;}
: ook als je over de <img> hovert of deze aanraakt, blijft de <img> geopend. Dit bleek echter op Microsoft Edge tot het hierboven probleem te leiden. Door de <img> volledig ongevoelig voor aanraken (of hoveren) te maken, wordt dit opgelost.
Hier zit één klein nadeel aan. Bij hoveren zou de afbeelding eigenlijk getoond moeten blijven, zolang de cursor boven de <img> staat. Nu sluit de <img> echter, zodra de cursor de gemarkeerde tekst verlaat. Een echt probleem blijkt dit echter niet te zijn.
position: fixed; top: 50%; left: 50%;
De linkerbovenhoek van de afbeelding in het midden van het browservenster neerzetten. Met behulp van de iets hierboven opgegeven negatieve marges komt de afbeelding uiteindelijk precies in het midden van het venster te staan. Het hele verhaal is bij die marges te vinden.
z-index: 100;

Elementen worden normaal genomen op het scherm gezet in de volgorde, waarin ze in de html voorkomen. Op de illustratie staat een afbeelding die tamelijk onderin een <p> staat. Hierdoor komt tekst uit de <p> daaronder over de afbeelding te staan.
Door de <img> een z-index te geven, komt de afbeelding toch boven de latere <p> te staan.
Een z-index werkt alleen in bepaalde omstandigheden. Eén van die omstandigheden is een fixed positie. Die is hierboven gegeven, dus dat is geregeld.
(In browservensters minimaal 630 px breed wordt de<img> relatief of sticky gepositioneerd, en ook dan werkt een z-index.)
.buiten:focus-within .markeer
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.markeer {background: #fe8; color: black; border: black dotted 1px; padding: 2px;}
Alle elementen met class="buiten", maar alleen als een nakomeling van dat element focus heeft.
In elke span.buiten
zit onder andere een <span class="pict" tabindex="0">
. Met behulp van de Tab-toets kunnen links, tekstvelden, en dergelijke worden bezocht. Het bezochte veld heeft focus: een link kan worden gevolgd door het indrukken van Enter, in een tekstveld kan tekst worden ingevoerd, enzovoort.
Normaal genomen kan een <span> geen focus krijgen. Maar door toevoeging van het attribuut tabindex="0"
kan dat wel. Dit is het geval bij span.pict
. Omdat deze <span> verder helemaal leeg en daardoor onzichtbaar is, kan de <span> alleen focus krijgen door de Tab-toets te gebruiken. Aanraken van of hoveren over een onzichtbare <span> is wat lastig, vandaar. Deze selector kan dus alleen maar werken, als de Tab-toets wordt gebruikt.
Omdat span.pict
binnen span.buiten
zit, gaat de pseudo-class :focus-within
werken, zodra span.pict
de focus heeft. Op dat moment kan er dus css worden uitgevoerd bij span.buiten
.
outline: green dotted 3px;
Groen gestippeld kadertje rondom span.buiten
zetten.
Als je een gemarkeerd woord aanraakt of erover hovert, weet je dat de getoonde afbeelding daarbij hoort. Voor gebruikers van de Tab-toets is dat niet duidelijk. Daarom wordt, als een afbeelding wordt getoond, een groen gestippeld kadertje rondom de gemarkeerde woorden gezet.
Dit kadertje komt rondom span.buiten
te staan en daarmee dus ook om alles wat ín span.buiten
zit. Dat is span.markeer
met de gemarkeerde tekst. Dat komt goed uit, want dat is precies de tekst, waarom het kadertje moet komen te staan.
Slimmeriken denken nou natuurlijk: "ho, wacht even, er zit toch nog veel meer in span.buiten
?" (Om minderwaardigheidsgevoelens en andere enge dingen te voorkomen: als je dat niet hebt gedacht, ben je niet dom. Je bent dan zo superslim dat je gelijk de eindconclusie hebt gevonden en deze stap hebt overgeslagen.)
Buiten de tekst zit in span.buiten
nog span.pict
. Die staat inderdaad ook binnen dat kadertje, maar omdat span.pict
leeg is en dus onzichtbaar, heeft die geen invloed op de grootte van het kadertje.
Dan zit er nog de <img> in, maar die is fixed of absoluut gepositioneerd, als deze selector werkt. En een fixed of absoluut gepositioneerd element heeft geen invloed op de grootte van z'n ouder.
Kortom: het kadertje komt precies rondom de gemarkeerde tekst die bij de afbeelding hoort.
Voor browsers die het relatief nieuwe :focus-within
niet ondersteunen wordt dit met behulp van een beetje JavaScript gesimuleerd.
.markeer:hover
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
.markeer {background: #fe8; color: black; border: black dotted 1px; padding: 2px;}
.buiten:focus-within .markeer {outline: green dotted 3px;}
Alle elementen met class="markeer", maar alleen als daarover wordt gehoverd of, op touchscreens, bij aanraking van het element. In deze <span>'s staan de gemarkeerde woorden.
-moz-user-select: none; -ms-user-select: none; -webkit-user-select: none; user-select: none;
Hier staat in feite vier keer hetzelfde: user-select: none;
. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.
Als op een touchscreen de gemarkeerde tekst iets langer wordt aangeraakt, opent de afbeelding niet, maar wordt de tekst geselecteerd. Dit maakt het heel moeilijk de afbeelding te openen. (Heel moeilijk, want bij precies de juiste aanraking is de afbeelding toch te zien. Maar het vangen van een vlo met de blote hand is 'n stuk makkelijker.)
Als je de tekst niet kunt selecteren, kun je die ook niet kopiëren en dergelijke. Maar dat geldt alleen als je alleen precies zo'n gemarkeerd stukje wilt selecteren. Als je van iets voor tot iets achter de gemarkeerde tekst selecteert, wordt ook de tussenliggende gemarkeerde tekst geselecteerd, want daar hover je dan niet over. Het selecteren van één extra spatie voor en na de gemarkeerde tekst is al genoeg, om ook de gemarkeerde tekst te kunnen selecteren.
.markeer:hover + span + img, .pict:focus + img
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat.
img {background: white; display: none; width: 119px; height: 106px; margin: -53px 0 0 -60px; border: black solid 1px; pointer-events: none; position: fixed; top: 50%; left: 50%; z-index: 100;}
De eerste selector, die voor de komma:
.markeer:hover
: alle elementen met class="markeer", maar alleen als daarover wordt gehoverd (of als deze worden aangeraakt). Dit zijn de <span>'s, waarin de gemarkeerde tekst staat.
+
: het element achter de +
moet in de html direct volgen op het element voor de +
. In dit geval gaat het om een <span> die gelijk op span.markeer
volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder span.buiten
.
span
: omdat deze <span> direct op span.markeer
moet volgen, kan dit alleen span.pict
zijn.
+
: het element achter de +
moet in de html direct volgen op het element voor de +
. In dit geval gaat het om de <img> die gelijk op span.pict
volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder span.buiten
.
img
: de <img> met de afbeelding.
De hele eerste selector in normale mensentaal: doe iets met de <img> die direct op span.pict
en span.markeer
volgt, maar alleen als over span.markeer
wordt gehoverd (of als deze wordt aangeraakt).
De tweede selector, die na de komma:
.pict:focus
: alle elementen met class="pict", maar alleen als die focus hebben. Dit zijn de lege <span>'s die voor gebruikers van de Tab-toets zijn aangebracht.
+
: het element achter de +
moet in de html direct volgen op het element voor de +
. In dit geval gaat het een <img> die gelijk op span.pict
volgt. Beide elementen moeten ook nog dezelfde ouder hebben. Dat is hier het geval, ze hebben beide als ouder span.buiten
.
img
: de <img> met de afbeelding.
De hele tweede selector in normale mensentaal: doe iets met de <img> die direct op span.pict
volgt, maar alleen als span.pict
focus heeft.
display: block;
Bij img is de <img> met display: none;
verborgen. Nu wordt hij zichtbaar gemaakt.
css voor vensters minimaal 630 px hoog
@media screen and (min-height: 630px)
De css die hier tot nu toe staat, geldt voor alle browservensters.
De css die binnen deze media query staat, geldt alleen voor browservensters die minimaal 630 px hoog zijn. In deze hogere vensters wordt de afbeelding niet meer in het midden van het venster gezet, maar meer in de buurt van de bijbehorende tekst.
@media
: geeft aan dat het om css gaat die alleen van toepassing is, als aan bepaalde voorwaarden wordt voldaan. Al langer bestond de mogelijkheid om met behulp van zo'n @media-regel css voor bijvoorbeeld printers op te geven. css3 heeft dat uitgebreid tot bepaalde fysieke eigenschappen, zoals de breedte en hoogte van het venster van de browser.
screen
: deze regel geldt alleen voor schermweergave.
and
: er komt nog een voorwaarde, waaraan moet worden voldaan.
(min-height: 630px)
: het browservenster moet minimaal 630 px hoog zijn. Is het venster lager, dan wordt de css die binnen deze media-regel staat genegeerd.
Gelijk na deze regel komt een {
te staan, en aan het einde van de css die binnen deze query valt een bijbehorende afsluitende }
. Die zijn in de regel hierboven weggevallen, maar het geheel ziet er zo uit:
@media screen and (min-height: 630px) {
body {color: silver;}
(...) rest van de css voor deze @media-regel (...)
footer {color: gold;}
}
Voor de eerste css binnen deze media-regel staat dus een extra {
, en aan het eind staat een extra }
.
Als je nou 'n mobieltje hebt met een resolutie van – ik roep maar wat – 1024 x 768 px, dan geldt deze media query soms toch niet voor dat mobieltje. Terwijl dat toch echt meer dan 630 px hoog is. Een vuig complot van gewetenloze multinationals? Voordat je je gaat beklagen bij Radar, zou ik eerst even verder lezen.
Steeds meer mobiele apparaten, maar ook steeds meer gewone beeldschermen, hebben een hogere resolutiedichtheid. Dat wil zeggen dat ze kleinere pixels hebben, die dichter bij elkaar staan. Daardoor zijn foto's, tekst, en dergelijke veel scherper weer te geven. Hoe kleiner de puntjes (de pixels) zijn, waaruit een afbeelding is opgebouwd, hoe duidelijker het wordt.
Er ontstaat alleen één probleem: als je de pixels twee keer zo klein maakt, wordt ook wat je ziet twee keer zo klein. En inmiddels zijn er al apparaten met pixels die meer dan vier keer zo klein zijn. Een lijntje van 1 px breed zou op die apparaten minder dan 'n kwart van de oorspronkelijke breedte krijgen en vrijwel onzichtbaar zijn. Een normale foto zou in een thumbnail veranderen. Kolommen zouden heel smal worden. Tekst zou onleesbaar klein worden. Allemaal fantastisch scherp, maar je hebt 'n vergrootglas nodig om 't te kunnen zien.
Om dit te voorkomen wordt een verschil gemaakt tussen css-pixels en schermpixels (in het Engels 'device-pixels'). De css-pixels zijn gebaseerd op de – tot voor kort – normale beeldschermen van de desktop. 1 css-pixel is op zo'n beeldscherm 1 pixel. Het aantal schermpixels is het werkelijk op het apparaat aanwezige aantal pixels (dat is het aantal pixels, waarvoor je hebt betaald).
Dat eerder genoemde mobieltje van 1024 x 768 px heeft wel degelijk het aantal pixels, waarvoor je hebt betaald. Maar die zitten dichter bij elkaar. Op een gewoon beeldscherm zitten 96 pixels per inch, wat wordt uitgedrukt met de eenheid ppi (’pixels per inch’). (Vaak wordt foutief de eenheid dpi (’dots per inch’) gebruikt. Die eenheid is voor printers.)Als dat mobieltje een resolutie van 192 ppi heeft, 192 pixels per inch, zijn de pixels ervan twee keer zo klein als op een origineel beeldscherm. Er zijn per inch twee keer zoveel schermpixels aanwezig.
Om nu te voorkomen dat alles op dat mobieltje twee keer zo klein wordt, geeft het mobieltje niet het echte aantal schermpixels (1024 x 768), maar een lager aantal css-pixels door bij een media query. De 192 ppi van het mobieltje is twee keer zo veel als de 96 ppi van een normaal beeldscherm. Het aantal css-pixels is dan het aantal schermpixels gedeeld door 2. 1024 x 768 gedeeld door 2 is 512 x 384 px. Het aantal css-pixels is 512 x 384 px en zit daarmee onder de grens van deze media query.
Je bent dus niet opgelicht, of in ieder geval niet wat betreft het aantal pixel.
Door deze truc is een lijn van 1 px breed op een normaal beeldscherm ook op het mobieltje nog steeds 1 px breed, alleen wordt die ene (css‑)pixel opgebouwd uit twee schermpixels (feitelijk vier, want het verhaal geldt voor breedte én hoogte). De dikte van het lijntje is hetzelfde, maar het is veel fijner opgebouwd. Bij lijntjes is dat verschil bijvoorbeeld in bochten goed te zien.
Hetzelfde verhaal geldt voor hogere resoluties, Een tablet met een breedte van 4096 schermpixels en een ppi van 384 (vier keer de originele dichtheid) geeft 4096 gedeeld door 4 = 1024 css-pixel door. Het lijntje van 1 px breedte op de originele monitor is nog steeds 1 css pixel breed op de tablet, maar die ene css-pixel is nu opgebouwd uit zestien schermpixel.
(Overigens kun je met behulp van media query's ook testen op de resolutie met gebruik van het sleutelwoord 'resolution'. Apple gebruikt het niet-standaard 'device-pixel-ratio', maar het idee is hetzelfde. Dit kan bijvoorbeeld handig zijn om te bepalen, hoe groot een foto moet zijn.)
Kort samengevat: omdat niet het aantal schermpixels (waarvoor je hebt betaald), maar het aantal css-pixels (de door de ontwerper bedoelde afmeting) wordt doorgegeven, wordt voorkomen dat een hogeresolutiescherm onleesbaar klein wordt.
.markeer:hover + span + img, .pict:focus + img
Voor deze elementen is eerder css opgegeven. Deze wordt binnen dit blokje herhaald in de volgorde, waarin deze in de stylesheet staat, zodat alles hier overzichtelijk bij elkaar staat. (Alleen wat binnen deze media query geldig is, wordt binnen dit blokje herhaald.)
img {background: white; display: none; width: 119px; height: 106px; margin: -53px 0 0 -60px; border: black solid 1px; pointer-events: none; position: fixed; top: 50%; left: 50%; z-index: 100;}
.markeer:hover + span + img, .pict:focus + img {display: block;}
Deze selector werkt precies hetzelfde als die bij .markeer:hover + span + img, .pict:focus + img, waar een uitgebreidere beschrijving staat. Als over span.markeer
(de <span>'s met de gemarkeerde tekst) wordt gehoverd of als deze wordt aangeraakt, of als span.pict
focus heeft, doe dan iets met de daaropvolgende <img>.
display: inline;
Bij img is de <img> met display: none;
verborgen. Nu wordt hij zichtbaar gemaakt.
De <img> wordt als een inline-element zichtbaar gemaakt. Daardoor wordt de <img> niet op een nieuwe regel gezet, wat met display: block;
wel zou gebeuren. De <img> gedraagt zich nu min of meer als normale tekst.
De afbeelding was eerst verborgen met display: none;
. Als die afbeelding nu opeens tussen de tekst wordt gezet, neemt die ruimte in. Daardoor zou een deel van de tekst moeten worden verplaats om ruimte te maken. Dat zou uiterst storend zijn. Bovendien wordt soms ook span.markeer
verplaatst, de <span> die bij hoveren over en aanraken van de <span> de <img> zichtbaar maakt. Daardoor zouden ook hoveren en aanraken niet meer goed werken.
Je zou dit op kunnen lossen door de <img> absoluut te positioneren. Op die manier is het in de vorige versie opgelost. Maar dat heeft als nadeel dat de afbeelding makkelijk (gedeeltelijk) buiten het browservenster kan komen te staan. Met behulp van het relatief nieuwe position: sticky;
kan dit grotendeels worden voorkomen, maar dan neemt de afbeelding wel ruimte in.
Het probleem van de ruimte wordt gelijk hieronder met behulp van negatieve marges opgelost. Hierdoor kunnen display: inline;
én position: sticky;
worden gebruikt en hebben we het beste uit twee werelden.
margin: -54px -61px -54px -60px;
Boven en onder een negatieve marge van 54 px, rechts van 61 px en links van 60 px.
Iets hoger wordt opgegeven dat de <img> als inline-element moet worden weergegeven. Een marge aan de boven- en onderkant heeft geen effect op inline-elementen zoals een <span>, <a>, <i>, en dergelijke. Ook een <img> is een inline-element en dus zouden marge aan boven- en onderkant geen effect hebben. Maar dat is niet zo.
Een <img> is een bijzonder soort inline-element: een 'replaced element'. De tag <img> wordt vervangen door iets anders: de afbeelding. Een marge aan boven- en onderkant werkt wel op een replaced element, ook als dit een inline-element is.
Zoals hierboven bij display: inline;
beschreven is de <img> eerst verborgen en neemt dus geen ruimte in. Maar bij tonen neem de afbeelding opeens wel ruimte in, waardoor de tekst zou moet en opschuiven.
De afbeeldingen zijn 119 px breed en 106 px hoog. Daar komt aan alle kanten nog een border van 1 px bij, dus de breedte wordt 121 px en de hoogte 108 px.
Als aan een element een marge wordt gegeven, wordt het element daadwerkelijk van plaats veranderd. Als aan de bovenkant een negatieve marge van 54 px aan de <img> wordt gegeven, wordt de <img> daadwerkelijk 54 px naar boven verplaatst. Omdat de <img> daadwerkelijk wordt verplaatst, wordt tekst en dergelijke die onder de <img> staat, ook 54 px naar boven verplaatst.
Aan de onderkant wordt ook een negatieve marge van 54 px gegeven. Een negatieve marge aan de onderkant verplaatst alles eronder 54 px naar boven.
De <img> zelf wordt dus 54 px naar boven verplaatst, en alle tekst en dergelijke eronder ook. Samen is dag 2 x 54 = 108 px. Precies de hoogte van de <img> met border. Oftewel: de 108 px hoogte die de <img> bij verschijnen inneemt, worden gecorrigeerd door de negatieve marges. Het lijkt alsof de <img> geen hoogte inneemt.
Precies hetzelfde geldt voor de negatieve marges rechts en links. De marge links verplaatst de <img> 61 px naar links, en de marge rechts verplaatst de tekst rechts van de <img> nog 'ns 60 px naar links. Samen de breedte van de <img> met z'n border.
De <img> neemt dus wel degelijk gewoon ruimte in, maar daar zie je niets van, omdat de negatieve marges dat wegmoffelen.
position: relative;
Hier gelijk onder wordt position: sticky;
gebruikt. UC browser op Windows en iOS9 en Internet Explorer ondersteunen dat niet. Daardoor zou het eerder bij img opgegeven position: fixed;
van kracht blijven. Dat werkt daar goed, omdat ook top: 50%;
en left: 50%;
zijn opgegeven.
Iets hieronder worden echter top: 10px;
en left: 10px;
opgegeven. Dat betekent dat de <img> nu ergens in de linkerbovenhoek van het browservenster zou komen te staan. Daarom wordt hier een relatieve positie opgegeven. Browsers die position: sticky;
niet ondersteunen gebruiken de hier opgegeven relatieve positie, en browsers die het wel ondersteunen gebruiken de position: sticky;
hieronder, want die staat lager in de css.
(Iets hieronder worden niet alleen nieuwe waarden voor top
en left
opgegeven, maar ook right: 10px;
en bottom: 10px;
. In combinatie met position: fixed;
is dat een onmogelijke opgave, daarom worden right
en bottom
iets hieronder genegeerd. Overigens worden die ook genegeerd bij deze relatieve positie, want je kunt een afbeelding niet gelijktijdig naar links én rechts én boven én onder verplaatsen. Althans: dat kan wel, maar dat levert een aantal forse scheuren op.)
position: -webkit-sticky; position: sticky;
Hier staat in feite twee keer hetzelfde: position: sticky;
. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.
Dit is een relatief nieuwe eigenschap. Normaal genomen is dit hetzelfde als position: relative;
. Hier gelijk onder worden top
, right
, bottom
en left
opgegeven, allemaal met 10 px. De <img> wordt dus 10 px naar onder, naar links, naar boven en naar rechts verplaatst. Dat kan natuurlijk niet, en daarom worden right
en bottom
genegeerd.
Voor een sticky positie is de eerste voorouder die een blok-element is van belang. Dat is de <p>, waar de <img> (en nog wat tekst) in staat. Zodra deze <p> door scrollen buiten het browservenster komt te staan, zorgt de sticky positie ervoor dat de <img> binnen het venster blijft staan. Althans: tot op zekere hoogte. Als je de <p> ver genoeg naar boven of naar beneden scrolt, zal uiteindelijk de <img> ook boven of onder het venster komen te staan.
Hier gelijk onder wordt opgegeven dat de <img> in principe altijd op minimaal 10 px van de boven-, rechter-, onder- en linkerkant van het venster van de browser moet komen te staan. In principe, want als je genoeg scrolt, zal de <img> uiteindelijk verdwijnen. Als je wilt dat de <img> altijd zichtbaar is, moet je een fixed positie gebruiken (zoals in dit voorbeeld bij vensters minder dan 630 px hoog inderdaad is gebruikt).
Hopelijk wordt dit wat duidelijker met behulp van onderstaande illustraties. De <p> waar de <img>'s bij horen heeft een gestippelde rand, zodat duidelijk is, hoe groot de <p> precies is. De vier <img>'s binnen de <p> op de illustratie zijn alle vier zichtbaar gemaakt. In werkelijkheid kan er steeds maar één zichtbaar zijn.


position: sticky;
in combinatie met top: 10px;
. Normaal genomen zou een deel van de <img>'s nu aan de bovenkant van het venster zijn verdwenen.De onderste afbeelding staat nog gewoon op z'n 'natuurlijke' hoogte, omdat die nog niet binnen de grens van 10 px vanaf de bovenkant van het browservenster staat.

position: sticky;
zou dat al veel eerder zijn gebeurd.Aan de onderkant werkt dit precies hetzelfde. De <img> staat op z'n 'natuurlijke' hoogte. Zodra de <p> te laag wordt gescrold, komt de <img> op 10 px van de onderkant van het venster van de browser te staan. Als er laag genoeg wordt gescrold, zal de <img> uiteindelijk ook aan de onderkant verdwijnen.
Ook in de breedte werkt dit op dezelfde manier. <main> is 800 px breed, maar nooit breder dan 95% van de breedte van het browservenster.

top: 10px; right: 10px; bottom: 10px; left: 10px;
In principe de <img> altijd op 10 px vanaf alle kanten van het venster van de browser houden. Dit wordt iets hierboven bij position: sticky;
veel uitgebreider beschreven.
JavaScript
De code is geschreven in een afwijkende
lettersoort. De code die te maken heeft met de basis van dit voorbeeld (essentiële code) is in de hele uitleg onderstippeld blauw
. Alle niet-essentiële code is bruin
. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)
Bij de uitleg van deze code zijn allerlei haakjes en dergelijke grotendeels weggelaten, want dat voert hier te ver. Als je je in dat soort dingen wilt verdiepen, kun je beter naar sites gaan die meer voor JavaScript zijn bedoeld.
Als je onderstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.
<script>
document.getElementsByTagName("body")[0].addEventListener("touchstart", function (){return null; });
(function () {
"use strict";
var focusWithin = probeer(),
picts,
len,
i;
if (focusWithin) return;
picts = document.getElementsByClassName("pict");
len = picts.length;
for (i = 0; i < len; i++) {
picts[i].addEventListener("focus", tekenRandje);
picts[i].addEventListener("blur", verwijderRandje);
}
function probeer() {
try {
document.querySelector(":focus-within");
} catch (error) {
return false;
}
return true;
}
function tekenRandje(e) {
e.target.previousSibling.setAttribute("style", "outline: green dotted 3px;");
}
function verwijderRandje(e) {
e.target.previousSibling.removeAttribute("style");
}
}) ();
</script>
Als je bovenstaande code ergens aanraakt of ‑klikt, ga je rechtstreeks naar de bijbehorende uitleg.
Dit script bestaat uit twee delen.
Het JavaScript voor iOS bestaat uit één simpele regel. Zonder deze regel worden de afbeeldingen op iOS alleen in Firefox, Opera Mini en Microsoft Edge getoond.
Het overige JavaScript is iets langer. Sommige mensen gebruiken niet de muis of aanraken om naar een link, tekstveld, en dergelijke te gaan, maar de Tab-toets. Bijvoorbeeld omdat ze moeite hebben een muis te gebruiken, maar soms is het gewoon ook veel sneller dan een muis.
Als een element met de Tab-toets wordt bezocht, heeft dat element focus. Dat wordt aangegeven door een kadertje rondom het element. Dat is belangrijk, want anders is niet duidelijk, welk element focus heeft. Bij focus wordt een link gevolgd door op Enter te drukken, in een tekstveld kan tekst worden ingevoerd, enzovoort.
In dit voorbeeld kunnen de afbeeldingen ook met behulp van de Tab-toets worden getoond.
Als iemand ergens op de pagina gemarkeerde tekst aanraakt of erover hovert, is duidelijk bij welke tekst de getoonde afbeelding hoort. Maar bij gebruik van de Tab-toets is dat onduidelijk. Daarom wordt bij .buiten:focus-within .markeer met behulp van :focus-within
een kadertje getekend rondom de tekst, waarbij de getoonde afbeelding hoort.
Voor browsers die het relatief nieuwe :focus-within
niet ondersteunen, wordt dat in dit script geïmiteerd.
Als dit script op meerdere pagina's wordt gebruikt, kan het ook als een extern script worden gebruikt: <script src="pad-naar-script/script.js"></script>
In dat geval moet <script> helemaal onderaan de pagina worden gezet, gelijk boven </body>. Het script zoekt namelijk elementen in de pagina op, en als die nog niet zijn gemaakt door de browser, gaat het mis. Bovendien stopt de opbouw van de pagina, zodra de browser een script ontmoet, omdat het script eerst wordt uitgevoerd. Het zou immers kunnen dat het script (heel) belangrijk is voor de weergave. Dat is hier niet het geval. Door het script onderaan de pagina te zetten, voorkom je ook die in dit geval overbodige vertraging.
<script></script>
Dit is gewone html: het zijn de openings- en sluittag voor het script. In html5 is de toevoeging type="text/javascript"
niet meer nodig.
JavaScript nodig voor iOS
document.getElementsByTagName("body")[0].addEventListener("touchstart", function () {return null; });
document.getElementsByTagName("body")
: het eerste stukje.
getElementsByTagName
is een zogenaamde 'functie'. Een functie is een stukje in de browser ingebakken code, waarmee je iets kunt doen. Deze functie is te vinden in het object document
, vandaar dat document
ervoor staat.
Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.
JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document
bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.
Met de methode getElementsByTagName()
uit document
kan JavaScript alle elementen van 'n bepaalde soort opzoeken. De tags waarnaar wordt gezocht, staat tussen haakjes:
"getElementsByTagName("body")
Jij en ik weten dat er maar één <body> is, maar een browser is nou eenmaal niet zo slim, dus die zoekt trouwhartig naar álle <body>'s. En vindt er uiteraard maar eentje.
[0]
: de gevonden tags worden geretourneerd in de vorm van een lijst. Als er bijvoorbeeld honderd <div>'s zouden worden gevonden, heeft deze lijst honderd items. Zo'n item kun je aanspreken door het volgnummer te gebruiken. En omdat computers dol zijn op '0', is het volgnummer van het eerste item '0', en geen '1'.
Uiteraard is er maar één <body> gevonden. Het volgnummer van die <body> is dus '0', het eerste item.
document.getElementsByTagName("body")[0]
samen: doe iets met het element <body>.
addEventListener
: voeg aan <body> een 'eventlistener' toe. Dat is een ding dat luistert, of er iets gebeurt. Zo'n gebeurtenis kan een aanraking van het scherm zijn, een liefdevolle aai van de muis, een ram op het toetsenbord, van alles.
"touchstart"
: in dit geval wordt naar het begin van een aanraking van het touchscreen geluisterd. Dat is nog niet zo interessant, het wordt pas echt opwindend wat er ná die eerste, inleidende aanraking gaat gebeuren... Vinden zij elkaar, of wordt het moord- en doodslag?
function () {return null; }
: Helaas, ze vinden elkaar niet én het wordt geen moord- en doodslag.
function()
is gewoon een soort aankondiging dat er iets gaat gebeuren. Erachter tussen de accolades staat, wat er gaat gebeuren: return null;
. Doe niets. Helemaal niets. Vanavond niet, schat, ik heb hoofppijn.
Overige JavaScript (voor kadertje)
De rest van het script zorgt voor een kadertje rondom de gemarkeerde tekst die bij de getoonde afbeelding hoort.
(function () {
function
: het sleutelwoord waarmee het begin van een functie wordt aangegeven. Een functie is een stukje bij elkaar horende code. (Het haakje helemaal aan het begin wordt iets verderop beschreven.)
()
: achter een functie moeten twee haakjes staan. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie, maar bij deze functie gebeurt dat niet.
{
: geeft het begin van de code binnen de functie aan. Aan het eind van de functie, dat is in dit geval helemaal onderaan in de laatste regel van het script, staat een bijbehorende }
.
In die laatste regel staat in dit geval nog meer dan alleen de }
die het einde van de code aangeeft: }) ();
}
: dit is de eerder genoemde afsluitende }
, waarmee het einde van de code in de functie wordt aangegeven.
)
: dit afsluitende haakje is de tegenhanger van het haakje dat voor de functie staat. Samen zorgen ze ervoor dat de hele functie, met alles erop en eraan, tussen haakjes staat. De reden van deze haakjes wordt iets hieronder besproken.
()
: dit is weer gewoon een taalregel van JavaScript. In dit geval moeten er achter de })
nog twee haakjes staan. Een computer is gewoon niet zo slim, anders weet de ziel niet wat er moet gebeuren.
;
: met de puntkomma wordt in JavaScript een regel afgesloten. Het is te vergelijken met een gewone punt in een tekst.
We hebben hier een script, waarin alle code binnen een functie is geplaatst. Alle code staat tussen {
en }
, zodat de computer het begin en einde van de functie kan herkennen.
Een functie is een stukje bij elkaar horende code dat je, zo vaak als je wilt, kunt uitvoeren. Als je de tafel van twaalf op het scherm wilt zetten, hoef je niet twaalf vermenigvuldigingen in JavaScript te schrijven, maar schrijf je 'n functie voor één vermenigvuldiging, die je vervolgens tien keer (op steeds iets andere wijze) uitvoert.
Een functie heeft echter één probleem: de code in de functie wordt pas uitgevoerd, als de functie wordt aangeroepen. Dat aanroepen kan op allerlei manieren gebeuren, bijvoorbeeld als de gebruiker 'n toets indrukt, als de pagina is geladen, als het 13:13 is op vrijdag de dertiende, noem maar op. Maar zonder te worden aangeroepen doet een functie helemaal niets.
In dit script is dat ook zo. Er zit bijvoorbeeld een functie in die kijkt of de browser de css-pseudo-class :focus-within
ondersteunt. Om die functie goed te laten werken, moet de computer eerst wat voorbereidend werk verrichten. Daarvoor moet het script worden gelezen. Maar dat hele script zit in een functie, en die functie doet dus pas wat, als die wordt aangeroepen.
Om te zorgen dat de buitenste functie, die waar alle code in zit, toch vanzelf wordt uitgevoerd, zet je er een (
voor. En helemaal aan het eind, achter de afsluitende }
, zet je de tegenhanger )
. Nu wordt de functie automatisch uitgevoerd, zonder dat deze hoeft te worden aangeroepen. En kan de code in het script worden gelezen, waardoor het benodigde voorbereidende werk kan worden uitgevoerd.
(Je kunt de code ook in een niet alles omvattende functie zetten. Dan wordt de code gelijk uitgevoerd. Maar dat brengt belangrijke risico's met zich mee. In dit script worden namen voor variabelen gebruikt als 'focusWithin' en 'len'. Als nou een ander JavaScript toevallig dezelfde namen zou gebruiken, gaat het gruwelijk mis. Door het hele script in een functie te stoppen, voorkom je dat. Als je hier meer over wilt weten, kun je op internet zoeken naar 'name conflict' of 'name clash'.
De bovenste regel van dit script staat buiten deze functie, die wordt dus automatisch uitgevoerd. Het hierboven genoemde risico voor een conflict bestaat daar niet, omdat in die regel geen variabelen worden gebruikt.)
"use strict";
Deze regel zorgt ervoor dat bepaalde slordigheden in de code, die makkelijk tot grote problemen kunnen leiden, niet meer mogen. Een validator (die controleert op fouten in de code) is nu strenger en keurt meer dingen af.
Een klein aantal oudere browsers ondersteunt dit niet, maar die hebben er verder geen last van, omdat ze de regel gewoon negeren.
var focusWithin = probeer(),
In dit deel van de code worden een paar dingen voorbereid. Het écht uitvoerende deel van het script, waarin bijvoorbeeld een toetsaanslag daadwerkelijk wordt herkend, volgt later.
Het is gebruikelijk dit soort voorbereidende zaken bovenin het script te zetten.
Deze regel valt in een aantal delen uiteen, die worden gescheiden door een komma. Het eerste deel begint met var
. Dit sleutelwoord var
wordt automatisch ook voor de andere delen geplaatst, omdat die delen op een komma volgen. Door die komma weet het script dat het hier om bij elkaar horende delen van één regel gaat.
Na het laatste deel staat een puntkomma. Dit is het echte einde van deze regel code. In gewone tekst zou je hier een punt gebruiken.
Het is gebruikelijk zo'n tweede, derde, ... deel op een nieuwe regel te laten beginnen en iets in te laten springen. Zo zie je in één oogopslag dat het sleutelwoord var
voor alle delen geldt, dat hier dertien variabelen worden aangemaakt: in elke regel één.
Pardon? Variwiewatwaar? Ha, leuk dat je het vraagt.
var
: het begin van het eerste deel van de eerste regel. Met het sleutelwoord var
wordt aangegeven dat elk van de erop volgende woorden de naam van een 'variabele' is. Een variabele is een soort portemonnee: er kan van alles in zitten, en de inhoud kan veranderen.
Gelijk na var
volgen de namen van de variabelen. Als er meerdere variabelen zijn, zoals hier het geval is, worden die gescheiden door een komma. Hier zijn de variabelen 'focusWithin', 'picts', 'len' en 'i'. Elke variabele staat óf helemaal alleen op een eigen regel, óf aan het begin van een regel, gelijk gevolgd door een isgelijkteken.
In 'focusWithin', 'picts', 'len', en 'x'. wordt dus iets opgeborgen. Omdat de variabele een naam heeft, kan de rest van het script de variabele aanroepen bij deze naam. Net zoals je iemand die 'Marie' heet kunt aanroepen met 'Marie', ongeacht of Marie aardig, onaardig, muzikaal of arrogant is, ongeacht de 'inhoud' van Marie.
Wat er precies in die variabelen wordt opgeslagen, kun je hier opgeven of elders in het script. Als het om iets simpels gaat, wordt het hier opgegeven. Als het om iets meer ingewikkelds gaat, of als nog niet bekend is wat moet worden opgeslagen, gebeurt het later.
De variabelen krijgen hier hun naam, ze worden hier 'gedeclareerd' of 'aangemaakt'. Dat gebeurt in de volgorde, waarin ze in het script worden gebruikt. Die volgorde hoeft niet, dat is een kwestie van voorkeur. Je hoeft ook niet alle variabelen aan het begin van een functie aan te maken, maar dat is wel overzichtelijker.
Een gebruikelijke manier om de namen van variabelen weer te geven is 'camelCase'. Hierbij staat aan het begin geen hoofdletter, maar bij elk nieuw woord in de naam wel: 'focusWithin'. In css zou je dit schrijven als 'focus-within', maar koppeltekens mogen in JavaScript niet worden gebruikt in namen van variabelen. De hoofdletters zorgen dat de namen toch leesbaar zijn.
Dingen als het gebruik van hoofdletters zijn geen absolute eisen, maar het zijn wel 'n soort afspraken, waar vrijwel elke programmeur zich aan houdt. Door je aan dit soort afspraken te houden, is je code ook leesbaarder voor anderen (en voor jezelf over acht jaar...).
Hieronder worden de aangemaakte variabelen één voor één doorgenomen.
focusWithin = probeer(),
Het tweede deel van de eerste regel. Hier wordt de eerste variabele aangemaakt.
focusWithin
: dit is de variabele, waarin iets moet worden opgeborgen.
=
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat moet worden opgeslagen.
probeer()
: dit is, wat in focusWithin
moet worden opgeslagen. Het is een aanroep van een zogenaamde 'functie': een stukje bij elkaar horende code dat vaker kan worden uitgevoerd. Dat uitvoeren doe je door het aan te roepen met de naam van de functie: probeer()
. De haakjes achter zo'n aanroep zijn een verplichte taalregel, anders weet de browser niet dat het om een functie gaat. (Je kunt tussen de haakjes ook informatie doorgeven aan de functie, maar dat gebeurt hier niet.)
Bij het vullen van focusWithin
wordt deze functie al aangeroepen en dus uitgevoerd. De functie zelf staat een heel eind verderop, maar dat maakt niets uit. Functie probeer() kijkt, of de browser de css-pseudo-class :focus-within
ondersteunt. Als dat zo is, retourneert de functie de waarde true
(waar). Als :focus-within
niet wordt ondersteund, wordt de waarde false
(niet waar) geretourneerd.
Die waarde true
of false
wordt in variabele focusWithin
opgeslagen en kan later worden gebruikt om te kijken, welke code moet worden toegepast: als focusWithin
waar (true
) is, doe dan dit. Als focusWithin
niet waar (false
) is, doe dan dat.
,
: de regel eindigt hier niet, er moeten nog meer variabelen worden aangemaakt.
De hele declaratie: sla in variabele focusWithin
het resultaat van functie probeer()
op: true
of false
.
picts,
In deze variabele wordt voor elke <img> in de html een zogenaamd object opgeslagen: een verzameling informatie en dergelijke over elke afbeelding, zoals breedte en hoogte. Met zo'n object kun je ook allerlei dingen doen, zoals css toevoegen.
Je zou dat opslaan van objecten ook hier al kunnen doen, omdat het tamelijk eenvoudig is, maar omdat dit een uitleg is, gebeurt dat pas later.
Over wat een variabele is, is meer te vinden bij var focusWithin = probeer(),
len,
In deze variabele wordt later het aantal <img>'s opgeslagen.
Over wat een variabele is, is meer te vinden bij var var focusWithin = probeer(),
i;
i
: deze variabele wordt op een aantal plaatsen als teller gebruikt. Aan het begin van een berekening wordt er 'n getal in gestopt. Het is gebruikelijk om dit soort tellers de naam 'i' te geven. Dat soort gewoontes maakt het makkelijker code van anderen te lezen. Hier wordt de variabele alleen aangemaakt, er wordt pas iets in gestopt, als er geteld moet worden.
Over wat een variabele is, is meer te vinden bij var var focusWithin = probeer(),
;
: de regel waarin variabelen worden aangemaakt, eindigt hier. Aan het eind van de eerdere regels, waarin een variabele werd aangemaakt, stond steeds een komma: er moest nog een variabele worden aangemaakt. De puntkomma geeft het definitie einde van de regel aan, er hoeven geen verder variabelen te worden aangemaakt.
Tot nu toe is alleen een aantal noodzakelijke gegevens opgevraagd en opgeborgen. Vanaf nu gaat het script echt beginnen.
if (focusWithin) return;
if
: dat betekent gewoon 'als': als aan de voorwaarde hierachter is voldaan. Die voorwaarde staat tussen haakjes, omdat dat nou eenmaal zo hoort. Als aan de voorwaarde wordt voldaan, wordt de code achter de voorwaarde uitgevoerd.
focusWithin
: het deel tussen de haakjes. Dat is hier maar één woord, maar dat kan veel meer zijn.
Om te bepalen of aan de voorwaarde wordt voldaan, wordt gekeken naar de inhoud van variabele focusWithin
. Die inhoud is eerder bepaald bij var focusWithin = probeer(),. Daar werd de uitslag van functie probeer() in focusWithin
gestopt: als de browser de css-pseudo-class :focus-within
ondersteunt, is de uitslag true
('waar') en bevat focusWithin
de waarde true
. Als de browser :focus-within
niet ondersteunt, is de uitslag false
('onwaar') en bevat focusWithin
de waarde false
.
Oftewel: als de browser :focus-within
ondersteunt, is de voorwaarde voor de if
waar en wordt rest van de regel uitgevoerd.
Als de browser :focus-within
niet ondersteunt, is de voorwaarde voor de if
niet waar en wordt de rest van de regel niet uitgevoerd.
return;
: Met het sleutelwoord return
wordt de functie afgebroken: de rest van de code wordt gewoon niet uitgevoerd. De ;
geeft weer het eind van de regel aan.
Deze regel kijkt dus, of de browser :focus-within
ondersteunt. Als dat zo is, als aan de voorwaarde voor de if
wordt voldaan, wordt return
Als de browser :focus-within
niet ondersteunt, wordt return
niet uitgevoerd. En wordt de rest van de code dus uitgevoerd.
Deze regel staat binnen de functie die begint met (function () {. Dit is de buitenste functie (je kunt functies ook in elkaar nesten). Als deze functie wordt verlaten, is er voor het script verder niets meer te doen.
En dat is precies de bedoeling: als de browser :focus-within
ondersteunt, is dit hele script overbodig.
Een if
kan enorm ingewikkeld worden, zowel de voorwaarde als de eventueel uit te voeren code. Om de code voor mensen leesbaar te houden wordt een if
met de bijbehorende code daarom meestal over een (groot) aantal regels uitgesplitst. Omdat deze if
superkort is, is het in dit geval duidelijker alles op dezelfde regel te zetten.
picts = document.getElementsByClassName("pict");
picts
: dit is de variabele, waarin iets moet worden opgeborgen. Deze variabele is al eerder bij picts, aangemaakt, nu wordt er iets in opgeborgen.
=
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat moet worden opgeslagen.
document.getElementsByClassName("pict")
: het middelste stukje getElementsByClassName
is een zogenaamde 'functie'. Een functie is een stukje in de browser ingebakken code, waarmee je iets kunt doen. Deze functie is te vinden in het object document
, vandaar dat document
ervoor staat.
Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.
JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document
bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.
Met de methode getElementsByClassName()
uit document
kan JavaScript alle elementen met 'n bepaalde class opzoeken. De class waarnaar wordt gezocht, staat tussen haakjes:
getElementsByClassName("pict")
De elementen met de gevraagde class 'pict' worden geretourneerd in de vorm van een lijst. In het voorbeeld zitten 37 <span>'s met class="pict", dus er worden 37 elementen gevonden en in de lijst gestopt.
Als je de in de html de classnaam 'pict' verandert, moet je die ook in deze regel veranderen.
;
: de ;
geeft weer het eind van de regel aan.
De hele regel: er worden 37 elementen in variabele picts
gestopt: elke <span> met class="pict" uit de html van het voorbeeld.
Van elk van deze 37 elementen wordt in variabele picts
een ongelooflijke hoeveelheid informatie gestopt, waar het script later gebruik van kan maken. Zo zit bijvoorbeeld alle css, die aan elk van die <span>'s is gegeven, ook in picts
. Maar niet alleen de in de stylesheet opgegeven css, ook alle standaardwaarden, en ook alle css die van voorouders wordt geërfd. Alle eventuele nakomelingen van elke <span> en hun css, attributen, enzovoort, zitten ook in picts
. Van al deze informatie in picts
kan het script gebruik maken. En ook kunnen veel van deze dingen worden veranderd door het script, zoals een andere kleur, of een element verwijderen, of juist toevoegen.
Feitelijk is elk van de 37 <span>'s in de vorm van een object in picts
opgeslagen. Naast allerlei informatie die in elk item wordt opgeslagen, kun je daardoor ook gebruik maken van allerlei methoden (functies), die JavaScript gratis en voor niets toevoegt aan picts
.
Het script gebruikt picts
om bepaalde css toe te voegen als een span met class="pict" focus krijgt, en deze weer te verwijderen als de <span> de focus weer verliest. Die css zorgt voor een kadertje rondom de gemarkeerde woorden, die bij de getoonde afbeelding horen.
Je kunt 'n bepaald item uit de lijst aanspreken door het volgnummer te gebruiken. En omdat computers dol zijn op '0', is het volgnummer van het eerste item '0', en geen '1'. picts[0]
is de eerste in picts
opgeslagen <span>, picts[7]
is de achtste in picts
opgeslagen <span>.
len = picts.length;
len
: bij len, is deze variabele al aangemaakt, maar er is nog niets mee gedaan. Hier gaat er iets in worden opgeborgen.
=
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat moet worden opgeslagen.
picts
: bij picts = document.getElementsByClassName("pict"); is elke <span class="pict">
in de vorm van een eigen object opgeslagen in picts
. In het voorbeeld zijn dit er 37, dus er zitten 37 objecten in picts
.
length
: variabele picts
heeft zelf ook wat informatie, onder andere het aantal items dat erin is opgeslagen. Dat aantal zit in de eigenschap length
. Omdat er 37 objecten – één voor elke <span> met class="pict" – in zitten, is de lengte van picts
37.
De hele regel: sla in len
het aantal objecten in picts
– oftewel: het aantal <span>'s met class="pict" – op. Omdat dat aantal eerder door het script is vastgesteld, wordt dit aantal automatisch aangepast, als het aantal <span>'s met class="pict" in de pagina verandert door het toevoegen of verwijderen van 'n <span> met class="pict" in de html.
for (i = 0; i < len; i++) {
for
: doe iets met iets, zolang iets waar is. Nou, is dat lekker vaag of niet? Wat er waarmee moet gebeuren, komt later. Dat staat tussen de {}
aan het eind van de regel. (In de echte code staat de laatste }
lager, achter wat er waarmee moet gebeuren.)
Hier eerst het deel dat ervoor zorgt alle 37 <span>'s met class="pict" worden behandeld.
(
: met dit haakje opent het deel dat ervoor zorgt, dat alle 37 <span>'s aan de beurt komen. Aan het eind van de regel staat de bijbehorende )
, waardoor het script weet dat dit het einde van dit deel van de code is.
i = 0;
: hiermee geef je in JavaScript aan dat in de voor het isgelijkteken staande variabele het resultaat van wat achter het isgelijkteken staat, moet worden opgeslagen. In dit geval is dat resultaat heel simpel: het is het getal 0.
De variabele i
is al eerder aangemaakt bij i, en kan daarom hier nu gewoon worden gebruikt.
Omdat i
een variabele is, kan de waarde ervan veranderen, variëren. Wat later in de regel ook gaat gebeuren: elke keer als een <span> is afgehandeld, wordt i
met 1 verhoogd. Dat gebeurt in het laatste deel van de regel.
De ;
geeft aan dat dit stukje code, waarin variabele i
z'n beginwaarde krijgt, hier eindigt.
i++
: eerst het laatste deel, het middelste deel komt gelijk hieronder.
Elke keer als een <span> 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 ('2' dus).
Als i
2 is, betekent i++
: i
wordt 2 + 1 ('3' dus).
(...)
Als i
36 is, betekent i++
: i
wordt 36 + 1 ('37' dus). En meer dan 37 wordt het niet, vanwege redenen die gelijk hieronder staan.
i < len;
: het middelste deel.
i
bevat een getal. Als er nog geen enkele <span> is verwerkt, is dat getal 0, want dat is hierboven opgegeven.
Het teken <
betekent: kleiner dan.
In len
is iets hoger bij len = picts.length; het aantal <span>'s met class="pict" opgeslagen. In het voorbeeld is dat 37. Eigenlijk staat hier dus: i < 37;
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 37.
Als niet meer aan deze voorwaarde wordt voldaan, als teller i
niet meer kleiner is dan de 37 in len
, stop dan met het uitvoeren van de code die tussen de {}
staat. En omdat 37 even groot is als het aantal <input>'s in het menu dat moet worden bekeken, geeft dit een mogelijkheid om elke <input> één keer te verwerken. En er, als ze allemaal verwerkt zijn, mee te stoppen.
)
: dit haakje hoort bij de (
gelijk achter for
. Tussen deze twee haakjes staat de code, die ervoor zorgt dat elk niveau in het menu 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 met elk item uit picts
, met elke <span> met class="pict", íé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 zetten op één onwijs lange regel. Alleen is niet alleen die regel dan onwijs, ook de gemiddelde programmeur zou heel snel bijzonder onwijs worden, als alles op één lange regel wordt gezet.
Elke keer als een <span> met class="pict" 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 36e ronde heeft i
de waarde 37. Waarmee i
niet meer kleiner is dan de 37 in len
, het aantal <spans>'s.
Omdat niet meer aan de voorwaarde i < len
wordt voldaan, wordt gestopt met het uitvoeren van de code tussen de {}
. En dat komt goed uit, want alle <span class="pict">
'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.
(Wat mogelijk wat verwarrend is: het script begint te tellen met 0. De eerste <span> heeft dus volgnummer 0, en de 36e <span> heeft volgnummer 37. Ook al stopt de for-lus bij 36, er worden dus toch 37 <input>'s bekeken.)
De code tussen de haakjes in gewone taal: zet teller i
op 0 als de for
de eerste keer wordt uitgevoerd. Herhaal de for
zolang teller i
lager is dan de 37 in len
. Verhoog teller i
elke keer als de for
wordt uitgevoerd met 1.
picts[i].addEventListener("focus", tekenRandje);
Deze regel zit binnen een for-lus en wordt voor elke <span> met class="pict" één keer uitgevoerd.
pics[i]
: in de variabele pics
zijn bij picts = document.getElementsByClassName("pict"); alle <span>'s met class="pict" opgeslagen. (Feitelijk is voor elke <span> een object opgeslagen, waarin allerlei informatie over de <span> zit, zoals de bijbehorende css.)
De teksthaken []
geven aan dat hierin een teller zit. Die teller is hier de variabele i
. In de for-lus, waarbinnen deze regel staat, heeft i
het volgnummer gekregen van de <span> die aan de beurt is.
addEventListener
: er wordt een zogenaamde 'eventlistener' gekoppeld aan het voor de punt staande deel. Dat is hier picts[i]
, de <span> die aan de beurt is.
Een eventlistener luistert naar een gebeurtenis. Die gebeurtenis, de 'event', kan van alles zijn: het indrukken van een toets, klikken, scrollen, de video is afgespeeld, van alles. Tussen de haakjes van addEventListener()
staat, naar welke soort gebeurtenis moet worden geluisterd, en wat er moet gebeuren, als die gebeurtenis zich voordoet. Zeg maar 'n soort rampenplan: áls gebeurtenis is 'doodsmak', dán handeling 'bel 112'.
"focus"
: tussen aanhalingstekens, zodat het script weet dat dit een letterlijke naam is (dit is gewoon een van de taalkundige regels van JavaScript). Dit is de naam van de gebeurtenis, waarnaar wordt geluisterd, waarop wordt gewacht: 'focus'. Er wordt geluisterd of de <span> focus krijgt.
tekenRandje
: deze naam staat niet tussen aanhalingstekens, omdat het hier niet om een letterlijke naam of zo gaat. De naam verwijst naar een 'functie', iets wat moet gebeuren. Die functie staat iets hieronder bij function tekenRandje(e) { en zorgt voor een randje rondom de gemarkeerde tekst die bij de getoonde afbeelding hoort.(Probeer op dit moment vooral niet de logica van wel of geen aanhalingstekens te begrijpen. Het makkelijkste is om dat soort dingen maar gewoon te accepteren. Nederlands heeft ook zo z'n eigenaardigheden...)
;
: aan het eind van elke regel staat een puntkomma. Daarmee geef je aan dat de regel is afgelopen. In een gewoon boek zou je hier een punt gebruiken, om aan te geven dat een nieuwe zin begint.
De hele regel nog eens in gewone mensentaal: als een <span> met class="pict" focus krijgt, voer dan functie 'tekenRandje ()' uit.
picts[i].addEventListener("blur", verwijderRandje);
Deze regel zit binnen een for-lus en wordt voor elke <span> met class="pict" één keer uitgevoerd.
Deze regel werkt precies hetzelfde als die iets hierboven bij picts[i].addEventListener(focus, "tekenRandje");. De enige verschillen: hier wordt geluisterd naar 'blur': de <span> verliest de focus weer. Als dat gebeurt, wordt functie verwijderRandje(e) uitgevoerd: haal het randje rondom de gemarkeerde tekst weer weg.
function probeer() {
Ook deze functie is, zoals elke functie, weer een stukje bij elkaar horende code. Maar anders dan de buitenste functie wordt deze niet automatisch uitgevoerd. (Waarom de buitenste functie wel automatisch wordt uitgevoerd, is te vinden bij (function () {.)
De code in deze functie wordt alleen uitgevoerd, als de functie wordt aangeroepen. Dat aanroepen gebeurt, als variabele focusWithin
wordt aangemaakt bij var focusWithin = probeer(),
De code kijkt, of de browser de css-pseudo-class :focus-within
ondersteunt. Als dat zo is, retourneert de functie de waarde true
, die dan in variabele focusWithin
wordt opgeslagen. Als :focus-within
niet wordt ondersteund, retourneert de functie de waarde false
.
function
: het sleutelwoord waarmee het begin van een functie wordt aangegeven.
probeer
: 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.)
()
: die haakjes horen nou eenmaal zo na de naam van een functie. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie. Dat gebeurt hier niet.
{
: geeft het begin van de code binnen de functie aan. Aan het eind van de functie staat een bijbehorende }
.
try {
Deze regel is onderdeel van function probeer() {
Binnen een try
-blok staat code, die mogelijk een fout kan opleveren. Er wordt geprobeerd ('try') de code uit te voeren. Als dat lukt, wordt gewoon de rest van de code uitgevoerd. Maar als een fout wordt gegenereerd, wordt de code na } catch (error) { uitgevoerd.
Een 'fout' moet je niet al te letterlijk nemen. In dit geval wordt gekeken, of de browser de css-pseudo-class :focus-within
ondersteunt. Als dat niet zo is, wordt een fout gegenereerd.
document.querySelector(":focus-within");
Deze regel is onderdeel van function probeer() {
Deze regel is onderdeel van een try-blok.
Het middelste stukje querySelector
is een zogenaamde 'functie'. Een functie is een stukje in de browser ingebakken code, waarmee je iets kunt doen. Deze functie is te vinden in het object document
, vandaar dat document
ervoor staat.
Een object is een bij elkaar horende verzameling van functies en andere code. Een van die objecten heeft de naam 'document'. Bij een object werkt een functie alleen een klein beetje anders dan een gewone functie, daarom heet een functie uit een object 'methode'.
JavaScript heeft een groot aantal ingebakken objecten, waar je gebruik van kunt maken. In document
bijvoorbeeld zit heel veel informatie over de pagina, en er zitten heel veel methodes in om met die informatie te kunnen werken.
Met de methode querySelector()
uit document
kan JavaScript een bepaalde selector opzoeken. De selector waarnaar wordt gezocht, staat tussen haakjes:
querySelector(":focus-within")
Als :focus-within
niet wordt ondersteund door de browser, wordt een fout gegenereerd. In dat geval wordt die fout ('error') iets hieronder gevangen ('catch') en wordt de code achter } catch (error) {
uitgevoerd. Die code retourneert false
en dat wordt dan opgeslagen in variabele focusWithin
. (Want de functie probeer()
, waar dit try
-blok onderdeel van is, is aangeroepen bij het aanmaken van variabele focusWithin
bij var focusWithin = probeer(),.)
Als geen fout wordt gegenereerd, als :focus-within
door de browser wordt ondersteund, wordt de code achter } catch error {
niet uitgevoerd. Er wordt dan doorgegaan met de eerste regel na het catch
-blok: return true;
: in focusWithin
wordt nu true
opgeslagen.
} catch (error) {
Deze regel is onderdeel van function probeer() {
De in het catch
-blok zittende code wordt alleen uitgevoerd, als door het bijbehorende try-blok een fout is gegenereerd (als de browser de css-pseudo-class :focus-within
niet ondersteunt).
}
: dit is de afsluitende accolade van de code van het try
-blok. De openings-accolade staat bij try {.
catch (error)
: catch
is gewoon het sleutelwoord dat aangeeft dat hier de fout wordt afgehandeld. Tussen de haakjes wordt een zogenaamd fout-object doorgegeven, waarvan de naam 'error' is. Je mag het ook 'wilhelmina' noemen in plaats van 'error', maar 'error' is min of meer een standaardnaam. Zo houd je je code 'n beetje leesbaar. Niet alleen voor jezelf, maar ook voor anderen.
In error
zit een hele serie informatie over de fout, maar die wordt hier verder niet gebruikt.
{
: deze accolade geeft aan dat hier de code begint die moet worden uitgevoerd, als zich een fout heeft voorgedaan. Aan het eind van deze code staat weer een afsluitende }
.
return false;
Deze regel is onderdeel van function probeer() {
Dit deel van het script wordt alleen uitgevoerd, als het try-blok een fout heeft gegenereerd (als de browser de css-pseudo-class :focus-within
niet ondersteunt).
return
zorgt ervoor dat de rest van functie probeer()
niet meer wordt uitgevoerd. Omdat er false
achter staat, wordt de waarde false
geretourneerd naar de aanroepende code. Die waarde false
wordt in variabele focusWithin
opgeslagen. (Want de functie probeer()
, waar deze regel onderdeel van is, is aangeroepen bij het aanmaken van variabele focusWithin
bij var focusWithin = probeer(),.)
return true;
Deze regel is onderdeel van function probeer() {
Dit deel van het script wordt alleen uitgevoerd, als het try-blok geen fout heeft gegenereerd (als de browser de css-pseudo-class :focus-within
ondersteunt).
Als het try-blok geen fout heeft gegenereerd, wordt deze regel uitgevoerd: functie probeer()
retourneert de waarde true
. Die waarde true
wordt in variabele focusWithin
opgeslagen. (Want de functie probeer()
, waar deze regel onderdeel van is, is aangeroepen bij het aanmaken van variabele focusWithin
bij var focusWithin = probeer(),.)
function tekenRandje(e) {
Ook deze functie is, zoals elke functie, weer een stukje bij elkaar horende code. Maar anders dan de buitenste functie wordt deze niet automatisch uitgevoerd. (Waarom de buitenste functie wel automatisch wordt uitgevoerd, is te vinden bij (function () {.)
De code in deze functie wordt alleen uitgevoerd, als de functie wordt aangeroepen. Dat aanroepen gebeurt, als een <span> met class="pict" focus krijgt. Het luisteren naar dat focus krijgen wordt geregeld bij picts[i].addEventListener("focus", tekenRandje);.
De code in deze functie regelt, wat er gebeurt, als een <span> met class="pict" focus krijgt. Als de <span> de focus krijgt, wordt een kadertje rondom de bijbehorende gemarkeerde tekst gezet. Dit gebeurt door het toevoegen van een beetje css aan de <span> in de html. Als je die toevoeging wilt bekijken moet je niet de gewone code, maar de Gegenereerde code bekijken.
function
: het sleutelwoord waarmee het begin van een functie wordt aangegeven.
tekenRandje
: de naam van de functie. Als het beestje geen naam heeft, kun je het ook niet aanroepen en heb je er dus niets aan. (Dit klopt niet helemaal. JavaScript kent ook equivalenten van 'hé!', 'hé, jij daar!', 'hé, jij daar in die zwarte jas', en dergelijke, maar die worden hier niet gebruikt. En het is zo al ingewikkeld genoeg.)
(e)
: die haakjes horen nou eenmaal zo na het sleutelwoord function
. Behalve dat het gewoon zo hoort, kun je hier ook van alles in stoppen om door te geven aan de code in het binnenste van de functie. Zoals de plaats waar het scherm is aangeraakt of ‑geklikt. In dit geval wordt e
doorgegeven.
e
is een zogenaamd object. In een object zitten allerlei gegevens over hoe de functie is aangeroepen (over dat aanroepen later meer). In dit geval wordt deze functie aangeroepen, als een <span> met class="pict' focus heeft gekregen. In e
zit bijvoorbeeld de hoogte en breedte van de <span>. En nog 'n waanzinnige hoop andere informatie, waarvan het overgrote deel hier verder niet wordt gebruikt.
Los hiervan voegt JavaScript aan e
allerlei methodes toe: functies binnen het object, waarmee je allerlei dingen kunt doen.
Heel formeel is e
eigenlijk geen object, maar is e
een parameter, iets dat wordt doorgegeven aan de functie, zodat het binnen die functie gebruikt kan worden. e
is de naam van het object, en de inhoud van e
is een object. Om het object iets te kunnen vragen, of het iets te laten doen, moet het beestje 'n naam hebben: e
.
De naam e
voor het object is niet verplicht, maar 'n soort afspraak, zodat code makkelijker door anderen is te begrijpen. Maar als je het object niet e
, maar 'hetIsStervenskoud' wilt noemen, is daar technisch geen enkel bezwaar tegen. Het is dan wel verstandig een cursus zelfverdediging te volgen, voor het geval iemand anders ooit je code moet bekijken.
(e
is een afkorting van 'event', gebeurtenis. De functie reageert op een gebeurtenis, in dit geval het krijgen van focus door de <span>. In e
zit het object dat bij díé gebeurtenis hoort. Bij bijvoorbeeld een muisklik krijg je een ander object met andere informatie dan bij het indrukken van een toets.)
{
: geeft het begin van de code binnen de functie aan. Aan het eind van de functie staat een bijbehorende }
.
e.target.previousSibling.setAttribute("style", "outline: green dotted 3px;");
Deze regel is onderdeel van function tekenRandje(e) {
e
: het bij function tekenRandje(e) { aan de code in de functie doorgegeven object, waarin onder andere allerlei informatie zit over de <span> die focus heeft.
target
: dit is een onderdeel van het hierboven genoemde object e
. In target
zit, in de vorm van een object, informatie over de <span> met class="pict" die focus heeft. Ook dat is weer heel veel informatie: het soort element, eventuele tekst erin, nakomelingen, wat de ouder is, noem maar op.
previousSibling
: het vorige element in de html. In het hierboven genoemde target
zit, in de vorm van een object, de <span> met class="pict" die focus heeft. Omdat previousSibling
achter target
staat, gaat het om het element vóóŕ het element dat in target
zit. Dat is altijd een <span> met class="markeer", waarin gemarkeerde tekst zit, want in de <html> volgt altijd een <span> met class="pict" op een <span> met class="markeer".
Omdat deze twee <span>'s altijd gelijk op elkaar volgen in de html, weet je altijd zeker dat de <span> met gemarkeerde tekst bij de <span> met focus hoort. En dus bij de getoonde afbeelding.
Ook deze <span> met class="markeer" is weer beschikbaar in de vorm van een object, waardoor veel informatie over de <span> beschikbaar is. En allerlei methoden uit het object gebruikt kunnen worden.
setAttribute()
: dit is zo'n methode. Eigenlijk is dit een gewone functie, maar omdat het om een functie uit een object gaat, werkt die soms net iets anders dan een gewone functie. Daarom wordt een functie in een object een 'methode' genoemd.
Met setAttribute()
kun je een attribuut aan een element in de html toevoegen. Dat kan van alles zijn: tabindex
, een WAI-ARIA-code, noem maar op. Tussen de haakjes komen de naam en de waarde van het attribuut te staan.
("style", "outline: green dotted 3px;")
: voor de komma staat tussen aanhalingstekens de naam van het attribuut dat wordt toegevoegd, achter de komma staat tussen aanhalingstekens de waarde van het attribuut.
In dit geval levert dat style="outline: green dotted 3px;"
op.
De hele regel in normale mensentaal: zet een groene gestippelde rand rondom de gemarkeerde tekst in de <span>, die gelijk voor de <span> met focus staat.
Als je de toegevoegde css wilt bekijken moet je niet in de gewone code, maar in de Gegenereerde code kijken.
function verwijderRandje(e) {
e.target.previousSibling.removeAttribute("style");
Deze functie en de regel eronder werken precies hetzelfde als de hierboven beschreven function tekenRandje(e) {.
De enige verschillen:
* Deze functie wordt aangeroepen als de <span> met class="pict" die focus heeft die focus weer verliest. Het aanroepen van deze functie wordt geregeld bij picts[i].addEventListener("blur", verwijderRandje);
* De naam van de functie. Deze functie heet 'verwijderRandje'.
* In plaats van setAttribute
wordt hier removeAttribute
gebruikt met tussen de haakjes "style": het attribuut 'style' wordt hier weer verwijderd. De waarde 'outline: green dotted 3px;' is hier niet nodig, want als 'style' wordt verwijderd, wordt automatisch ook de bijbehorende waarde verwijderd.