Skip links en inhoudsopgave

Beweeg de cursor en er verschijnen smileys - uitleg

Laatst aangepast: .

Afbeelding 1: zwarte pagina met één smiley zichtbaar

Korte omschrijving

Als je de cursor over het lege, zwarte vlak beweegt, of als je dit vlak aanraakt, verschijnen er steeds andere smileys.

BELANGRIJK

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

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

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

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

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

Opmerkingen

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

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

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

Iets gevonden waar je wat aan hebt? Mooi. Als je je waardering wilt uiten, maak dan een donatie over aan War Child Nederland, een organisatie die kinderen uit oorlogsgebieden helpt hun trauma's te verwerken. Of - nog beter - wordt donateur:
Naar site van War Child Nederland

Achterliggend idee

Lege stukjes op een scherm kun je relatief makkelijk opleuken door er smileys op te laten duiken, als je er met de cursor overheen gaat, of als je het scherm aanraakt.. In principe kun je er van alles laten opduiken, maar hier gebruik ik smileys. Dit is natuurlijk meer geschikt voor kinderen dan voor volwassenen (denk ik...).

Elke smiley zit gewoon in een normale <img>-tag. Het zijn gewone afbeeldingen. Deze <img>'s worden absoluut gepositioneerd, zodat er achttien naast en 24 onder elkaar komen te staan.

Met behulp van css wordt elke <img> 20 px hoog en 20 px breed gemaakt. Daardoor vervormen de smileys wanstaltig. Maar omdat ze onzichtbaar zijn, zie je dat niet. Bij het weergeven krijgt de afbeelding de echte afmeting, waardoor de vervorming weer is verdwenen.

Met behulp van opacity worden de <img>'s onzichtbaar gemaakt. Dat kan niet met behulp van visibility: hidden; of display: none;, omdat hoveren en aanraken dan niet werken. Als over een <img> wordt gehoverd, of als het een <img> wordt aangeraakt, wordt de <img> zichtbaar gemaakt.

In Internet Explorer 11 op een touchscreen en in UC browser op Windows Phone blijven de smileys alleen geopend, als ze focus kunnen krijgen. Daarom reageren de <img>'s ook op focus. Daarvoor moet wel aan elke <img> een tabindex worden gegeven. Als waarde krijgt de tabindex '-1', zodat deze niet wordt bezocht bij gebruik van de Tab-toets. (Ik neem aan dat niemand met behulp van de Tab-toets 432 smileys wil bekijken...)

Er zijn nog wat aanpassingen voor bijvoorbeeld iOS nodig. Dat staat verder allemaal beschreven bij de uitleg van de code.

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 en Safari: -webkit-.

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

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

In dit voorbeeld wordt user-select gebruikt.

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

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: ...;}

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

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

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

WAI-ARIA-codes

WAI-ARIA wordt vaak ingekort tot ARIA. Als je ergens ARIA-codes of aria-codes tegenkomt, wordt daarmee precies hetzelfde bedoeld. Voluit betekent het Web Accessibility Initiative – Accessible Rich Internet Applications.

WAI-ARIA-codes zijn speciale codes voor schermlezers en dergelijke Ze hebben geen invloed op de normale weergave en werking, maar geven extra informatie aan schermlezers en dergelijke Hierdoor is het voor gebruikers van schermlezers duidelijker, waarvoor bepaalde dingen dienen.

In dit geval gebeurt eigenlijk het omgekeerde: met behulp van de WAI-ARIA-code aria-hidden="true" worden dingen juist verborgen voor een schermlezer.

Deze hele pagina is hoe dan ook volkomen ongeschikt voor schermlezers. Er is domweg niets om voor te lezen. De smileys hebben een lege alt-tekst, waarmee je aangeeft dat het illustraties zijn: afbeeldingen zonder informatieve waarde of zo. En verder is de pagina leeg.

Vrijwel leeg, want gelijk boven de <div> met de smileys staan een <input> en een label>. Deze hebben geen enkele echte functie, ze zijn alleen nodig om de smileys weer makkelijk onzichtbaar te kunnen maken op iOS. Een schermlezer zou er echter wel melding van maken, wat nogal verwarrend kan zijn, omdat de indruk wordt gewekt dat die radioknop ergens voor dient. In dit geval is het nog extra verwarrend, omdat er geen tekst in de <label> zit.

Daarom worden <input> en <label> voor schermlezers en dergelijke verborgen met de volgende code:

<input id="sluit-smileys" type="radio" aria-hidden="true">

en

<label for="sluit-smileys" aria-hidden="true"></label>

<input> wordt bij input met behulp van display: none; verborgen. Als je iets met display: none; verbergt, is het ook voor schermlezers verborgen. Voor <input> is de aria-hidden dus strikt genomen niet nodig. Toch gebruik ik het, omdat ik daar expres heel zwart-wit in ben. Daardoor hoop ik te voorkomen dat ik het te makkelijk vergeet. Bovendien kan css uitstaan, ontbreken of onvolledig zijn geïmplementeerd, en dan is aria-hidden wel nodig.

Tabindex

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.

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

Normaal genomen wordt focus aangegeven door een lijntje rondom het element dat focus heeft. In het algemeen is het een bijzonder slecht idee om dat lijntje te verwijderen, omdat gebruikers van de Tab-toets dan niet meer kunnen zien, waar ze zijn aangekomen met de Tab-toets. Als je het lijntje verwijdert met behulp van css, moet je het daarom normaal genomen vervangen door iets anders. In dit geval is dat niet nodig, omdat de focus hier alleen wordt gebruikt om het werkend te krijgen in alle browsers op een touchscreen. Het (lelijke) lijntje kan dus zonder probleem worden weggehaald.

De Tab-toets volgt normaal genomen de volgorde van de elementen in de html. Het maakt niet uit, hoe 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 attribuut tabindex: <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, waaronder iets hieronder 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" gebruikt bij elke <img>:

<img tabindex="-1" src="015-pics/aa.gif" alt="">

Zonder deze tabindex blijven de smileys niet zichtbaar in Internet Explorer 11 op een touchscreen. Ze zijn wel heel even zichtbaar, maar verdwijnen gelijk weer.

Door het toevoegen van de negatieve tabindex kan de <img> focus krijgen en blijven de smileys ook bij aanraken zichtbaar. Omdat een tabindex="-1" wordt genegeerd door de Tab-toets, heeft dit verder geen negatieve invloed op gebruikers van de Tab-toets. Als er onderaan de pagina bijvoorbeeld nog 'n link zou staan, zouden die anders eerst 432 keer de Tab-toets moeten indrukken, voordat ze bij die link zouden zijn aangekomen. Dat maakt alleen fabrikanten van Tab-toetsen vrolijk, want zo'n toets is dan lekker snel versleten. De vingers en het humeur van de tabbende bezoeker echter ook, dus vandaar een negatieve waarde en geen '0' of – nog erger – een positieve waarde.

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.

Deze waarde wordt in dit voorbeeld niet gebruikt.

