Tijdschrift voor webwerkers » Artikel #91
Vroeger was het zo simpel. Je kreeg een ontwerp aangeleverd, inclusief de waarschuwing dat alles pixel-precies moest kloppen in de browser van de klant, Explorer 3.
Je zette een basistabel op, zorgde dat spacer.gif
in je pixmap stond, en kon beginnen.
Menulijsten, subtiele dropshadows, teksten met een marge, het waren allemaal dankbare aanleidingen om een
nieuw blik tabellen open te trekken. Klopte het daarna nog steeds niet helemaal, dan moest je er nog veel
en veel meer tabellen inproppen, anders kreeg de ontwerper een creatieve hartverzakking.
Tegenwoordig weten we beter. We hebben tabellen-in-tabellen-in-tabellen naar de vuilnisbelt van de geschiedenis verwezen, scheiding van structuur en presentatie omarmd, en zijn enthousiast geworden over CSS. Niettemin is het praktiseren van nieuwe technieken alléén niet voldoende. pagina’s die volledig in CSS zijn gemaakt, kunnen ook een ongelofelijke warboel vormen, en haast niet te wijzigen zijn zonder dagenlange studie (ik kan het weten, ik heb ook zulke pagina’s gemaakt).
Maar hoe maak je nu een goede XHTML-structuur, die een solide basis vormt voor CSS en JavaScript, en die voor andere webontwikkelaars makkelijk te begrijpen is?
De voorkant van een website rust op drie poten: structuur, presentatie en gedrag, oftewel XHTML, CSS en JavaScript. Deze drie poten dienen goed met elkaar samen te werken en strikt van elkaar gescheiden te zijn. Klinkt tegenstrijdig, maar dat is het niet.
Strikt gescheiden betekent dat elke poot zijn eigen plek heeft: .html
bestanden voor de
structuur, een .css
bestand voor de presentatie en een .js
bestand voor het
gedrag. Een beetje site bestaat uit tientallen XHTML-pagina’s, maar als al deze pagina’s naar
dezelfde .css
en .js
bestanden linken, kun je door een paar regels code te
veranderen de presentatie of het gedrag van de gehele site wijzigen. Strikte scheiding vereenvoudigt dus
het onderhoud van de site.
Strikte scheiding kan ook tot schonere code leiden. Je hoeft geen <FONT>
tags, geneste
tabellen en andere opmaakcode meer te gebruiken, je kunt het lettertype en de marges immers via CSS
instellen. Je hoeft ook geen event handlers, zoals
onMouseOver="switchImages('tranendal',7,false)"
, in je XHTML meer te
zetten. Je kunt de event handlers immers geheel vanuit het .js bestand initialiseren.
Hierdoor blijft je XHTML overzichtelijk, en ook je JavaScript kan aan duidelijkheid winnen. Een strikt gescheiden JavaScript kan nog steeds een rommeltje zijn, maar je bent er tenminste zeker van dat alle noodzakelijke code zich in één bestand bevindt, en dat je niet ook nog tientallen XHTML-pagina’s hoeft te doorzoeken op obscure functie-aanroepen.
XHTML, CSS en JavaScript moeten wel goed samenwerken. De belangrijkste voorwaarde voor deze samenwerking is een goede XHTML-structuur. De zogenaamde semantische benadering biedt hier aanknopingspunten.
Sommige XHTML elementen hebben een speciale betekenis. <h1>
, bijvoorbeeld, is
“van nature” een kop, terwijl een <p>
“van nature” een
paragraaf is. Je kunt er redelijkerwijs van uitgaan dat alle grafische- en tekstbrowsers een kop meer
gewicht zullen geven dan gewone tekst, en een paragraaf netjes zullen scheiden van andere paragrafen.
Voorleesbrowsers voor blinden en slechtzienden zouden de kop iets anders kunnen uitspreken en een kleine
pauze tussen de paragrafen in acht kunnen nemen.
Natuurlijk mag elke browser zelf bepalen hoe hij met deze structurele elementen omgaat, en sommigen zullen het slechter doen dan anderen. Niettemin heb je als webontwikkelaar je plicht gedaan: je hebt duidelijk aangegeven welke tekst waarvoor dient.
Vanuit deze benadering is het algemeen gebruik geworden om de hoofdnavigatie van je site in een
<ul>/<li>
te structureren. Een <ul>
is immers semantisch
gezien een lijst, en de links in de hoofdnavigatie vormen ook een lijst. Nadat je op deze manier de
navigatie correct hebt gestructureerd, kun je je in CSS druk gaan maken over de presentatie van de links.
Verder horen tabellen uitsluitend gebruikt te worden voor het presenteren van tabulaire data (data is tabulair als je zelfs in drukwerk een tabel zou gebruiken om ze te presenteren). Dat is op zich goed, maar het probleem is dat sommige soorten presentatie – vooral rasters en verticale uitlijning – niet of heel moeilijk in CSS te creëeren zijn. Tabellen zijn dan veel makkelijker.
Een enkele keer is het gebruik van één (1!) tabel om de hoofdelementen in een raster te plaatsen dus ook toegestaan. Maar probeer het altijd eerst in CSS! Een tabel is een paardenmiddel dat uitsluitend gebruikt mag worden als je na dagen nijver CSS schrijven nog steeds helemaal nergens bent gekomen. Zelfs een mislukte CSS-poging geeft je veel meer nuttige ervaring dan de zoveelste tabel.
Helaas hebben niet alle semantische regels zin. Haarkloverijen over de relatieve waarde van
<b>
en <strong>
, of het correcte gebruik van de zes headers bieden
soms leuke lectuur, maar hebben weinig praktische waarde en kunnen een moralistische ondertoon krijgen die
sommige webontwikkelaars doet besluiten semantiek en standaarden maar te laten voor wat ze zijn en verder
te ploeteren met tabellen-in-tabellen.
Gebruik dus altijd je gezonde verstand als het over semantiek gaat, en wantrouw de predikers.
Omgekeerd is niet alle XHTML semantisch verantwoord. De veelgebruikte <div>
heeft geen
enkele “natuurlijke” betekenis, en wordt alleen gebruikt om er presentatie en gedrag aan te
hangen. Daar is op zich niets mis mee, maar het probleem is dat <div>
zich als de
tabellen van het CSS-tijdperk beginnen te gedragen. Werkt ’t niet? Prop er meer
<div>
’s in! Dat is jammer, en hopelijk zullen er in de toekomst betere regels
komen om excessieve “divitis” te vermijden.
Als je eenmaal een XHTML-structuur gemaakt hebt, voeg je een <link>
tag toe die de
presentatie importeert en een <script>
tag die het gedrag importeert.
Presentatie en gedrag hebben aanhaakpunten nodig, code waarmee je als webontwikkelaar kunt zeggen “presenteer dit blok zo” en “geef alle links in dit blok dat gedrag”
De meest gebruikelijke aanhaakpunten zijn class
en id
. Voor CSS zijn ze
onontbeerlijk. Let op: “onontbeerlijk” betekent niet “prop maar door totdat alles een
class
heeft“. Structuren als deze zijn niet nodig:
<div class="text">
<div class="bodytext">
<p class="maintext">Ontslagbegeleidingsprocedures zijn geen zaak meer voor
de betrokkenen alleen.</p>
</div>
<div class="bodytext">
<p class="maintext">Ook overheid, vakbonden en maatschappelijk middenveld
spreken tegenwoordig een woordje mee.</p>
</div>
</div>
<div class="tekst">
<p>Ontslagbegeleidingsprocedures zijn geen zaak meer voor de betrokkenen
alleen.</p>
<p>Ook overheid, vakbonden en maatschappelijk middenveld spreken
tegenwoordig een woordje mee.</p>
</div>
Je hoeft de paragrafen geen aparte class
te geven, je kunt ze stijlen door de div.tekst
p
selector. Deze zogenaamde “descendant selector”
is uitermate krachtig en ik gebruik hem zelf graag en vaak. Deel je pagina in in verschillende blokken met
een class
of id
, gebruik binnen deze blokken uitsluitend simpele structurele
XHTML, en je kunt er zonder problemen stijlen aan toekennen.
Neem dit voorbeeld:
<div class="navigatie">
<ul>
<li><a href="sollproc.html">Sollicitatieprocedures</a></li>
<li><a href="ontproc.html">Ontslagprocedures</a></li>
<li><a href="ontbegproc.html">Ontslagbeleidingsprocedures</a></li>
</ul>
</div>
<div class="tekst">
<p>Ontslagbegeleidingsprocedures zijn geen zaak meer voor de betrokkenen
alleen.</p>
<p>Ook overheid, vakbonden en <a href="mm.html">maatschappelijk
middenveld</a> spreken tegenwoordig een woordje mee.</p>
</div>
De links in de navigatie stijl je met div.navigatie a
, die in de tekst met div.tekst
a
. Zoals je ziet heb je geen extra class
es nodig, de twee div
s zijn
voldoende.
Navigatiestijlen zijn meestal wat complexer dan tekststijlen, en daarom is het bijzonder handig dat de
navigatie naast a
-elementen ook li
-elementen bevat. Kijk bijvoorbeeld eens naar
Sliding Doors of CSS, een
schitterende techniek van CSS-goeroe Douglas Bowman die zonder een li/a
structuur niet werkt.
Alleen als je een zeer expliciete uitzondering wilt definieren, kun je een extra class
of
id
toekennen, zoals bijvoorbeeld:
<div class="navigatie">
<ul>
<li><a href="sollproc.html">Sollicitatieprocedures</a></li>
<li><a href="ontproc.html">Ontslagprocedures</a></li>
<li><a href="ontbegproc.html" id="hierbenik">Ontslagbeleidingsprocedures</a></li>
</ul>
</div>
Nu kun je een specifieke stijl definieren voor de link naar de pagina waar de gebruiker op dit moment is.
Deze link is een uitzondering, daarom is het gebruik van een extra id
toegestaan.
Als je jezelf strenge regels oplegt voor het gebruik van class
es en id
's, en
pas na grote aarzeling een extra class
of id
toevoegt, dan zal dat schonere en
duidelijkere code opleveren.
Ook JavaScript heeft aanhaakpunten nodig. In simpele situaties kun je dezelfde class
es en
id
's gebruiken die je al voor CSS gedefinieerd hebt. Over het algemeen werkt JavaScript
beter met id
's, omdat de getElementById()
methode een simpele manier
verschaft om elementen met een bepaald id
aan te spreken. Er is geen overeenkomstige
getElementsByClassName()
methode, dus als je een element met een bepaalde class
wilt zoeken, moet je het gehele document doorlopen.
Laten we een gedrag toekennen aan alle links in de navigatie, bijvoorbeeld het tonen van een klein blokje extra informatie over elke link. Dat zou je ook met CSS kunnen doen, maar vandaag gebruiken we JavaScript, mede omdat het een open vraag is welke methode "beter" is.
We willen dus een onmouseover
event handler toekennen aan alle links in de navigatie,
maar niet aan de links in het tekstgedeelte. Derhalve is het lastigste probleem het zoeken van de correcte
links, oftewel het zoeken naar een aanhaakpunt.
De structuur van onze simpele pagina geeft al direct een "natuurlijk" aanhaakpunt: alle
navigatielinks staan in een <ul>
. We zouden dus dit kunnen doen:
var x = document.getElementsByTagName('ul')[0].getElementsByTagName('a');
for (var i=0;i<x.length;i++)
x[i].onmouseover = toonExtraInfo;
Pak alle a
elementen die kinderen zijn van het eerste ul
-element in de pagina en
geef ze allemaal een onmouseover
event handler mee.
Dit werkt in eerste instantie prima. Deze aanpak legt echter de structuur van de XHTML aan zeer rigide
banden. Je moet er volkomen zeker van zijn dat er nooit een <ul>
vóór de
navigatie zal voorkomen, niet alleen in de huidige site, maar ook in alle eventuele toekomstige
uitbreidingen. Je kunt dus nooit de navigatie eens naar onderaan het document verplaatsen, omdat je dan in
problemen zou komen als het tekstgedeelte ook een <ul>
bevat.
Verder moet moet je er volkomen zeker van zijn dat je altijd en eeuwig de <ul>
in de
navigatie zal blijven gebruiken, en hem nooit zal inruilen voor, bijvoorbeeld, een
<ol>
.
Zelf vind ik deze structuur te rigide. Ik ga liever één stapje hoger en neem de <div
class="navigatie">
als aanhaakpunt, omdat dit veel logischer is. De
<div>
zal altijd blijven bestaan als container van de navigatie, en als ik op
class
zoek, maakt het ook niet meer uit waar in het document de <div>
precies staat. Ik kan de navigatie nu naar de onderkant van het document verplaatsen zonder mijn script te
herzien.
var x = document.getElementsByTagName('div');
for (var i=0;i<x.length;i++)
{
if (x[i].className != 'navigatie') continue;
var y = x[i].getElementsByTagName('a');
for (var j=0;j<y.length;j++)
y[j].onmouseover = toonExtraInfo;
}
Maar deze functie is ook redelijk ingewikkeld, omdat we alle <div>
's in het hele
document moeten aflopen om te kijken of ze soms class="navigatie"
hebben. Vandaar
dat ik er nog liever voor kies om de class
in een id
te veranderen:
<div id="navigatie">
Dan krijgen we dit simpele script:
var x = document.getElementById('navigatie').getElementsByTagName('a');
for (var i=0;i<x.length;i++)
x[i].onmouseover = toonExtraInfo;
Mijns inziens is een id
het beste aanhaakpunt voor een simpel script.
Het kiezen van aanhaakpunten kan echter ingewikkeld worden. Als je iets schrijft dat complexer is dan één klein effectje op één groep elementen, moet je eerst een half uur fundamenteel nadenken over je XHTML-structuur.
Neem bijvoorbeeld een formuliervalidatie; het zou erg handig zijn om in de XHTML van een formulierveld aan te kondigen dat dit veld verplicht is. Je kunt dan dit soort code gaan gebruiken
function valideerFormulier()
{
var x = document.forms[0].elements;
for (var i=0;i<x.length;i++)
{
if ([dit veld is verplicht] && !x[i].value)
// wijs gebruiker op fout
}
}
We moeten dus eerst kijken of een formulierveld verplicht is, als het dat is en geen waarde heeft, dan
waarschuwen we de gebruiker en zetten de formulierverzending stop. Maar hoe definieren we dit aanhaakpunt?
Een mogelijkheid is de informatie in de class
op te nemen:
<input name="naam" class="verplicht" />
if (x[i].className == 'verplicht' && !x[i].value)
Als je ook CSS-class
es wilt gebruiken, gebruik je
<input name="naam" class="breedveld verplicht" />
if (x[i].className.indexOf('verplicht') != -1 && !x[i].value)
Persoonlijk ben ik echter niet zo gecharmeerd van deze aanpak. class
es zijn voor CSS bedoeld,
niet voor JavaScript. Bovendien wordt het benodigde script ingewikkelder dan noodzakelijk is.
Neem nu een script dat bijhoudt hoeveel tekens de gebruiker in een textarea heeft getypt (het oude
maxlength
attribuut werkt alleen voor <input>
, niet voor
<textarea>
).
In de site zitten meerdere van deze textareas, en ze accepteren allemaal een ander maximum aantal tekens. We hebben nu twee brokjes informatie nodig:
We krijgen dan een script als:
var x = document.getElementsByTagName('textarea');
for (var i=0;i<x.length;i++)
{
if ([deze textarea heeft een maximumlengte])
x[i].onkeypress = controleerLengte;
}
function controleerLengte()
{
var max = [lees de maximumlengte];
if (this.value.length > max)
// wijs gebruiker op fout
}
Laten we proberen dit aanhaakpunt te definieren met een class
. Het kan, maar het wordt erg
ingewikkeld:
<textarea class="groot maxlen=300">
Uitvinden of de textarea een maximumlengte heeft is nog simpel:
if (x[i].className.indexOf('maxlen') != -1)
x[i].onkeypress = controleerLengte;
Maar nu moeten we de daadwerkelijke waarde van de maximumlengte eruit peuteren, en dat is erg lastig. We
nemen aan dat de maxlen
de laatste waarde in de class
is (als het dat niet is,
wordt de code nog ingewikkelder).
var tmp = this.className.substring(this.className.indexOf('maxlen'));
var max = tmp.substring(tmp.indexOf('=')+1);
Nogmaals, technisch gesproken kan dit allemaal. Maar als we eens goed naar dit voorbeeld kijken, zien we dat de maximumlengte het meest logisch kan worden uitgedrukt als een naam/waarde paar, oftewel een attribuut. Als het attribuut aanwezig is, dient de textarea gecontroleerd te worden, en de waarde van het attribuut geeft de maximumlengte:
<textarea class="groot" maxlen="300">
if (x[i].getAttribute('maxlen'))
x[i].onkeypress = controleerLengte;
var max = this.getAttribute('maxlen');
Veel simpeler, toch? Het enige nadeel is dat het maxlen
attribuut niet bestaat, en dat de W3C
validator begint te klagen als hij hem tegenkomt. Mijns inziens is dat geen groot probleem, je kunt deze
meldingen gewoon negeren zonder dat het nadelige gevolgen heeft.
Niettemin zullen sommige webontwikkelaars valide XHTML op prijs stellen. Daarom moet iedereen voor zich
beslissen of hij dergelijke maatwerkattributen wil gebruiken, of de validator tevreden wil stellen door de
informatie in de class
op te nemen.
En waarom gebruik ik maxlen
in plaats van maxlength
? Omdat Opera geen bestaande
attributen op de verkeerde tags accepteert. Een script dat naar maxlength
in een
<textarea>
zoekt werkt niet in deze browser, omdat het attribuut alleen maar op een
<input>
bestaat. Attributen die in het geheel niet bestaan, mogen echter weer wel van
deze browser, en ook van alle andere.
We hebben nu een logische, simpele XHTML structuur die aanhaakpunten voor CSS en JavaScript bevat. Als de pagina ook nog aan de toegankelijkheidseisen voldoet, zijn we een heel eind gekomen. Maar hoe controleer je dat?
Bekijk de pagina eens zonder presentatie en gedrag, en zelfs zonder plaatjes. Verwijder de
<link>
tag naar de presentatie en de <script>
tag naar het gedrag,
schakel de plaatjes uit (bijvoorbeeld door alle 'pix/'
in de pagina even tijdelijk
door 'ix/'
te vervangen). Bekijk de pagina. Kun je makkelijk bij zowel navigatie als
inhoud komen? Werkt de navigatie? Is de titel/kop van de pagina duidelijk? Mis je informatie doordat
plaatjes ontbreken? Is er functionaliteit die JavaScript vereist?
Als de tekst nog steeds leesbaar en begrijpelijk is, en als de navigatie nog steeds werkbaar is, weet je dat je pagina in principe toegankelijk is. Is de pagina ontoegankelijk, los het probleem dan op de simpelste manier op. Een extra linkje of paragraafje dat je met CSS of JavaScript verbergt voor moderne grafische browsers kan al wonderen doen.
Let op zinvolle alt
-teksten voor plaatjes. Een goede alt
-tekst herhaalt de
letterlijke tekst in het plaatje, inclusief hoofdletters en leestekens. Als er geen tekst in het plaatje
staat, moet je je afvragen of een alt
-tekst zin heeft. alt="Sfeerbeeld met
komkommer"
helpt niemand, maar alt="Foto van demonstranten met ludieke
zwaaihandjes"
zou, afhankelijk van de context, nuttige informatie kunnen leveren. Besluit je
dat een alternatieve tekst zinloos is, gebruik dan alt=""
, zodat browsers geen
teksten als “Image” tonen (of uitspreken).
Na deze acties heb je nog niet aan alle toegankelijkheidsrichtlijnen voldaan, maar je weet wel zeker dat je 90% van de problemen hebt opgelost.
class
es en id
's gebruiken.
Het is eigenlijk niet eens zo moeilijk.
is freelance webontwikkelaar te Amsterdam. Hij is gespecialiseerd in client side programmeren (xhtml, css, javascript).
Publicatiedatum: 13 oktober 2004
Naar Voren is op 18 juli 2010 gestopt met publiceren. De artikelen staan als een soort archief online. Het kan dus zijn dat de informatie verouderd is en dat er inmiddels veel betere of makkelijkere manieren zijn om je doel te bereiken.
Copyright © 2002-heden » NAAR VOREN en de auteurs