An important aspect of the DOM standard supported by today’s browsers is CSS. DOM Level 2 adds support to manipulate CSS values. DHTML object models, notably Microsoft’s, support similar facilities, and, because of the lack of complete DOM Level 2 support in Internet Explorer, these capabilities are also mentioned here.
The primary way that developers modify CSS values with JavaScript is through the style property that corresponds to the inline style sheet specification for a particular HTML element. For example, if you have a paragraph like this,
<<p id="myParagraph">>This is a test<</p>>
you could insert an inline style like this:
<<p id="myParagraph" style="color: red;">>This is a test<</p>>
To perform a manipulation with JavaScript DOM interfaces, you would use a script like this:
theElement = document.getElementById("myParagraph"); theElement.style.color = "green";
As with (X)HTML manipulations, the key concern is how to map the various CSS property names to DOM property names. In the case of CSS, you often have a hyphenated property name like background-color, which under JavaScript becomes backgroundColor. In general, hyphenated CSS properties are represented as a single word with camel-back capitalization in the DOM. This rule holds for all CSS properties except for float, which becomes cssFloat because “float” is a JavaScript reserved word. A list of the commonly used CSS1 and CSS2 properties with their corresponding DOM properties is shown in Table 10-6 for reference.
CSS Property |
DOM Level 2 Property |
---|---|
background |
background |
background-attachment |
backgroundAttachment |
background-color |
backgroundColor |
background-image |
backgroundImage |
background-position |
backgroundPosition |
background-repeat |
backgroundRepeat |
border |
border |
border-color |
borderColor |
border-style |
borderStyle |
border-top |
borderTop |
border-right |
borderRight |
border-left |
borderLeft |
border-bottom |
borderBottom |
border-top-color |
borderTopColor |
border-right-color |
borderRightColor |
border-bottom-color |
borderBottomColor |
border-left-color |
borderLeftColor |
border-top-style |
borderTopStyle |
border-right-style |
borderRightStyle |
border-bottom-style |
borderBottomStyle |
border-left-style |
borderLeftStyle |
border-top-width |
borderTopWidth |
border-right-width |
borderRightWidth |
border-bottom-width |
borderBottomWidth |
border-left-width |
borderLeftWidth |
border-width |
borderWidth |
clear |
clear |
Clip |
clip |
color |
color |
display |
display |
float |
cssFloat |
Font |
font |
Font-family |
fontFamily |
Font-size |
fontSize |
Font-style |
fontStyle |
Font-variant |
fontVariant |
Font-weight |
fontWeight |
height |
height |
Left |
left |
letter-spacing |
letterSpacing |
Line-height |
lineHeight |
list-style |
listStyle |
list-style-image |
listStyleImage |
list-style-position |
listStylePosition |
list-style-type |
listStyleType |
margin |
margin |
margin-top |
marginTop |
margin-right |
marginRight |
margin-bottom |
marginBottom |
margin-left |
marginLeft |
overflow |
overflow |
padding |
padding |
padding-top |
paddingTop |
padding-right |
paddingRight |
padding-bottom |
paddingBottom |
padding-left |
paddingLeft |
position |
position |
Text-align |
textAlign |
Text-decoration |
textDecoration |
Text-indent |
textIndent |
Text-transform |
textTransform |
Top |
top |
vertical-align |
verticalAlign |
Visibility |
visibility |
white-space |
whiteSpace |
Width |
width |
word-spacing |
wordSpacing |
z-index |
zIndex |
An example that manipulates many of the common CSS properties is presented here. A sample rendering is shown in Figure 10-5.
<<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">> <<html xmlns="http://www.w3.org/1999/xhtml">> <<head>> <<title>>CSS Inline Rule Scripting<</title>> <<meta http-equiv="content-type" content="text/html; charset=utf-8" />> <</head>> <<body>> <<div id="test">> CSS Rules in Action <</div>> <<hr />> <<script type="text/javascript">> <<!-- theElement = document.getElementById("test"); //-->> <</script>> <<form id="cssForm" name="cssForm" action="#" method="get">> <<strong>>Alignment:<</strong>> <<select onchange="theElement.style.textAlign=this.options[this.selectedIndex].text;">> <<option>>left<</option>> <<option>>center<</option>> <<option>>right<</option>> <<option>>justify<</option>> <</select>> <<br />><<br />> <<strong>>Font:<</strong>> <<select onchange="theElement.style.fontFamily=this.options[this.selectedIndex].text;">> <<option>>sans-serif<</option>> <<option selected="selected">>serif<</option>> <<option>>cursive<</option>> <<option>>fantasy<</option>> <<option>>monospace<</option>> <</select>> <<input type="text" id="font" name="font" size="10" value="Impact" />> <<input type="button" value="set" onclick="theElement.style.fontFamily = document.cssForm.font.value;" />> <<br />><<br />> <<strong>>Style:<</strong>> <<select onchange="theElement.style.fontStyle=this.options[this.selectedIndex].text;">> <<option>>normal<</option>> <<option>>italic<</option>> <<option>>oblique<</option>> <</select>> <<strong>>Weight:<</strong>> <<select onchange="theElement.style.fontWeight=this.options[this.selectedIndex].text;">> <<option>>normal<</option>> <<option>>bolder<</option>> <<option>>lighter<</option>> <</select>> <<strong>>Variant:<</strong>> <<select onchange="theElement.style.fontVariant=this.options[this.selectedIndex].text;">> <<option>>normal<</option>> <<option>>small-caps<</option>> <</select>> <<br />><<br />> <<strong>>Text Decoration<</strong>> <<select onchange="theElement.style.textDecoration=this.options[this.selectedIndex].text;">> <<option>>none<</option>> <<option>>overline<</option>> <<option>>underline<</option>> <<option>>line-through<</option>> <<option>>blink<</option>> <</select>> <<br />><<br />> <<strong>>Font Size:<</strong>> <<select onchange="theElement.style.fontSize=this.options[this.selectedIndex].text;">> <<option>>xx-small<</option>> <<option>>x-small<</option>> <<option selected="selected">>small<</option>> <<option>>medium<</option>> <<option>>large<</option>> <<option>>x-large<</option>> <<option>>xx-large<</option>> <</select>> <<input type="text" id="size" name="size" size="3" maxlength="3" value="36pt" />> <<input type="button" value="set" onclick="theElement.style.fontSize = document.cssForm.size.value;" />> <<br />><<br />> <<strong>>Color:<</strong>> <<input type="text" id="fgColor" name="fgColor" size="8" value="yellow" />> <<input type="button" value="set" onclick="theElement.style.color = document.cssForm.fgColor.value;" />> <<br />><<br />> <<strong>>Background Color:<</strong>> <<input type="text" id="bgColor" name="bgColor" size="8" value="red" />> <<input type="button" value="set" onclick="theElement.style.backgroundColor = document.cssForm.bgColor.value;" />> <<br />><<br />> <<strong>>Borders:<</strong>> <<select onchange="theElement.style.borderStyle=this.options[this.selectedIndex].text;">> <<option>>none<</option>> <<option>>dotted<</option>> <<option>>dashed<</option>> <<option>>solid<</option>> <<option>>double<</option>> <<option>>groove<</option>> <<option>>ridge<</option>> <<option>>inset<</option>> <<option>>outset<</option>> <</select>> <<br />><<br />> <<strong>>Height:<</strong>> <<input type="text" id="height" name="height" value="100px" size="3" />> <<strong>>Width:<</strong>> <<input type="text" id="width" name="width" value="100px" size="3" />> <<input type="button" value="set" onclick="theElement.style.height = document.cssForm.height.value; theElement.style.width = document.cssForm.width.value;" />> <<br />><<br />> <<strong>>Top:<</strong>> <<input type="text" id="top" name="top" value="100px" size="3" />> <<strong>>Left:<</strong>> <<input type="text" id="left" name="left" value="100px" size="3" />> <<input type="button" value="Set" onclick="theElement.style.position='absolute';theElement.style.top = document.cssForm.top.value; theElement.style.left = document.cssForm.left.value;" />> <<br />><<br />> <<strong>>Visibility<</strong>> <<input type="button" value="show" onclick="theElement.style.visibility='visible';" />> <<input type="button" value="hide" onclick="theElement.style.visibility='hidden';" />> <</form>> <<hr />> <</body>> <</html>>
Manipulating style in the fashion of the previous section works only on a single tag at a time. This section explores how you might manipulate style rules in a more complex manner. First, consider the use of CSS class selectors. You might have a style sheet with two class rules like this:
<<style type="text/css">> <<!-- .look1 {color: black; background-color: yellow; font-style: normal;} .look2 {background-color: orange; font-style: italic;} -->> <</style>>
We might then apply one class to a particular <<p>> tag, like so:
<<p id="myP1" class="look1">>This is a test<</p>>
You could then manipulate the appearance of this paragraph by using JavaScript statements to change the element’s class. The element’s class attribute is exposed in its className property:
theElement = document.getElementById("myP1"); theElement.className = "look2";
The following example shows a simple rollover effect using such DOM techniques:
<<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">> <<html xmlns="http://www.w3.org/1999/xhtml">> <<head>> <<title>>Class Warfare<</title>> <<meta http-equiv="content-type" content="text/html; charset=utf-8" />> <<style type="text/css">> <<!-- body {background-color: white; color: black;} .style1 {color: blue; font-weight: bold;} .style2 {background-color: yellow; color: red; text-decoration: underline;} .style3 {color: red; font-size: 300%;} -->> <</style>> <</head>> <<body>> <<p class="style1" onmouseover="this.className='style2';" onmouseout="this.className = 'style1';">>Roll over me<</p>> <<p>>How about <<span class="style2" onmouseover="this.className='style1';" onmouseout="this.className= 'style2';">>me<</span>>?<</p>> <<p>> Be careful as dramatic style changes may <<span class="style1" onmouseover="this.className = 'style3';" onmouseout="this.className = 'style1';">>reflow a document<</span>> significantly<</p>> <</body>> <</html>>
Another way to perform manipulations is by using the getElementsByTagName() method and performing style changes on each of the individual elements returned. The following example illustrates this technique by allowing the user to dynamically set the alignment of the paragraphs in the document.
<<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">> <<html xmlns="http://www.w3.org/1999/xhtml">> <<head>> <<title>>Change Style On All Paragraphs<</title>> <<meta http-equiv="content-type" content="text/html; charset=utf-8" />> <</head>> <<body>> <<p>>This is a paragraph<</p>> <<p>>This is a paragraph<</p>> <<div>>This is not a paragraph<</div>> <<p>>This is a paragraph<</p>> <<script type="text/javascript">> <<!-- function alignAll(alignment) { var allparagraphs = document.body.getElementsByTagName('p'); for (var i = 0; i << allparagraphs.length; i++) allparagraphs.item(i).style.textAlign = alignment; } //-->> <</script>> <<form action="#" method="get">> <<input type="button" value="left align all paragraphs" onclick="alignAll('left');" />> <<input type="button" value="center all paragraphs" onclick="alignAll('center');" />> <<input type="button" value="right align all paragraphs" onclick="alignAll('right');" />> <</form>> <</body>> <</html>>
It might seem cumbersome to have to iterate through a group of elements, particularly when you might have set different rules on each. If you are a CSS maven, you may prefer instead to manipulate complex rule sets found in a document-wide or even external style sheet.
So far, we haven’t discussed how to access CSS rules found in <<style>> tags or how to dynamically set linked style sheets. The DOM Level 2 does provide such an interface, but, as of the time of this writing, browser support is still limited and can be very buggy where it does exist. This section serves only as a brief introduction to some of the more advanced DOM Level 2 bindings for CSS.
Under DOM Level 2, the Document object supports the styleSheets[] collection, which we can use to access the various <<style>> and <<link>> tags within a document. Thus,
var firstStyleSheet = document.styleSheets[0];
or
var firstStyleSheet = document.styleSheets.item(0);
retrieves an object that corresponds to the first <<style>> element in the HTML. Its properties correspond to HTML attributes just as have the other correspondences we’ve seen. The most common properties are shown in Table 10-7.
Property |
Description |
---|---|
type |
Indicates the type of the style sheet, generally “text/css.” Read-only. |
disabled |
A Boolean value indicating if the style sheet is disabled or not. This is settable. |
href |
Holds the href value of the style sheet. Not normally modifiable except under Internet Explorer, where you can dynamically swap linked style sheets. |
title |
Holds the value of the title attribute for the element. |
media |
Holds a list of the media settings for the style sheet, for example, “screen.” |
Note |
Under the DOM, when a style is externally linked, you cannot modify its rules nor can you change the reference to the linked style sheet to an alternative value. However, you may override them with local rules. |
Under the DOM, the CSSStyleSheet object inherits the StyleSheet object’s features and then adds the collection cssRules[] that contains the various rules in the style block as well as the insertRule() and deleteRule() methods. The syntax for insertRule() is theStyleSheet.insertRule('ruletext', index), where ruletext is a string containing the style sheet selector and rules and index is the position to insert it in the set of rules. The position is relevant because, of course, these are Cascading Style Sheets. Similarly, the deleteRule() method takes an index value and deletes the corresponding rule, so theStyleSheet.deleteRule(0) would delete the first rule in the style sheet represented by theStyleSheet. Unfortunately, at the time of this writing, Internet Explorer doesn’t support these DOM facilities and instead relies on the similar addRule() and removeRule() methods for its styleSheet object.
Accessing individual rules is possible through the cssRules[] collection or, in Internet Explorer, the nonstandard rules[] collection. Once a rule is accessed, you can access its selectorText property to examine the rule selector, or you can access the style property to access the actual set of rules. While the DOM Level 2 provides various methods, such as getPropertyValue() and setProperty(), to modify rules, it is generally far safer to simply access the style object and then the DOM property corresponding to the CSS property in question. For example, theStyleSheet.cssRules[0].style.color = 'blue' would modify (or add) a property to the first CSS rule in the style sheet. Under Internet Explorer, you would use theStyleSheet.rules[0].style.color = 'blue'. The following script demonstrates the basics of style sheet rule manipulation:
<<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">> <<html xmlns="http://www.w3.org/1999/xhtml">> <<head>> <<title>>Style Rule Changes<</title>> <<meta http-equiv="content-type" content="text/html; charset=utf-8" />> <<style type="text/css" id="style1">> <<!-- h1 {color: red; font-size: 24pt; font-style: italic; font-family: Impact;} p {color: blue; font-size: 12pt; font-family: Arial;} body {background-color: white;} strong {color: red;} em {font-weight: bold; font-style: normal; text-decoration: underline;} -->> <</style>> <</head>> <<body>> <<h1>>CSS Test Document<</h1>> <<hr />> <<p>>This is a <<strong>>test<</strong>> paragraph.<</p>> <<p>>More <<em>>fake<</em>> text goes here.<</p>> <<p>>All done. Don't need to <<strong>>continue this<</strong>><</p>> <<hr />> <<h3>>End of Test Document<</h3>> <<script type="text/javascript">> <<!-- var styleSheet = document.styleSheets[0]; function modifyRule() { if (styleSheet.rules) styleSheet.cssRules = styleSheet.rules; if (styleSheet.cssRules[0]) { styleSheet.cssRules[0].style.color='purple'; styleSheet.cssRules[0].style.fontSize = '36pt'; styleSheet.cssRules[0].style.backgroundColor = 'yellow'; } } function deleteRule() { if (styleSheet.rules) styleSheet.cssRules = styleSheet.rules; if (styleSheet.cssRules.length >> 0) // still rules left { if (styleSheet.removeRule) styleSheet.removeRule(0); else if (styleSheet.deleteRule) styleSheet.deleteRule(0); } } function addRule() { if (styleSheet.addRule) styleSheet.addRule("h3", "color:blue", 0); else if (styleSheet.insertRule) styleSheet.insertRule("h3 {color: blue}", 0);} } //-->> <</script>> <<form action="#" method="get">> <<input type="button" value="Enable" onclick="document.styleSheets[0].disabled=false;" />> <<input type="button" value="Disable" onclick="document.styleSheets[0].disabled=true;" />> <<input type="button" value="Modify Rule" onclick="modifyRule();" />> <<input type="button" value="Delete Rule" onclick="deleteRule();" />> <<input type="button" value="Add Rule" onclick="addRule();" />> <</form>> <</body>> <</html>>
There are a few things to study carefully in the previous example. First, notice how we use conditional statements to detect the existence of particular objects, such as Internet Explorer proprietary collections and methods. Second, notice how in the case of rules[] versus cssRules[], we add the collection to simulate correct DOM syntax under Internet Explorer. Last, notice how if statements are used to make sure that there are still rules to manipulate. You can never be too sure that some designer hasn’t changed the rules on you, so code defensively!
Note |
You may find that this example does not work well under some browsers. It also may suffer refresh problems because rule-removal may not necessarily be reflected automatically. If you enable or disable rules or refresh a document, you may notice changes. |