tabindex="..."

Op de plaats van de puntjes moet een positief getal worden ingevuld: het volgnummer. Positieve tabindexen worden hier 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.

:hover

Omdat :hover mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :hover tonen.

Je hovert over een element, als je met behulp van muis of touchpad de cursor boven dat element brengt. Hoveren kan over álle elementen. Het wordt veel gebruikt om iets van uiterlijk te laten veranderen, een pop-up te laten verschijnen, en dergelijke.

In dit voorbeeld levert hover niet al te veel problemen op, omdat hover niet wordt gecombineerd met klikken. Bij gebruik van een muis zit er een verschil tussen hoveren en klikken, maar op een touchscreen is dat verschil er niet: je raakt een touchscreen aan of niet. En dat kan problemen opleveren op een touchscreen.

Op iOS worden de smileys bij aanraking gewoon zichtbaar. Als je 'n tweede zichtbaar maakt, verdwijnt de eerste netjes. Maar als je buiten de <div> met de smileys het scherm aanraakt. blijft de laatst getoonde smiley gewoon zichtbaar. Om die te laten verdwijnen, is een <input> met bijbehorend <label> aangebracht. Meer daarover is te vinden bij <input id="sluit-smileys"...

:focus

Omdat :focus mogelijk niet werkt, als css uitstaat, ontbreekt of onvolledig is geïmplementeerd, moet je nooit belangrijke informatie alleen met behulp van :focus tonen.

De meeste mensen gaan met een muis naar een link, invoerveld, en dergelijke. Waarna ze vervolgens klikken om de link te volgen, tekst in te voeren, of wat ze ook maar willen doen.

Er is echter 'n tweede manier om naar links, invoervelden, en dergelijke te gaan: met behulp van de Tab-toets (sommige browsers gebruiken andere toetsen, maar het principe is hetzelfde). 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.)

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, enz.

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. Maar in dit voorbeeld kan het kadertje veilig worden weggehaald, omdat het hier geen enkel nut heeft.

:focus wordt hier gebruikt voor Internet Explorer 11 op touchscreens en UC browser op Windows Phone. In deze browsers blijft bij aanraken van het scherm de smiley niet geopend, maar sluit gelijk weer. Bij gebruik van :focus blijft de smiley wel geopend.

Als bijwerking van het focus kunnen geven aan een <img>, blijft de <img> – en de daarin zittende smiley – zichtbaar, als met de muis op de <img> wordt geklikt. Dat maakt verder weinig uit, want bij klikken op een andere <img> of buiten de <div> met smileys wordt de <img> weer verborgen. (Alleen Firefox op OS X laat bij klikken met de muis de smiley niet zichtbaar.)

Op iOS worden de smileys bij aanraking gewoon zichtbaar. Als je 'n tweede zichtbaar maakt, verdwijnt de eerste netjes. Maar als je buiten de <div> met de smileys het scherm aanraakt. blijft de laatst getoonde smiley gewoon zichtbaar. Om die te laten verdwijnen, is een <input> met bijbehorend <label> aangebracht. Meer daarover is te vinden bij <input id="sluit-smileys"...

De code aanpassen aan je eigen ontwerp

Toegankelijkheid en zoekmachines

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

Toegankelijkheid (accessibility in het Engels) is belangrijk voor bijvoorbeeld blinden die een schermlezer gebruiken, of voor motorisch gehandicapte mensen die moeite hebben met het bedienen van een muis. Een spider van een zoekmachine (dat is het programmaatje dat de site indexeert voor de zoekmachine) is te vergelijken met een blinde. Als je je site goed toegankelijk maakt voor gehandicapten, is dat gelijk goed voor een hogere plaats in een zoekmachine. Dus als je 't niet uit sociale motieven wilt doen, kun je 't uit egoïstische motieven doen.

(Op die plaats in de zoekmachine heb je maar beperkt invloed. De toegankelijkheid van je site is maar één van de factoren, maar zeker niet onbelangrijk.)

Als je bij het maken van je site al rekening houdt met toegankelijkheid, is dat nauwelijks extra werk. 't Is ongeveer te vergelijken met inbraakbescherming: doe dat bij 'n nieuw huis en 't is nauwelijks extra werk, doe 't bij 'n bestaand huis en 't is al snel 'n enorme klus.

Enkele tips die helpen bij toegankelijkheid:

Specifiek voor dit voorbeeld

Deze pagina is absoluut niet geschikt voor schermlezers en dergelijke. Er staan alleen afbeeldingen zonder alt-omschrijving op, dus er is niets om voor te lezen.

Je zou als alt-tekst een omschrijving van de smiley kunnen schrijven, maar dat slaat naar mijn idee nergens op. Want dan zou de omschrijving van 432 smileys worden voorgelezen.

De enige specifieke toevoeging voor toegankelijkheid is het gebruik van aria-hidden="true" bij de <label> en <input> bovenaan de pagina, waardoor schermlezers en dergelijke dit niet zien. Meer daarover bij WAI-ARIA-codes.

Getest in

Laatst gecontroleerd op 22 augustus 2015.

Onder dit kopje staat alleen maar, hoe en waarin is getest. Eventuele problemen, ook die met betrekking tot zoomen en lettergroottes, staan hieronder bij Bekende problemen (en oplossingen). Het is belangrijk dat te lezen, want uit een test kan ook prima blijken dat iets totaal niet werkt!

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

Dit voorbeeld is getest op de volgende systemen:

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

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

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

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

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

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

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

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

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

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

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

Als het voorbeeld in deze programma's toegankelijk is, zou het in principe toegankelijk moeten zijn in alle aangepaste browsers en dergelijke. En dus ook voor zoekmachines, want een zoekmachine is redelijk vergelijkbaar met een blinde. Eventuele opmerkingen over de toegankelijkheid specifiek voor dit voorbeeld staan hierboven bij Toegankelijkheid en zoekmachines onder het kopje Specifiek voor dit voorbeeld.

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

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

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

Nieuwe browsers test ik pas, als ze uit het bèta-stadium zijn, omdat er anders 'n redelijke kans is dat ik 'n bug zit te omzeilen, die voor de uiteindelijke versie nog gerepareerd wordt. Dit voorbeeld is alleen getest in de hierboven met name genoemde browsers. Vragen over niet-geteste browsers kan ik niet beantwoorden, en het melden van fouten in niet-geteste browsers heeft ook geen enkel nut. (Melden van fouten, problemen, enz. in wel geteste browsers: graag!)

Bekende problemen (en oplossingen)

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

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

iOS, Windows Phone, UC browser op Android en Android browser

Als je 'n touchscreen langer aanraakt, opent een venstertje met contextueel menu. Dat is in de <div> met de smileys wat onhandig. Daarom wordt dit met behulp van wat JavaScript uitgeschakeld. Meer daarover is te lezen bij JavaScript.

De mogelijkheid om dit menu uit te schakelen is relatief nieuw. Op iOS en Windows Phone kan dat nog in geen enkele browser. In Android kan het niet in UC browser en Android browser.

