Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

Modifying Styles

Older browsers, such as Netscape’s Navigator 4 series, had relatively poor support for modifying Cascading Stylesheets from JavaScript—instead requiring that you use either document.write() calls to rewrite the contents of a particular element or their equally burdensome (and Navigator-only) Javascript Stylesheets mechanism.

With the release of W3 compliant browsers however, we now have the ability to change styles on the fly from JavaScript, using the W3C DOM. Unfortunately, due to a distinction between the way that embedded and remote stylesheet properties are exposed as opposed to the way that inline STYLE properties are exposed, this can be tricky. In effect, developers are required to define all styles inline or in embedded stylesheets (whether internal or external) if they want to be able to read and modify them reliably. Despite the fact that stylesheets are far easier to work with, may be reused across pages, and may be designed by someone with no JavaScript knowledge, browser vendors recommend that dynamic changes be made via the JavaScript .style property directly.

For example, given the following embedded stylesheet declaration:

<style type="text/css">
H1 {
  font-family: Arial;
  font-size: 12pt;
}
</style>

You can read the properties from JavaScript as follows (note that the CSS properties themselves are camelCased rather than hyphenated):

<script type="text/javascript">
var myStyle = document.styleSheets[0].cssRules[0].style;
var fFamily = myStyle.fontFamily;
var fSize = myStyle.fontSize;
alert("H1 stylesheet:\nfamily: "
  + fFamily + "\nsize: " + fSize);
</script>

However, given the following inline style attribute on a particular H1, you need to use a different interface to read the properties:

<h1 style="font-family: Palatino;
  font-size: 14pt;">example</h1>
<script type="text/javascript">
var myH1Array = document.getElementsByTagName("H1");
var myElem = myH1Array.item(0);
var myStyle = myElem.style;
var fFamily = myStyle.fontFamily;
var fSize = myStyle.fontSize;
alert("H1 Inline:\nfamily: "
  + fFamily + "\nsize: " + fSize);
</script>

If you use the former method to read the style properties for H1, but have declared them inline as in the latter example, you get the wrong values—those defined in the embedded stylesheet, not those defined in the inline style attribute. Obviously, the problem can be resolved for named elements by reading the style properties for the element in question:

<h1 id="example"
  style="font-family: Palatino;
    font-size: 18pt;">example</h1>
<script type="text/javascript">
var myElem = document.getElementById("example");
var myStyle = myElem.style;
var fFamily = myStyle.fontFamily;
var fSize = myStyle.fontSize;
alert("H1 with ID `example':\nfamily: "
  + fFamily + "\nsize: " + fSize);
</script>

If the element in question doesn’t use inline style attributes, you get empty or null values, rather than the embedded stylesheet properties you’re after.

In essence, although the browser knows how to properly override global stylesheet declarations when rendering the element, there is no single built-in cross-browser way to access the style being used for that rendering. Internet Explorer has (in the 5.x generation) introduced the currentStyle and runtimeStyle collections, but they’re not W3 standard, and runtimeStyle doesn’t seem to be supported in Internet Explorer 5.0 for the Macintosh.

If you want to change an element’s style, a similar problem exists. If you only modify the global stylesheet for an element type for which inline styles are defined, only those elements without inline styles are changed. This may be viewed as a feature or a weakness, depending on your point of view, your particular application, and the lateness of the hour or proximity of the deadline.

There is a standard way to read the current style properties for any element, the getComputedStyle() method, but it is not yet supported on the Macintosh platform. Internet Explorer does support the currentStyle collection, which is a proprietary implementation of the method, but Navigator 6 does not yet appear to support either method reliably, if at all.

Fortunately, there is a way to read and change an element’s styles regardless of where they were originally defined. As you might expect, it entails checking all the available stylesheet properties in both embedded styles and inline STYLE attributes. I’ve provided a script that will take some of the pain out of doing so.

The Script’s Purpose

As demonstrated above, with the increased power of the newer browsers come some compromises in ease of use for the developer. More importantly, as more and more applications are being jointly produced by developers and designers working in tandem (and sometimes without perfect communication between those implementing behavior and those implementing the look and feel) it’s important to preserve flexibility in the approaches used to apply and modify style. This script helps the developer do just that.

Why would you want to modify styles on the fly? As Web applications become more and more powerful, users are demanding more flexibility and control over their personal preferences, just as they are used to having in traditional desktop applications. For instance, some users may like reading body copy in serif fonts, while others may enjoy sans-serif. Or source code listings, like those in this article, might be too small to read, so you’d want the user to be able to modify them at will. Of course, there are literally thousands of different applications for these capabilities—I’m just pointing out some that are convenient in the context of this article.

Using the Script

The script contains several functions, discussed in detail below. The first three functions set styles, allowing you to discriminate between elements based on their ID, their CLASS, or their tag name. The second set of functions simply allows you to get the current style settings for each element.

The simplest of these is setStyleById(), which takes an element ID, a CSS property, and a value, and sets that element’s property to that value.

setStyleById(ID, property, value)

The second function takes a tag name (e.g., H1), a class name, a CSS property, and a value, and sets the style for all elements of that type (or for all elements, if passed the “*” specifier).

setStyleByClass(type, class, property, value)

The third function takes a tag name (e.g., H1), a CSS property, a value, and the final (and optional) Boolean argument, which specifies whether to modify the style for that element in the stylesheet or in the .style array of the element. Unfortunately, due to the lack of a functional selectorText property in Netscape6/Mozilla, the stylesheet mode of the function does not work.

setStyleByTag(tagname, property, value, global)

The second set of functions allows you to read the values of any CSS property for any element, based on the element name, ID, or CLASS selector, as above.

getStyleById(ID, property)
getStyleByClass(type, class, property)
getStyleByTag(type, property)

If the property is found, it is returned as a string. If not, the functions return null.

A Demonstration of the Script

Note that because these scripts use advanced DOM functionality, they will not work in any browser previous to the IE5/Netscape6/Mozilla generation. This includes Navigator 4.x, Internet Explorer 4.x, and other, older browsers. To ensure that your site provides for users of those browsers, consider using server-side logic to deliver different content to those browsers.

Simply click on the buttons below to demonstrate the script.













Download Scripts