Tijdschrift voor webwerkers » Artikel #131
JavaScript geeft je de mogelijkheid om de CSS-presentatielaag van je site te veranderen. Een verandering in hoe een element in de pagina er uit ziet is een uitstekende (en veelgebruikte) manier om de aandacht van je bezoekers te trekken naar het element waar je hun aandacht wilt hebben.
Zeven van de voorbeeldscripts in mijn boek gebruiken een of andere vorm van CSS-modificatie. Form Validation, bijvoorbeeld, verandert de stijl van een formulierveld dat niet correct is, en XMLHTTP Speed Meter gebruikt animaties (d.w.z. meerdere veranderingen in dezelfde stijl in korte tijd) om het oog van de bezoeker naar de gegevens over de snelheid te trekken (en, eerlijkheidshalve, ook om het er extra leuk uit te laten zien). Dropdown Menu gebruikt stijlveranderingen om menu-items te tonen en verbergen. Al deze veranderingen hebben hetzelfde doel: het oog van de bezoeker naar het element te trekken waar je hun aandacht op wilt vestigen.
JavaScript kan op vier manieren de CSS veranderen:
style
property van een element te modificeren (element.style.margin =
'10%'
).
element.className =
'error'
). De browser past automatisch de stijl toe die is gedefinieerd voor de nieuwe class
of id.
document.write('<style>.accessibility {display: none}</style>'
).
De meeste scripts die CSS modificeren gebruiken óf de style
property óf een class/id change.
De document.write
methode wordt alleen in bepaalde gevallen gebruikt om de toegankelijkheid
van een pagina te vergroten. Het veranderen van het hele stylesheet is maar zelden nuttig, omdat het niet
door alle browsers ondersteund wordt en omdat je in de meeste gevallen alleen bepaalde elementen
wilt selecteren waarvan je de stijl wilt veranderen.
Ik zal echter alle vier de methoden gebruiken in de voorbeeldscripts. In dit hoofdstuk zullen we ze allemaal bekijken, in de juiste context.
NOOT: De bespreking van de laatste twee methoden is niet opgenomen in deze voorpublicatie.
De eerste en bekendste manier om CSS aan te passen is met behulp van de style
property die
alle HTML elements hebben en die toegang biedt tot hun inline styles. style
bevat één
property voor iedere inline CSS declaration. Als je de CSS margin van een element wilt wijzigen, gebruik
je element.style.margin
. Als je de CSS color wilt wijzigen, gebruik je
element.style.color
. De JavaScript property heeft altijd een naam die lijkt op die van de CSS
property.
Onthoud: de style property van een HTML element geeft toegang tot de inline styles van dat element.
Laten we eerst eens naar wat CSS-theorie kijken. CSS geeft je vier manieren om de stijl van een element te
definiëren. Je kunt inline styles gebruiken, waarbij je je CSS direct in het style
attribuut
van de HTML tag plaatst:
<p style="margin: 10%">Test</p>
Daarnaast kun je een stylesheet embedden, er naar linken, of hem importeren. Maar aangezien een inline
style specifieker is dan alle andere soorten stijlen, overschrijft hij stijlen die gedefinieerd zijn in
een gelinkte, embedded of geïmporteerde style. Omdat de style
property toegang geeft tot deze
inline styles, gaat het altijd voor alle andere stijlen. Dat is de grote kracht van deze methode.
Maar wanneer je de stijlen probeert in te lezen kan het zijn dat je problemen tegen komt. Neem dit voorbeeld:
<p id="test">Test</p>
p#test {
margin: 10%;
}
alert(document.getElementById('test').style.margin);
De testparagraaf heeft geen inline styles. In plaats daarvan wordt de marge, margin: 10%
,
gedefinieerd in een embedded (of gelinkte of geïmporteerde) stylesheet en kan daardoor niet gelezen worden
door middel van de style property. De alert blijft leeg.
In het volgende voorbeeld zal de alert de waarde "10%" laten zien, omdat de margin nu gedefinieerd is als een inline style:
<p style="margin: 10%" id="test">Text</p>
alert(document.getElementById('test').style.margin);
De style property is dan ook uitstekend geschikt om stijlen te definiëren, maar veel minder voor het inlezen. Verderop in dit artikel zullen we manieren bespreken waarop we de stijlen kunnen inlezen uit embedded, gelinkte of geïmporteerde stylesheets.
Veel CSS property-namen bevatten een verbindingsstreepje, zoals bijvoorbeeld font-size
. In
JavaScript betekent het verbindingstreepje echter 'min', dus kun je het niet gebruiken in je
property namen. Dit veroorzaakt een foutmelding:
element.style.font-size = '120%';
Moet de browser de (ongedefinieerde) variabele size
aftrekken van
element.style.font
? En zo ja, wat betekent het stukje = '120%'
? In
plaats daarvan verwacht de browser een camelCase property naam:
element.style.fontSize = '120%';
De algemene regel is dat alle verbindingsstreepjes verwijderd worden uit de CSS property namen, en dat de
letter na het verbindingsstreepje een hoofdletter wordt. Op die manier wordt margin-left
marginLeft
, text-decoration
wordt textDecoration
, en
border-left-style
wordt borderLeftStyle
.
Veel numerieke waarden in JavaScript moeten een eenheid hebben, net zoals in CSS. Wat betekent
fontSize=120
? 120 pixels? 120 punts? 120 procent? De browser weet het niet en doet daarom ook
niets. De eenheid is onmisbaar om te laten zien wat je bedoeling is.
Laten we eens kijken naar de setWidth()
functie, die het hart vormt van de animaties in de
XMLHTTP Speed Meter:
XMLHTTP Speed Meter, regel 70-73
function setWidth(width) {
if (width < 0) width = 0;
document.getElementById('meter').style.width = width + 'px';
}
De functie krijgt een waarde aangereikt en zou de breedte van de meter aan deze nieuwe waarde moeten
aanpassen. Na een veiligheidstest die alleen waarden doorlaat die groter dan of gelijk zijn aan 0, krijgt
de style.width
van het element de nieuwe breedte. Daarna voegt de functie +
'px'
toe, omdat de browser anders niet zou weten hoe hij het getal moest interpreteren en
niets zou doen.
Het toevoegen van de 'px
' eenheid aan hoogte of breedte wordt regelmatig vergeten
wanneer CSS gemodificeerd wordt. In de CSS Quirks Mode is het
toevoegen van 'px
' niet nodig, aangezien de browsers de oude regel volgen dat een
getal zonder eenheid een pixelwaarde is. Dat is op zichzelf geen probleem, maar veel webontwikkelaars
hebben de gewoonte aangeleerd om eenheden weg te laten wanneer ze hoogtes of breedtes veranderen, en
komen dan problemen tegen wanneer ze in CSS Strict Mode werken.
Pas op: u nadert browserproblemen
Zoals we gezien hebben, kan de style
property geen stijlen uitlezen die zich bevinden in
embedded, gelinkte of geïmporteerde stylesheets. Omdat webontwikkelaars af en toe tóch die stijlen moeten
ophalen, hebben Microsoft en het W3C allebei een manier bedacht om non-inline styles te
benaderen. De oplossing van Microsoft werkt alleen in Explorer, terwijl de W3C-standaard in Mozilla en
Opera werkt.
De oplossing van Microsoft is de currentStyle
property, die precies zo werkt als de
style
property, behalve dat:
Een voorbeeld:
var x = document.getElementById('test');
alert(x.currentStyle.color);
De alert toont de huidige color
style van het element, onafhankelijk van waar hij bepaald
wordt.
De oplossing van het W3C is de window.getComputedStyle()
methode, die ruwweg op de zelfde
manier werkt maar met een complexere syntax.
var x = document.getElementById('test');
alert(window.getComputedStyle(x,null).color);
getComputedStyle()
geeft altijd een pixel-waarde terug, zelfs als de beginwaarde van de style
bijvoorbeeld 50em
of 11%
was.
Zoals altijd wanneer we verschillen tussen de browsers tegenkomen, moeten we een beetje vorken in de code om alle browsers tevreden te stellen:
function getRealStyle(id,styleName) {
var element = document.getElementById(id);
var realStyle = null;
if (element.currentStyle)
realStyle = element.currentStyle[styleName];
else if (window.getComputedStyle)
realStyle = window.getComputedStyle(element,null)[styleName];
return realStyle;
}
Je gebruikt deze functie als volgt:
var textDecStyle = getRealStyle('test','textDecoration');
Onthoud dat getComputedStyle()
altijd een pixelwaarde teruggeeft, terwijl
currentStyle
de eenheid handhaaft die in de CSS werd gespecificeerd.
Pas op: u nadert browserproblemen
Of je nu inline styles benadert via de style property of andere stijlen via de functie die we zojuist besproken hebben, je zult altijd problemen tegenkomen wanneer je shorthand styles wilt uitlezen.
Zoals bij deze border declaratie:
<p id="test" style="border: 1px solid #cc0000;">Text</p>
Aangezien dit een inline style is, zou je verwachten dat deze regel code werkt:
alert(document.getElementById('test').style.border);
Helaas, hij werkt niet. De browsers verschillen van mening over welke waarde ze zullen tonen in de alert.
Let op de speciale color syntax die Mozilla gebruikt: rgb(204,0,0)
. Dit is een valide
alternatief voor de traditionele #cc0000;
en je kunt beiden manieren gebruiken in CSS en
JavaScript.
Het problem is dat border een ‘shorthand’ declaratie is,
een afgekorte declaratie. Hij bestaat ‘onder water’uit niet minder dan twaalf stijlen:
breedte, stijl en kleur voor de boven-, linker-, onder- en rechterkant. Op dezelfde manier is de font
declaratie shorthand voor font-size
, font-family
, font-weight
, en
line-height
, dus krijg je met dezelfde problemen te maken .
Hoe moet de browser omgaan met dergelijke shorthand declaraties? Het voorbeeld hierboven lijkt duidelijk;
je zou intuïtief verwachten dat de browser de waarde 1px solid #cc0000
aangeeft, precies
zoals het inline style attribute. Helaas zijn shorthand properties ingewikkelder.
Kijk eens naar het volgende voorbeeld:
p {
border: 1px solid #cc0000;
}
<p id="test" style="border-color: #00cc00;">Test</p>
alert(document.getElementById('test').style.borderRightColor);
Alle browsers rapporteren de juiste kleur, ondanks dat de inline style geen
border-right-color
bevat maar een border-color
declaratie. Kennelijk gaan de
browsers er van uit dat de kleur van de rechter rand bepaald is wanneer de kleur van de gehele rand is
vastgesteld. Geen onredelijke manier van denken.
Zoals je ziet moeten browsers regels bedenken voor dit soort ongewone situaties, en ze hebben allemaal nét iets verschillende regels vastgesteld bij het behandelen van shorthand declaraties. Er is geen standaard-specificatie voor hoe de shorthandproperties exact behandeld moeten, dus het is ook onmogelijk om uit te maken welke browsers het goed doen en welke fout.
JavaScript geeft je de mogelijkheid om de class of de id van een element te veranderen. Op het moment dat je dat doet, actualiseert de browser automatisch de stijlen van het element.
Na de baaierd aan ingewikkelde details en browserproblemen die we tegenkwamen bij de behandeling van de
style
property zijn veranderingen aan class en id een oase van begrijpelijkheid en pais en
vree. Zoals in dit voorbeeld:
p {
color: #000000; /* black */
}
p.emphasis {
color: #cc0000; /* red */
}
<p id="test">Test</p>
Als we beginnen heeft de paragraaf geen class en is daarom de kleur van de paragraaf zwart. Eén regel JavaScript is echter genoeg om de styles te veranderen:
document.getElementById('test').className = 'emphasis';
De tekst wordt direct rood. Om het weer terug te veranderen doe je het volgende:
document.getElementById('test').className = '';
Je verwijdert de class en de paragraaf valt weer terug op de standaard p{}
regel.
Let er op dat JavaScript className
gebruikt, omdat class
in reserve wordt
gehouden voor een mogelijke toekomst waarin JavaScript wellicht Java-achtige classes gaat ondersteunen.
Voor een praktijkvoorbeeld kijken we naar Textarea Maxlength. De teller heeft deze structuur en presentatie (de structuur wordt gegenereerd door JavaScript, maar dat doet er niet toe):
<div class="counter"><span>12</span>/1250</div>
div.counter {
font-size: 80%;
padding-left: 10px;
}
span.toomuch {
font-weight: 600;
color: #cc0000;
}
Wanneer het script ziet dat de bezoeker de maximumlengte heeft overschreden, verandert het de class van de
counter span in toomuch
:
Textarea Maxlength regel 20-23
if (currentLength > maxLength)
this.relatedElement.className = 'toomuch';
else
this.relatedElement.className = '';
Nu wordt de counter <span>
vet en rood.
Een id-verandering werkt op precies dezelfde manier:
p {
color: #000000; /* black */
}
p#emphasis {
color: #cc0000; /* red */
}
<p>Test</p>
document.getElementsByTagName('p')[0].id = 'emphasis';
Weer wordt de paragraaf rood. Toch adviseer ik je om niet te veel te werken met veranderingen aan de ids. Naast dat ze werken als aanhaakpunten voor de CSS, werken ze vaak ook als aanhaakpunt voor de JavaScripts, en als je ze weghaalt kan dat vreemde bijverschijnselen opleveren. In de praktijk kun je elke CSS-modificatie die je nodig hebt bereiken met veranderingen in de class, en hoef je niet te werken met ids.
In veel gevallen hoef je de class van een bepaald element niet te veranderen in een nieuwe waarde. In plaats daarvan zul je een nieuwe class-waarde toevoegen, omdat je geen stijlen wilt verwijderen die het element misschien al heeft. CSS geeft je de mogelijkheid om meerdere classes te gebruiken, en dus worden de stijlen van de nieuwe class toegevoegd aan het element zonder dat je de instructies die al bestaande classes geven weghaalt.
De writeError()
en removeError()
functies van Form Validation zijn een goed
voorbeeld. Ik gebruik meestal een aantal classes voor formuliervelden, omdat het grafisch ontwerp in veel
gevallen twee of zelfs drie verschillende breedtes gebruikt voor invulvelden. Op het moment dat een
formulierveld een fout bevat wil ik een speciale waarschuwingsstijl gebruiken, maar ik wil de stijl die
het element al heeft niet verstoren. Daarom kan ik de bestaande class-waarde niet simpelweg overschrijven:
dan zou ik mijn specifieke breedtes kwijtraken.
Kijk bijvoorbeeld eens naar deze situatie:
<input class="smaller" name="name" />
input.smaller {
width: 75px;
}
input.errorMessage {
border-color: #cc0000;
}
Het uitgangspunt is een invulveld met een breedte van 75px. Wanneer het script de class verandert in
'errorMessage
' en de oude waarde weggooit, krijgt de rand rond het formulierveld een
rode kleur, maar hij verliest zijn breedte, en dat zou erg verwarrend zijn voor de bezoeker.
Daarom besluit ik de class errorMessage
toe te voegen:
Form Validation, regel 105-106
function writeError(obj,message) {
obj.className += ' errorMessage';
Deze code pakt de bestaande className en voegt er een nieuwe class aan toe, voorafgegaan door een spatie. Deze spatie zorgt er voor dat de nieuwe class-waarde gescheiden wordt van de class-waardes die het object al heeft. Nu krijgt het invulveld een rode rand mét een breedte van 75px—precies wat we willen. Het invulveld past nu beide classes toe, alsof de HTML het volgende was:
<input class="smaller errorMessage" name="name" />
Op het moment dat de bezoeker haar vergissing hersteld heeft, moeten we de class errorMessage
verwijderen. Maar classes die in de uitgangspositie aanwezig waren moeten ongemoeid blijven. De
removeError()
functie levert die functionaliteit:
Form Validation, regel 119-120
function removeError() {
this.className = this.className.replace(/errorMessage/,'');
De functie pakt de class van het element en verandert de string 'errorMessage
' in
'' (een lege string). Het stukje “errorMessage
” wordt verwijderd uit de
class-waarde, maar de andere waarden worden in tact gelaten. Het invulveld raakt de rode kleur van zijn
rand kwijt, maar de rand behoudt de breedte van 75px.
Misschien is het je opgevallen dat removeError()
de class-waarde
“errorMessage
” verwijdert zonder de spatie die er aan voorafgaat. Dat heeft te
maken met een browserbug. Als je “ errorMessage
” toevoegt aan een class die nog
geen waarde heft, gooit Mozilla de spatie aan het begin weg. Als we daarna replace(/
errorMessage/,''
) doen, zal Mozilla de class niet verwijderen: hij kan namelijk de string
“ errorMessage
” niet vinden omdat de spatie aan het begin ervan er niet is.
NOOT: De secties C en D van het hoofdstuk maken geen deel uit van dit artikel. Ze gaan
over het toevoegen van stijlen met document.write()
(wat je alleen zou moeten doen uit
toegankelijkheidsoverwegingen) en over het veranderen van hele stylesheets. Beide technieken zijn vrij
specialistisch en zouden niet gebruikt moeten worden in de gemiddelde website.
Na deze paragrafen gaat het hoofdstuk verder met het vergelijken van de vier methoden.
Nu we alle vier de methoden van CSS-modificatie bekeken hebben, kunnen we ons afvragen welke methode de
beste is. De document.write
-methode zou alleen gebruikt moeten worden in speciale situaties
die te maken hebben met toegankelijkheid. Het veranderen van een heel stylesheet is maar zelden nuttig.
Dan blijven er nog twee methoden over. Wat kun je het beste doen: de style
property gebruiken
of class- en id-waarden veranderen?
Om daar een antwoord op te formuleren zullen we eens kijken naar de voorbeeldscripts.
Site Survey verandert geen CSS, Edit
Style Sheet verandert de hele stylesheet, en Usable Forms
gebruikt de document.write
-methode. Alleen XMLHTTP Speed
Meter verandert style
properties, terwijl vier scripts — Textarea Maxlength, Sandwich Picker, Form Validation en Dropdown Menu —
veranderingen in de class gebruiken. Zoals je misschien al raadt, vind ik het veranderen van de class in
de meeste gevallen de beste CSS-modificatietechniek.
Ik ben van mening dat te veel leunen op de style
property de scheiding van presentatie en
gedrag aantast, en het is ook nog eens ingewikkelder om te schrijven. Stijlen horen in de CSS
presentatielaag—hun natuurlijke omgeving—niet in de HTML structuurlaag of in de JavaScript
gedraglaag.
Op het moment dat je een style verandert zeg je “geef dit element een nieuw uiterlijk”. Het geven van deze opdracht is duidelijk een taak voor het JavaScript. Het definiëren van dat nieuwe uiterlijk is een taak voor de CSS. De nieuwe styles van het element (en ook de oude) moeten daarom gedefinieerd worden in het CSS-bestand.
Op die manier blijven presentatie en gedrag gescheiden: JavaScript geeft de opdrachten om stijlen te veranderen, maar het is aan CSS om die stijlen te definiëren.
Laten we naar een praktijkvoorbeeld kijken. Stel je voor dat ik de style
property had
gebruikt in plaats van een class-verandering in Form Validation:
Form Validation, regel 105-6 en 119-120, aangepast
function writeError(obj,message) {
obj.style.border = '1px solid #cc0000';
function removeError() {
this.style.border = '';
Dit werkt natuurlijk prima. Maar stel je voor dat de grafisch ontwerper op een later moment besluit dat de tekst ook rood moet worden. Je zou dan twee regels moeten toevoegen aan je script:
function writeError(obj,message) {
obj.style.border = '1px solid #cc0000';
obj.style.color = '#cc0000';
function removeError() {
this.style.border = '';
this.style.color = '';
Enzovoorts. Iedere extra stijl voor invulvelden met fouten zou twee regels JavaScript vergen. Een script dat gebruikmaakt van class-veranderingen is daarentegen makkelijker te onderhouden, aangezien een extra stijl maar één regel CSS vergt.
Twee regels JavaScript toevoegen kan natuurlijk nauwelijks complex programmeren genoemd worden. Desalniettemin vraagt deze verandering wel de inzet van iemand die goed de weg weet in de JavaScript code. Een grafisch ontwerper/CSS wizard zonder JavaScript-ervaring zou het niet zelf kunnen doen.
CSS-ontwikkelaars die niets van JavaScript weten kunnen wel een stylesheet aanpassen, en dat is een aanzienlijk voordeel in een groter bedrijf, waar het regelmatig gebeurt dat mensen gespecialiseerde functies hebben. Als JavaScriptdeveloper zit je er niet op te wachten dat iedere minieme verandering altijd via jou moet verlopen. Het is daarom ook in je eigen voordeel dat je de complexiteit van de JavaScriptlaag beperkt houdt.
Er zijn dus een aantal redenen waarom ik geloof dat een class-verandering over het algemeen beter is dan
een verandering aan de style
property. Maar zoals altijd zijn er uitzonderingen die de regel
bevestigen. De twee belangrijkste zijn eenvoudige show/hide scripts
en animaties.
NOOT: Einde van deze voorpublicatie. Het hoofdstuk in het boek gaat verder met het bespreken van show/hide scripts, animaties en het zoeken van de afmetingen en positie van HTML-elementen.
Dit artikel is een gedeelte uit hoofdstuk 9 van 'ppk on JavaScript' door Peter-Paul Koch.
Copyright 2007. Gepubliceerd met toestemming van Pearson Education, Inc. en New Riders.
Vertaling: Marrije Schaake
woont zijn hele leven al in Amsterdam. Peter-Paul (mét streepje) is een freelance web developer — je kunt hem dus inhuren — en specialiseert zich in client side programming - HTML, CSS en JavaScript, met de nadruk op dat laatste. Daarnaast schrijft hij veel, klust hij wat bij in werving & selectie en geeft hij zo regelmatig CSS- en JavaScript-cursussen. 'ppk on JavaScript' is zijn eerste boek.
Publicatiedatum: 31 oktober 2006
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