Een heel groot probleem is dit niet, want je moet het scherm vrij lang aanraken, voordat het menuutje opent.

Links, tekstvelden, enz. reageren niet en tekst kan niet worden gekopieerd

Dat kan komen door de <label> die het hele browservenster bestrijkt. Als dat het geval is, is het voldoende het element dat niet reageert een relatieve positie te geven. Meer hierover is te vinden onderaan <input id="sluit-smileys"...

De css valideert niet

O, gruwel. En dat terwijl voor sommigen de vervulling van hun leven hiervan lijkt af te hangen.

Er wordt gebruik gemaakt van de eigenschap user-select. Deze wordt in alle geteste browsers al (heel) lang ondersteund, maar zit vreemd genoeg in geen enkele (ontwerp-)specificatie. Het zorgt ervoor dat tekst niet geselecteerd kan worden.

Als tekst wordt geselecteerd, schiet de browser onmiddellijk te hulp met allerlei voorstellen om de geselecteerde tekst te kopiëren, te mailen, als gedicht uit te geven, en wat al niet meer. Sommige browsers doen dit heel snel, al bij een korte aanraking.

Een <img> wordt gezien als tekst, dus kan een <img> ook geselecteerd worden. In dit geval is de hulp van de browser even irritant als de kelner die in restaurants-voor-snobs achter je staat en bij elke hap vraagt: "Smaakt het?". Browser en kelner moeten gewoon hun mond houden.

De kelner het zwijgen opleggen ligt juridisch en zo wat gevoeliger, maar de mogelijkheid tot selecteren van de <img>'s, en daarmee de voorstellen tot kopiëren en dergelijke, schakel je eenvoudig uit met user-select: none;. Omdat dit niet in een specificatie staat, krijg je een foutmelding van de validator.

Omdat de reden van deze foutmelding bekend is, maakt dat verder niets uit. Valideren is bedoel om vergissingen te verbeteren, het is geen schoonheidswedstrijd.

Wijzigingen

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

:

Nieuw opgenomen.

25 juli 2008:

Aanpassingen voor Konqueror verwijderd.

9 april 2009:

Tekst aangepast aan de nieuw verschenen Internet Explorer 8. De code is niet veranderd.

4 augustus 2009:

Alleen het voorbeeld op de site is gewijzigd en wijkt nu enigszins af van het voorbeeld in de download.

7 oktober 2009:

Download is nu hetzelfde als het voorbeeld op de site, beide hebben nu hetzelfde doctype en dezelfde tabindex.

30 juli 2011:

22 augustus 2015:

Inhoud van de download en licenties

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

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

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

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

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

pop-up-015-dl.html: de pagina met het venstertje en de twee kolommen.

pop-up-015.pdf: deze uitleg (aangepast aan de inhoud van de download).

pop-up-015.txt: een kopie van de tekst onder dit kopje (Inhoud van de download en licenties).

015-css-dl:

pop-up-015-dl.css: stylesheet voor pop-up-015-dl.html.

015-pics:

aa.gif tot en met xr.gif: de smileys.

De herkomst van deze smileys weet ik helaas niet meer, maar ze zijn ergens uit het publieke domein afkomstig.

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 blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)

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

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

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

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

Als je dit lastig vindt, downloadt dan de hele handel (ga terug naar het voorbeeld en kies daar voor downloaden). In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.

<!DOCTYPE html>

<html lang="nl">

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.

De toevoeging lang="nl" bij <html> geeft aan dat de pagina in het Nederlands is. De taal is van belang voor schermlezers en dergelijke.

<meta charset="utf-8">

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

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

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

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

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

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

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

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

Nieuwe sites of pagina's kunnen echter wel rekening houden met de veel kleinere vensters van mobiele apparaten. Voor deze pagina bijvoorbeeld maakt het niets uit, als hij wat te breed of te hoog is. 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.

Dat klopt voor deze pagina niet helemaal, want de <div> met de smiley blijft 360 px breed en 480 px hoog. Maar het is geen enkel probleem als er wat smileys buiten het venster vallen, dus aanpassen is hier niet nodig.

Er staat nog een tweede deel in de tag: initial-scale=1. Sommige mobiele apparaten zoomen een pagina gelijk in of uit. Ook weer in een poging behulpzaam te zijn. Ook dat is hier niet nodig. Er is ook een instructie om zoomen helemaal onmogelijk te maken, maar die gebruik ik niet. De bezoeker kan zelf nog gewoon zoomen, wat belangrijk is voor mensen die wat slechter zien.

<input id="sluit-smileys" type="radio" aria-hidden="true">

<label for="sluit-smileys" aria-hidden="true"></label>

Omdat <label> en <input> bij elkaar horen, worden ze hier gelijktijdig beschreven.

Op iOS worden :hover en :focus op een eigen manier afgehandeld, die niet helemaal probleemloos is.

Hoveren (de muis ergens overheen bewegen) op een touchscreen kan eigenlijk niet. Maar veel websites maakten daar al gebruik van, toen touchscreens nog niet bestonden. Om niet heel veel bestaande sites onbruikbaar te maken, moesten touchscreens dus iets met hoveren doen.

Focus kan ook op een touchscreen nog enig nut hebben, bijvoorbeeld als er 'n pop-up opent als 'n element focus heeft, maar in het algemeen heeft ook dit meer nut bij gebruik van een toetsenbord of muis.

De smileys worden zichtbaar door middel van hoveren of focus. Normaal genomen kan een <img> geen focus krijgen, maar door ze een tabindex van -1 te geven, kan dit toch. Dit is nodig vanwege Internet Explorer 11 op touchscreens en UC browser op Windows Phone. Zonder tabindex blijven de smileys niet zichtbaar in deze browsers, maar verdwijnen gelijk weer. Android en iOS maken de smileys ook zichtbaar, als alleen :hover wordt gebruikt.

In touchscreens met Windows en Android verdwijnt de laatst getoonde smiley weer, als het scherm buiten de <div> met de smileys wordt aangeraakt. Dat is echter niet zo in iOS: de smiley blijft daarin zichtbaar, tot een ander element dat focus kan krijgen wordt aangeraakt. Dit geldt zowel voor :hover als voor :focus. Een ander element dat focus kan krijgen. Dat moet dus een link of een invoerveld voor tekst of zoiets zijn.

Maar die zijn niet aanwezig in dit voorbeeld. Bovendien moet de bezoeker dan maar net die link of dat invoerveld aanraken, anders blijft de smiley nog steeds zichtbaar.

Dit voorbeeld is eigenlijk voor kleine, dode hoekjes bedoeld. Maar het is 'n beetje in 'n groeisprint geschoten en wat groot geworden. Als het om 'n klein, dood hoekje gaat, is het misschien helemaal geen probleem als de smiley geopend blijft en is deze hele constructie niet nodig. Of er zitten genoeg andere elementen op de pagina die focus kunnen krijgen.

