Team LiB
Previous Section Next Section

The DOM and CSS

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.

Inline Style Manipulation

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.

Table 10-6: CSS Property-to-DOM Property Mappings

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.

Click To expand
Figure 10-5: Rendering of CSS Inline Tester under Mozilla
<<!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=ISO-8859-1" />>
<</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>>

&nbsp;&nbsp;

<<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>>
&nbsp;&nbsp;

<<input type="text" id="size" name="size" size="3" maxlength="3" value="36pt" />> &nbsp;&nbsp;
<<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" />> &nbsp;&nbsp;

<<strong>>Width:<</strong>> 
<<input type="text" id="width" name="width" value="100px" size="3" />> &nbsp;&nbsp;
<<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" />> &nbsp;&nbsp;
<<strong>>Left:<</strong>>
<<input type="text" id="left" name="left" value="100px" size="3" />> &nbsp;&nbsp;
<<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>> &nbsp;&nbsp;
<<input type="button" value="show" onclick="theElement.style.visibility='visible';"
 />>
<<input type="button" value="hide" onclick="theElement.style.visibility='hidden';"
 />>
<</form>>
<<hr />>
<</body>>
<</html>>

Dynamic Style Using Classes and Collections

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=ISO-8859-1" />>
<<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=ISO-8859-1" />>
<</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.

Accessing Complex Style Rules

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.

Table 10-7: Style Object Properties

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=ISO-8859-1" />>
<<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.


Team LiB
Previous Section Next Section