Maar als dat niet zo is, lossen de <input> en <label> bovenaan de pagina dit op.

Bij input wordt de <input> met behulp van display: none; onzichtbaar gemaakt. Zou je dat niet doen, dan zou je 'n radioknop (het type van de <input>) zien. Niets tegen radioknoppen, ze horen tot m'n beste vrienden, maar hier is het geen gezicht. Waarmee de <input> is afgehandeld.

De <label> wordt bij label absoluut gepositioneerd en krijgt top: 0;, right: 0;, bottom: 0; en left: 0;. Daardoor bestrijkt de <label> het volledige venster van de browser. Als dat venster nu ergens wordt aangeraakt, krijgt de bij het <label> horende <input> focus. Waarmee de <img> die het laatst is aangeraakt de focus verliest en dus weer onzichtbaar wordt.

Deze methode heeft één nadeel. Omdat de <label> absoluut is gepositioneerd en het hele browservenster afdekt, kan hij ook andere elementen afdekken. Hierdoor werken links mogelijk niet, omdat ze niet aangeklikt of aangeraakt kunnen worden. Tekst invoeren kan onmogelijk zijn, omdat de <label> het invoerveld afdekt. Tekst kan mogelijk niet worden gekopieerd, omdat je de tekst wel kunt zien door de doorzichtige <label> heen, maar niet kunt bereiken. Enz.

Een element dat is gepositioneerd, krijgt automatisch een z-index. Daarmee wordt de horizontale positie opgegeven. Een element met een hogere z-index komt over een element met een lagere of geen z-index heen te staan, ongeacht de volgorde van de html.

De <label> is absoluut gepositioneerd en krijgt daardoor een z-index. En dekt dus elementen zonder z-index af. Om die elementen zonder z-index bereikbaar te maken, moet je ze ook aan 'n z-index zien te helpen. Dat kan op allerlei manieren.

In dit voorbeeld speelt dit probleem niet, omdat de hele pagina bestaat uit alleen de <input>, de <label> en div#smileys met daarin de smileys. En div#smileys is absoluut gepositioneerd en heeft dus ook een z-index. En wordt daardoor niet gehinderd door de hebberige <label>.

Als er andere elementen op de pagina aanwezig zouden zijn, wat hier niet het geval is, is de makkelijkste manier om het op te lossen deze elementen een relatieve positie te geven. Met position: relative; krijgt een element ook een z-index. Als je verder niets invult bij top, right, bottom en left, heeft dit verder geen invloed.

Er zijn nog wat eigenschappen die een z-index opleveren, zoals opacity met een waarde van minder dan 1 en transform, maar die hebben allemaal bijwerkingen. Normaal genomen is position: relative; het meest geschikt hiervoor.

(Dit is een wat gesimplificeerde weergave van een uiterst complex geheel, maar het is wel bruikbaar en dingen als z-index en – zoals dat heet – stacking context zijn écht heel ingewikkeld. Even uitproberen of bovenstaande truc werkt, is in de regel veel sneller en makkelijker dan de stacking order gaan berekenen. Bovendien werkte die stacking order – in ieder geval in het verleden – bepaald niet helemaal vlekkeloos in alle browsers, dus uitproberen/testen is hoe dan ook nodig.)

<img tabindex="-1" src="015-pics/aa.gif" alt="">

tabindex="-1" is nodig, omdat anders in Internet Explorer 11 op een touchscreen en UC browser op Windows Phone de smileys bij aanraken van het scherm niet zichtbaar blijven. Omdat als waarde -1 is gebruikt, heeft dit verder geen invloed op het gebruik van de Tab-toets.

Meer over tabindex is te vinden bij Tabindex.

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 blauw gekleurd. Alle niet-essentiële code is bruin. (In de inhoudsopgave staat alles in een gewone letter vanwege de leesbaarheid.)

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

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

Als je dit lastig vindt, downloadt dan de hele handel (ga terug naar het voorbeeld en kies daar voor downloaden). In de download zit 'n voorbeeld dat wel naadloos aansluit op de uitleg in de download.

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

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

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


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

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

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

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

Je hebt dan eigenlijk twee stylesheets. De uitgebreide versie waarin je dingen uitprobeert, verandert, enz., met commentaar, inspringingen, en dergelijke. Dat is de mensvriendelijke versie. Daarnaast is er dan een stylesheet die je op de echte site gebruikt: een gecomprimeerde versie.

Dat comprimeren kun je met de hand doen, maar er bestaan ook hulpmiddelen voor. Als je op internet zoekt naar 'css' en 'compress' of 'comprimeren', vind je tal van sites, waar je dat automatisch kunt doen.

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

/* pop-up-015-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: black;

Zwarte achtergrond.

font-family: Arial, Helvetica, sans-serif;

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

margin: 0; padding: 0;

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

input

Alle <input>'s. Dat is er hier maar eentje.

Op iOS is een extra <input> nodig om de laatst zichtbaar gemaakte smiley weer te kunnen laten verdwijnen. Meer hierover bij <input id="sluit-smileys"...

display: none;

Deze <input> is van het type radioknop. Voor het mooie hoeft hij niet te blijven staan, dus wordt hij verborgen. De gelijk hieronder staande bij deze <input> horende <label> doet het eigenlijke werk.

label

Deze <label> hoort bij de <input> gelijk hierboven. Hij is nodig om op iOS de laatst zichtbaar gemaakte smiley weer te kunnen laten verdwijnen. Meer hierover bij <input id="sluit-smileys"...

position: absolute; top: 0; right: 0; bottom: 0; left: 0;

De <label> moet het volledige venster van de browser bestrijken. Dit kan het simpelst door de <label> absoluut te positioneren. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een positie heeft. Die ontbreekt hier. In dat geval wordt gepositioneerd ten opzichte van het venster van de browser. En dat is precies de bedoeling.

Met de opgeven waarden bestrijkt de <label> altijd het volledige venster van de browser. Hierdoor is een aanraking van het venster altijd ook een aanraking van de <label>, en daar gaat het om, zoals is beschreven bij <input id="sluit-smileys"...

div

Alle <div>'s. Dat is er hier maar eentje: div#smileys, waarin alle <img>'s met smileys zitten.

width: 360px; height: 480px;

Met deze breedte en hoogte passen er twintig <img>'s naast en vierentwintig onder elkaar.

Er is geen rekening gehouden met smallere en/of lagere browservensters, zoals die op smartphones voorkomen. Dat hoeft hier niet, omdat er geen enkel bezwaar is tegen scrollen. En het is ook geen probleem, als enkele smileys onbereikbaar worden, omdat ze buiten het venster komen te staan.

(Op de site zelf is het navigatiemenu bovenaan de pagina wel extra vastgezet, want dat mag niet meescrollen.)

Als het venster van de browser toevallig (ongeveer) even hoog is als deze <div>, kan een verticale scrollbalk verschijnen, als een smiley wordt geopend. De <img> met de smiley is gepositioneerd op een vaste hoogte. Als de smiley hoger is dan 20 px, zal de smiley daardoor aan de onderkant uitsteken. Als die onderkant toevallig gelijk loopt met de onderkant van het browservenster, verschijnt daardoor een verticale scrollbalk.

Dit is eventueel simpel te voorkomen: zet onderaan alleen smileys die niet hoger dan 20 px zijn.

margin-left: -180px;

180 px naar links verplaatsen.

Hier iets onder wordt de <div> met left: 50%; halverwege het venster van de browser neergezet. De <div> is 360 px breed. Door hem weer 180 px terug naar links te zetten, komt de <div> altijd in het midden van het venster, ongeacht de breedte hiervan.

In vensters smaller dan 360 px verdwijnt hierdoor links van het venster een deel van de <div>, en dus ook van de daarin zittende smileys. In dit geval is dat geen probleem, omdat het alleen maar om smileys gaat. Als dat wel een probleem is, moet voor een andere constructie worden gekozen, of er moet met behulp van media queries worden getest op de breedte van het venster.

position: absolute;

Om de <div> op de juiste plaats te kunnen zetten. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een positie heeft. Als die er niet is, zoals hier het geval is, wordt gepositioneerd ten opzichte van het venster van de browser.

top: 10px;

Kleine ruimte aan de bovenkant.

left: 50%;

Horizontaal halverwege het venster van de browser zetten. In combinatie met de margin-left iets hierboven staat de <div> nu altijd horizontaal gecentreerd. Er is iets meer over te lezen bij de margin-left iets hierboven.

-moz-user-select: none; -ms-user-select: none; -webkit-user-select: none; user-select: none;

Hier staat in feite drie keer hetzelfde: user-select: none;. Waarom dat zo is, staat bij De voorvoegsels -moz-, -ms- en -webkit-.

Een <img> wordt door de browser hetzelfde behandeld als tekst. Daarom kan een <img> worden geselecteerd om te kopiëren en dergelijke Op sommige touchscreens wordt die tekst, en dus ook <img>'s, wel heel snel geselecteerd. Daarom wordt de mogelijkheid om te selecteren binnen div#smileys uitgeschakeld.

Vreemd genoeg zit user-select in geen enkele (ontwerp-)standaard, maar is het wel in alle browsers ingebouwd. Met kleine verschillen, bijvoorbeeld op het gebied van overerving: niet bij alle browsers geldt dit ook voor de <img>'s binnen deze <div>. Daarom wordt iets hieronder bij img deze eigenschap nogmaals herhaald.

Hoewel het gebruik van een eigenschap die zelfs nog niet in een ontwerpstandaard zit tamelijk riskant is, kan het in dit geval weinig kwaad. De eigen schap wordt in de meest simpele vorm gebruikt, en het lijkt onwaarschijnlijk dat die veel zal veranderen. En zelfs als dat zou gebeuren, dan is het nog geen ramp, omdat het niet om heel essentiële css gaat.

img

Alle <img>'s. Dat zijn hier de <img>'s, waarin de smileys zitten.

opacity: 0;

Afbeeldingen onzichtbaar maken. Dat zou ook kunnen met display: none; of visibility: hidden;, maar in dat geval werken hoveren en aanraken niet. Als je de <img> alleen doorzichtig maakt, is de <img> nog gewoon aanwezig. En blijven hoveren en aanraken dus gewoon werken.

width: 20px; height: 20px;

Ongeacht de echte grootte van de smiley krijgen ze hier allemaal een breedte en hoogte van 20 px. Als je de waarde bij opacity hierboven even in een '1' verandert, zie je dat dit tot de meest gruwelijke misvormingen van de smileys leidt.

Dat maakt niet uit, want iets hieronder bij img:hover, img:focus, als de <img>'s zichtbaar worden, krijgen ze weer de juiste maat.

Door ze allemaal even groot te maken, passen er precies twintig naast en vierentwintig onder elkaar in div#smileys.

position: absolute;

Om de smileys op de juiste plaats neer te kunnen zetten. Er wordt gepositioneerd ten opzichte van de eerste voorouder die zelf een positie heeft. Dat is hier div#smileys, die bij div een absolute positie heeft gekregen.

Waarom worden de smileys absoluut gepositioneerd, terwijl het inline-elementen zijn die uit zichzelf ook netjes achter elkaar gaan staan? Daar zijn 'n paar redenen voor.

* Een <img> is een inline-element, net zoals een woord. Als je elke <img> op een eigen regel zet, zoals in de html is gebeurd, komt er daardoor een spatie achter elke <img> te staan. Om dat te voorkomen, zou je alle <img>'s achter elkaar in één lange regel in de html moeten zetten. Mensen zijn door minder in het dolhuis terecht gekomen, want dat is volstrekt onoverzichtelijk: 432 <img>' op één regel. Brrr. (En ik kan het weten, want dit was, zoals het er in de vorige versie ongeveer uitzag. Ik wil niet weer het dolhuis in, dus dat doen we nu anders.)

Als een inline-element absoluut wordt gepositioneerd, verandert het in 'n soort blok-element. Daardoor komt er geen spatie meer achter de <img> te staan.

* Als de <img> zichtbaar wordt, krijgt de <img> z'n echte maat. Die is meestal anders dan de hierboven opgegeven 20 x 20 px. Daardoor kan een smiley opeens op de volgende regel komen te staan, omdat hij net niet meer aan het eind van de regel past. Een absoluut gepositioneerd element blijft gewoon staan, waar het staat. Als het eigenlijk niet meer op de regel past, wordt het teveel gewoon toch getoond. (Tenzij je dat verbiedt, maar dat gebeurt hier niet.)

-moz-user-select: none; -ms-user-select: none; -webkit-user-select: none; user-select: none;

Iets hierboven bij div is hierover een uitgebreid verhaal te vinden.

img:hover, img:focus

Als over 'n <img> wordt gehoverd, of als de <img> focus krijgt. De enige <img>'s hier zijn de <img>'s met de smileys.

Hier is meer over te vinden bij Muis, toetsenbord, touchpad en touchscreen. In het kort komt het erop neer, dat er iets moet gebeuren als je met de muis over een <img> beweegt, als je klikt op een <img> of als je een <img> aanraakt.

opacity: 1;

Hier gelijk boven bij img is de <img> onzichtbaar gemaakt. Hier wordt de <img>, en dus de smiley, weer zichtbaar gemaakt.

width: auto; height: auto;

Hier gelijk boven bij img zijn alle <img>'s 20 px breed en 20 px hoog gemaakt, zodat er een bepaald aantal naast elkaar passen. Maar daardoor vervormen de smileys gruwelijk.

Daarom wordt bij weergave gezegd: ga je gang, wordt maar net zo groot als je eigenlijk bent. Waardoor niemand meer ziet dat de arme ziel in onzichtbare staat ernstig uitgerekt/ingedeukt/gemangeld was. Zoals de meeste politici in 'n onberispelijke ideale-schoondochter/zoon-pose schieten, zodra ze zichtbaar worden voor een camera.

outline: none; Afbeelding 2: smiley met outline

Als een element focus heeft, wordt dat meestal aangegeven door een outline. In het algemeen is het een bijzonder slecht idee om die outline weg te halen, omdat dan voor gebruikers van de Tab-toets volstrekt onduidelijk is, waar ergens op de pagina ze zitten.

In dit geval heeft een outline geen enkele zin en kan die veilig worden verwijderd. Dat is ook wel 'n goed idee, want sommige browsers lijken aandelen in verffabrieken te hebben. Op de afbeelding staat de outline die Google Chrome op Linux aan een element met focus geeft. Rechts staat dezelfde smiley zonder outline. En er zijn nog ergere. Opera heeft, in ieder geval in eerdere versies, overduidelijk een witkwast, of eigenlijk: een blauwkwast, gebruikt om de outline te tekenen.

Kortom: weg ermee.

img:nth-of-type(18n + 1)

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

Er zijn in totaal 432 <img>', die allemaal op de juiste plaats moeten worden neergezet. In eerdere versies, waarin Internet Explorer 6, 7 en 8 nog werden ondersteund, waren hiervoor honderden extra elementen en classes nodig. In nieuwere browsers zijn die extra elementen en classes niet meer nodig en is de css ongeveer tien keer zo klein geworden.

Maar helaas wel iets ingewikkelder.

Er zijn 432 <img>'s. Die moeten in 18 kolommen naast elkaar komen te staan en in 24 regels onder elkaar. Eerst worden de kolommen afgehandeld, de regels komen later. Dat halveert het probleem alvast.

In de tabel hieronder zijn alle <img>'s genummerd en op de juiste plaats gezet:

left (in px) 020406080100120140160180200220240260280300320340
top (in px)
0123456789101112131415161718
20192021222324252627282930313233343536
40373839404142434445464748495051525354
60555657585960616263646566676869707172
80737475767778798081828384858687888990
100919293949596979899100101102103104105106107108
120109110111112113114115116117118119120121122123124125126
140127128129130131132133134135136137138139140141142143144
160145146147148149150151152153154155156157158159160161162
180163164165166167168169170171172173174175176177178179180
200181182183184185186187188189190191192193194195196197198
220199200201202203204205206207208209210211212213214215216
240217218219220221222223224225226227228229230231232233234
260235236237238239240241242243244245246247248249250251252
280253254255256257258259260261262263264265266267268269270
300271272273274275276277278279280281282283284285286287288
320289290291292293294295296297298299300301302303304305306
340307308309310311312313314315316315318319320321322323324
360325326327328329330331332333334335336337338339340341342
380343344345346347348349350351352353354355356357358359360
400361362363364365366367368369370371372373374375376377378
420379380381382383384385386387388389390391392393394395396
440397398399400401402403404405406407408409410411412413414
460415416417418419420421422423424425426427428429430431432

De eerste <img> moet in de eerste kolom komen te staan. De tweede <img> moet in de tweede kolom komen te staan. De derde in de derde, enz. De achttiende <img> moet in de achttiende en laatste kolom komen te staan.

De negentiende <img> moet weer in de eerste kolom komen te staan. De twintigste weer in de tweede, de 21e weer in de derde, enz. En de 36e moet weer in de achttiende en laatste kolom komen te staan.

De 37e img komt weer in de eerste kolom. Enz.

Er zit dus 'n ijzeren regelmaat in welke <img> in welke kolom moet komen.

Om het probleem nog overzichtelijker te maken, kijken we eerst naar de eerste kolom. De andere zeventien komen later wel.

Kolom 1: hier moeten de eerste, negentiende, 37e, 55e, ..., <img> komen te staan. Steeds achttien hoger. Mogelijk is je nog iets anders opgevallen: dit is steeds een veelvoud van 18, maar dan 1 hoger: 0 x 18 + 1 = 1, 1 x 18 + 1 = 19, 2 x 18 + 1 = 37, 3 x 18 + 1 = 55, enz.

Nu halen we de selector van hierboven erbij: img:nth-of-type(18n + 1)

img: da's simpel: gewoon alle <img>'s.

:nth-of-type: een zogenaamde pseudo-class. nth wil zeggen 'de zoveelste', of-type betekent 'van de soort'. Aangezien dit achter een <img> staat, gaat het hier dus om één (of meer) <img>'s.

(18n + 1): tussen de haakjes staat aangegeven, om welke <img> of <img>'s het gaat.

De getallen '18' en '1' zijn gewoon getallen, daar is verder weinig geheimzinnigs aan.

De 'n' is een soort teller, die steeds met 1 wordt verhoogd. Bij de eerste keer is de 'n' 0, bij de tweede keer 0 + 1 = 1, bij de derde keer 1 + 1 = 2, enz.

18n betekent, net als in de wiskunde, 18 x de waarde van 'n'. De eerste keer is dat dus 18 x 0 = 0, de tweede keer 18 x 1 = 18, de derde keer 18 x 2 = 36, enz. Deze berekening levert een reeks getallen op, beginnend met 0, die steeds 18 hoger worden: 0, 18, 36, 54, 72, ...

Omdat er 432 <img>'s zijn, wordt de berekening 432 keer gemaakt. De 432e en laatste berekening is 18 x 431 = 7758. Maar alleen de uitkomsten tot en met 432 hebben nut, omdat er maar 432 <img>'s zijn.

De eerste keer is het resultaat 18 x 0 = 0. Daarachter staat nog + 1. De eerste keer is de volledige berekening dus 18 x 0 + 1 = 1. Oftewel: de eerste <img>.

De tweede keer is het resultaat 18 x 1 = 18. Daarachter staat nog + 1. De tweede keer is de volledige berekening dus 18 x 1 + 1 = 19. Oftewel: de negentiende <img>.

De derde keer is het resultaat 18 x 2 = 36. Daarachter staat nog + 1. De derde keer is de volledige berekening dus 18 x 2 + 1 = 37. Oftewel: de 37e <img>.

Enz.

In dit geval gaat het dus om de eerste, negentiende, 37e, 55e, enz. <img>. En als dat nou niet toevallig is: dat zijn precies de <img>'s die in de eerste kolom moeten komen te staan! Komt dat even goed uit, nu kan ik die in één keer aanspreken.

left: 0;

Helemaal links neerzetten binnen div#smileys. Waarmee de eerste kolom is gevormd. Weliswaar staan ze allemaal nog op dezelfde regel, maar dat wordt verderop opgelost.

img:nth-of-type(18n + 2)

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

Deze selector is exact hetzelfde als die gelijk hierboven, alleen wordt er nu 2 en geen 1 bij de 18n opgeteld. Waardoor hiermee de tweede, twintigste, 38e, 56e, enz. <img> worden aangesproken. Precies de <img>'s die in de tweede kolom moeten komen te staan.

left: 20px;

20 px vanaf links neerzetten. Daarmee komen ze precies naast de <img>'s uit de eerste kolom te staan en is de tweede kolom gevormd.

img:nth-of-type(18n + 3)

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

Ook dit werkt weer precies hetzelfde als hierboven, maar nu wordt er 3 bij opgeteld. Waardoor hiermee de derde, 21e, 39e, 57e, enz. <img< worden aangesproken. Precies de <img>'s die in de derde kolom moeten komen te staan.

left: 40px;

40 px vanaf links is precies naast de eerste en tweede kolom.

img:nth-of-type(18n + 4)

{left: 60px;} img:nth-of-type(18n + 5) {left: 80px;} img:nth-of-type(18n + 6) {left: 100px;} img:nth-of-type(18n + 7) {left: 120px;} img:nth-of-type(18n + 8) {left: 140px;} img:nth-of-type(18n + 9) {left: 160px;} img:nth-of-type(18n + 10) {left: 180px;} img:nth-of-type(18n + 11) {left: 200px;} img:nth-of-type(18n + 12) {left: 220px;} img:nth-of-type(18n + 13) {left: 240px;} img:nth-of-type(18n + 14) {left: 260px;} img:nth-of-type(18n + 15) {left: 280px;} img:nth-of-type(18n + 16) {left: 300px;} img:nth-of-type(18n + 17) {left: 320px;} img:nth-of-type(18n + 18) {left: 340px;}

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

Al deze selectors werken weer precies hetzelfde. Alleen is het tweede getal steeds 1 hoger, waardoor steeds 'n volgende <img< wordt bereikt.

Nog enkele berekeningen van de laatste selector: 18n + 18

Eerste ronde: 18 x 0 + 18: de achttiende <img>.

Tweede ronde: 18 x 1 + 18: de 36e <img>.

()

Laatste zinvolle ronde: 18 x 23 + 18: de 432e <img>, oftewel: de laatste.

Deze worden allemaal in de laatste kolom gezet. De laatste zinvolle ronde is geen 24, het aantal rijen, maar 23, omdat n in de eerste ronde 0 is. En 0 tot en met 23 maakt 24 getallen.

'Zinvolle' ronde? Ja. 18 x 24 + 18, de volgende ronde, komt uit op 450, en er zijn maar 432 <img>'s, dus er is geen <img> die aan die eis voldoet.

(Als je 8000 <img>'s zou hebben, zou je met deze ene regel alle 8000 <img>'s op precies dezelfde manier kunnen afhandelen en de eerste, negentiende, 37e, 55e, enz. <img> tot en met de achtduizendste kunnen aanspreken. Er zijn met behulp van deze en soortgelijke pseudo-classes nog veel ingewikkelder en handiger selectors mogelijk, waarvan een klein aantal hieronder wordt gebruikt. Overigens kun je uit het grote aantal berekeningen ook afleiden, waarom het meestal niet zo'n goed idee zal zijn om zoiets met zoveel <img>'s te maken. Rekenen kost tijd, en zeker op goedkopere smartphones kan dit wel 'nsssssssss laaaaaaannnnnnngggggg gaaaaaaan duren.)

img:nth-of-type(n + 19):nth-of-type(-n + 36)

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

Hierboven zijn de kolommen afgehandeld, maar er zijn ook nog 24 regels. Dit werkt anders dan met de kolommen, omdat het hier om opeenvolgende series <img>'s gaat, en niet elke achttiende of zo.

In de tabel is te zien dat op de eerste regel nummer 1 tot en met 18 komen te staan. Daar hoef je verder niets voor te doen, want als je verder niets opgeeft, is de waarde van top 'auto', wat hier hetzelfde is als '0': bovenin div#smileys.

Bovenstaande selector hoort bij de tweede regel: nummer 19 tot en met 37. Hij ziet er gruwelijk uit, maar als je 't ding in mootjes hakt, wordt het veel hanteerbaarder. Wat trouwens geldt voor meer dingen die je in mootjes hakt.

Achter de <img> van deze selector staan twee pseudo-classes: :nth-of-type(n + 19) en :nth-of-type(-n + 36). Dat betekent alleen maar dat de <img> aan beide pseudo-classes moet voldoen. Je kunt ze dus apart bekijken, waarmee het opeens een stuk beter te behappen is.

img: alle <img>'s.

:nth-of-type(n + 19): vrijwel hetzelfde als iets hierboven bij img:nth-of-type(18n + 1).

De 'n' is weer een teller die met 0 begint en steeds 1 hoger wordt. De eerste keer staat er dus 0 + 19 = 19, de tweede keer 1 + 19 = 20, de derde keer 2 + 19 = 21, enz. Bij 432 <img>'s levert dit de getallen 19, 20, 21, 22, 23, 24, 25, 26, ... tot en met 451 op. Alleen de uitkomsten 432 en lager hebben nut, want er zijn maar 432 <img>'s.

De eerste pseudo-class stelt dus als voorwaarde dat het de negentiende, twintigste, enz. tot en met de 432e <img> is.

:nth-of-type(-n + 36): ook deze selector is weinig anders dan de eerdere, maar met een minteken voor de 'n'. De 'n' is weer een teller die met 0 begint en steeds 1 hoger wordt. Alleen is het hier iets lastiger vanwege het minteken.

Bij de eerdere pseudo-class bij img:nth-of-type(18n + 1) stond 18n: voor de 'n' staat het getal 18. Wat je uit moet leggen als 18 x n.

Bij deze selector staat geen getal voor de 'n', alleen een minteken. Als er geen getal voor de 'n' staat, staat er eigenlijk toch 'n getal: de 1. Maar die wordt weggelaten, omdat '1n' moet worden gelezen als '1 x n', en dan is de 1 een beetje overbodig.

Hier staat echter een minteken voor de 'n', en dan kan het helpen om de 1 er wel even bij te denken: -1n: Wat je dus moet lezen als -1 x n.

Bij de eerste ronde is 'n' 0. De berekening wordt dan -1 x 0 = 0.

Bij de tweede ronde is 'n' 1. De berekening wordt dan -1 x 1 = -1.

Bij de derde ronde is 'n' 2. De berekening wordt dan -1 x 2 = -2.

Enz., de uitkomst is steeds 1 lager. Hoewel 'n' steeds 1 hoger wordt, wordt de uitkomst door het minteken steeds 1 lager.

Bij de 432e en laatste ronde is 'n' 431 en is de berekening -1 x 431 = -431.

(Omdat de 'n' met 0 begint te tellen, is de 'n' bij de 432e berekening 431 en geen 432.)

Bij deze uitkomst moet 36 worden opgeteld, want er staat -n + 36 tussen de haakjes.

Bij de eerste ronde staat er -1 x 0 + 36 = 0 + 36 = 36.

Bij de tweede ronde staat er -1 x 1 + 36 = -1 + 36 = 35.

Bij de derde ronde staat er -1 x 2 + 36 = -2 + 36 = 34.

Bij de 432e ronde staat er -1 x 431 + 36 = -431 + 36 = -395.

De uitkomst is de serie getallen 36, 35, 34, ..., -395.

Oftewel: het gaat om de 36e, 35e, 34e, ... tot en met de eerste <img>. De nulde en lagere <img>'s vervallen, want er bestaan geen nulde of lagere <img>'s.

:nth-of-type(n + 19):nth-of-type(-n + 36): beide pseudo-classes achter elkaar.

De <img>'s moeten binnen beide pseudo-classes vallen.

De eerste pseudo-class levert de negentiende tot en met de 432e <img> op.

De tweede pseudo-class levert de eerste tot en met de 36e <img> op.

Alleen de negentiende tot en met de 36e <img> zitten binnen beide pseudo-classes, dus de css van deze selector geldt alleen voor de negentiende, twintigste, tot en met de 36e <img>. En dat zijn, niet geheel toevallig, de <img>'s die in de tweede regel moeten komen te staan.

top: 20px;

Op 20 px vanaf de bovenkant van div#smileys komen ze precies onder de eerste regel te staan. Waarmee de tweede regel compleet is.

img:nth-of-type(n + 37):nth-of-type(-n + 54)

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

Los van de getallen is deze selector precies hetzelfde als die hierboven bij img:nth-of-type(n + 19):nth-of-type(-n + 36).

:nth-of-type(n + 37): de eerste pseudo-class levert hier de getallen 37, 38, 39, 40, 41, 42, 43, 44, 45, tot en met 468 op. Er zijn maar 432 <img>'s, dus alleen de getallen 37 tot en met 432 zijn interessant.

:nth-of-type(-n + 54): de tweede pseudo-class levert hier de getallen 54, 53, 52, 51, 50, tot en met -377 op. Alleen de getallen 1 tot en met 54 zijn interessant, want een nulde of lagere <img> is onzin.

Ook hier komen alleen de <img>'s in aanmerking, die binnen beide pseudo-classes vallen. Dat zijn alleen de 37e tot en met de 54e <img>. En komt dat even goed uit: dat zijn precies de <img>'s die in de derde rij zitten!

(Je kunt de werking van deze tweede selector voor de regels trouwens ook iets sneller herkennen: de getallen die bij n worden opgeteld zijn 18 hoger dan in de vorige selector. Het is dus logisch dat de uitkomst ook 18 hoger is: de <img>'s met de 18 volgnummers boven die van de eerste selector.)

top: 40px;

Op 40 px van de bovenkant van div#smileys komen ze precies onder de eerste twee regels te staan.

img:nth-of-type(n + 55):nth-of-type(-n + 72)

{top: 60px;} img:nth-of-type(n + 73):nth-of-type(-n + 90) {top: 80px;} img:nth-of-type(n + 91):nth-of-type(-n + 108) {top: 100px;} img:nth-of-type(n + 109):nth-of-type(-n + 126) {top: 120px;} img:nth-of-type(n + 127):nth-of-type(-n + 144) {top: 140px;} img:nth-of-type(n + 145):nth-of-type(-n + 162) {top: 160px;} img:nth-of-type(n + 163):nth-of-type(-n + 180) {top: 180px;} img:nth-of-type(n + 181):nth-of-type(-n + 198) {top: 200px;} img:nth-of-type(n + 199):nth-of-type(-n + 216) {top: 220px;} img:nth-of-type(n + 217):nth-of-type(-n + 234) {top: 240px;} img:nth-of-type(n + 235):nth-of-type(-n + 252) {top: 260px;} img:nth-of-type(n + 253):nth-of-type(-n + 270) {top: 280px;} img:nth-of-type(n + 271):nth-of-type(-n + 288) {top: 300px;} img:nth-of-type(n + 289):nth-of-type(-n + 306) {top: 320px;} img:nth-of-type(n + 307):nth-of-type(-n + 324) {top: 340px;} img:nth-of-type(n + 325):nth-of-type(-n + 342) {top: 360px;} img:nth-of-type(n + 343):nth-of-type(-n + 360) {top: 380px;} img:nth-of-type(n + 361):nth-of-type(-n + 378) {top: 400px;} img:nth-of-type(n + 379):nth-of-type(-n + 396) {top: 420px;} img:nth-of-type(n + 397):nth-of-type(-n + 414) {top: 440px;} img:nth-of-type(n + 415):nth-of-type(-n + 432) {top: 460px;}

De selectors voor de overige regels. Allemaal hetzelfde als de eerdere, alleen is het getal dat bij n wordt opgeteld steeds 18 hoger, waardoor de uitkomst ook steeds 18 hoger is.

De laatste selector, die bij de onderste regel hoort, nog 'ns bekeken:

:nth-of-type(n + 415): de eerste pseudo-class levert hier de getallen 415, 416, 417, 418, tot en met 846 op. Er zijn maar 432 <img>'s, dus alleen de getallen 415 tot en met 432 zijn interessant.

:nth-of-type(-n + 432): de tweede pseudo-class levert hier de getallen 432, 431, 430, 429, 428, 427, tot en met 1 op.

Ook hier komen alleen de <img>'s in aanmerking, die binnen beide pseudo-classes vallen. Dat zijn alleen de 415e tot en met de 432e <img>: de <img>'s die in de onderste regel moeten komen te staan.

JavaScript

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

Een minuscuul klein stukje JavaScript onderaan de html-pagina.

<script> document.getElementById("smileys").addEventListener("contextmenu", function (e) {e.preventDefault(); }); </script>

<script> en </script>

Dit is gewone html: het zijn de openings- en sluittag voor het script. In html5 is de toevoeging type="text/javascript" niet meer nodig.

Het eigenlijke JavaScript is tamelijk simpel. Ik ga er niet al te diep op in, want deze site gaat uiteindelijk niet over JavaScript, maar over css.

document.getElementById("smileys")

Zoek naar het element met id="smileys". Dit is vergelijkbaar met #smileys in css.

addEventListener

Voeg aan #smileys 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.

"contextmenu"

In dit geval wordt naar de gebeurtenis 'contextmenu' geluisterd: het openen van het contextuele menu. Dat is dat menuutje dat bij rechtsklikken of bij langer aanraken opent.

function (e) {e.preventDefault(); }

En hier dan wat er moet gebeuren. function() is gewoon een soort aankondiging dat er iets gaat gebeuren. Erachter tussen de accolades staat, wat er gaat gebeuren: preventDefault(). Voorkom de standaardactie. Dat is hier het openen van het contextuele menu.

In sommige browsers op touchscreens opent dat contextuele menu nogal snel, en dat is hier irritant, want er zal weinig animo zijn om zo'n smiley te printen, kopiëren, te mailen of wat er nog meer aan feestelijkheden in de aanbieding is.

Bij de uitleg van deze code zijn allerlei haakjes, de letter e, en dergelijke 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.

De eventlistener 'contextmenu' is vrij nieuw. Hij werkt (nog) niet op iOS, op Windows Phone en in UC browser en Android browser op Android. Dat is geen groot probleem of zo, want het is meer 'n extra dan dat het absoluut noodzakelijk is.