JavaScript tutorial - DOM CSS

Navigation

Skip navigation.

Site search

Site navigation

JavaScript tutorial

Printing

Other tutorials

DOM CSS

Individual element styles

As described in the section on DHTML, DOM compatible browsers support the style object. The style object was created by Microsoft and although only became a standard in DOM Level 2 CSS, there was nothing to replace it in browsers supporting earlier DOM implementations, so it has been universally adopted by all DOM browsers. Through the style object, DOM browsers allow all styles the element accepts to be changed, not just those I described in the section on DHTML. It is equivalent to reading and writing the value of the style attribute, so styles can only be read if they were set using that attribute. Styles are almost all read/write.

The syntax is simple. Simply write element.style.styleName. If the style name consists of two or more words separated by hyphens '-', remove the hyphen and capitalise the first letter of the word following it. For example, background-color becomes backgroundColor. When setting a value, it should be set as a string. Other data types will be converted to strings before setting the value to that string. Although most browsers will allow you to delete a style by setting it to null, a browser could legitimately set it to the string value 'null', and that would have an unwanted effect. If you want to delete a style, set it to an empty string, and never set it to null.

The only odd style is float, which is a reserved word in many languages, including JavaScript. As a result, the float style must be set using cssFloat in standards compliant browsers, and styleFloat in Internet Explorer 8- and 9+ in quirks mode (some standards compliant browsers also provide this as well). Simply set both of them. It will not cause any problems, and will work in all possible browsers.

The W3C DOM does provide an alternative way to change the styles on individual elements. The class attribute of the element can be removed using this:

element.className = '';

And it can be changed using:

element.className = 'newClassName';

Reading applied element styles

When CSS stylesheets are applied to a page, elements may be targetted by several style rules, and inherit various styles from their ancestors. They will also receive some default styling from the browser's internal stylesheet. The DOM specification offers a way to work out what the result of those styles was, using the window.getComputedStyle method. This is supported by Opera 7+, Mozilla, iCab 3+, Konqueror 3.5+, and Chrome/Safari 3+, as well as Internet Explorer 9+ in standards mode. Internet Explorer also offers an alternative that also works in quirks mode; the currentStyle property of an element. This is supported by Internet Explorer on Windows and Mac, Opera 9+ and iCab 3.

getComputedStyle requires two parameters. The first is a reference to the element. The second is either the name of a pseudo element (':before', ':after', ':first-line'), or null just for the element itself. Since currentStyle only allows you to obtain the style for the element itself, that is all I will show here. In most cases, the values returned by these are the same, but there are a few cases where they may be different. For example, a table may have a width set by the CSS, but may be stretched wider to fit its contents. In this case currentStyle will still return the width specified by the CSS, but getComputedStyle will return the new stretched width.

var oElement = document.getElementById('mydiv'), oColor;
if( window.getComputedStyle ) {
  oColor = window.getComputedStyle(oElement,null).color;
} else if( oElement.currentStyle ) {
  oColor = oElement.currentStyle.color;
}

As well as being an actual usable value, the returned value for several styles may be their default values, such as 'auto', 'normal', or 'inherit'. The browser may also choose to return values in any available unit. For example, even if the CSS specifies a length in 'em' units, the browser may still return the equivalent value in 'px' units.

In cases where currentStyle gives a different result to getComputedStyle, Internet Explorer offers an alternative; runtimeStyle. This is an object almost exactly like currentStyle, but it gives a computed value instead of a cascaded value. However, it does not always give a usable value, and often gives a different kind of result to what would be expected from getComputedStyle, if it gives any value at all. It often computes a blank string for unspecified values, instead of their default values. Use this with care and only if you are sure it gives the result you need.

It is also possible to obtain some details of an element using its offset, client, and scroll values. These are all available as properties of the element, and give its current dimensions in pixels, not the styles that apply to it. This means that they also give real dimensions, even if the CSS value is 'auto'. These are not reliable for inline elements, and should only be used for elements that have block or equivalent display. Note that these properties were not standardised for a long time (they will be part of future DOM standards), but they work fairly reliably cross browser.

offsetWidth and offsetHeight
The dimensions of the element taken outside its border. (The width inside the padding in IE's quirks mode.)
clientWidth and clientHeight
The dimensions of the element taken inside its border, and minus any scrollbar size.
scrollWidth and scrollHeight
The dimensions the element would be using if it did not have a scrollbar and was not constrained in size (in other words, the dimensions of its contents, plus its padding). Only usable and reliable if the element actually has a scrollbar.
scrollLeft and scrollTop
The distance the element has been scrolled.

Rewriting stylesheets

The DOM allows the stylesheets themselves to be changed. Some browsers allow stylesheets to be modified, some also allow rules to be created or removed. This will be covered in the next chapter of this tutorial.

Changing the href of a linked stylesheet

The href of the stylesheet can be read in some browsers using the href property. Opera 7+, Mozilla, Konqueror, Safari/Chrome and Internet Explorer 5+ can set the href of the link element using setAttribute on the link tag, and Internet Explorer 4+ can also set the href of the styleSheets[index].

Switching stylesheets

The stylesheet can be disabled/enabled in some browsers using the boolean disabled property, but some browsers will only allow you to change the disabled property if the title attribute is set. To create the most reliable cross browser effect, the function I have written (below) will only try to enable / disable a stylesheet if its title attribute has been set.

The best use of the disabled property is to allow your readers to change the look of the site to suit their personal tastes or accessibility requirements. This requires them to be able to switch between the different stylesheets that you provide. Most often, this technique is used along with cookies, storing the user's preference of stylesheet as they leave the page (via the onunload event) and then using it again next time they view the page (using the onload event).

Setting up the HTML

To do this, set out your document as follows:
Firstly, if you need one, create a persistent stylesheet with all global styles, using this:

<link rel="stylesheet" type="text/css" href="all.css">

As it has no title attribute, it will never be disabled. You do not have to define this stylesheet if you do not want to, but if you do, remember that all styles you define in it will be used in all stylesheet modes, and will be used along with any stylesheet you later use by stylesheet switching.

The default switchable (preferred) stylesheet is set up using this:

<link rel="stylesheet" type="text/css" href="default.css" title="Default">

This will also be used by browsers that cannot disable/enable stylesheets and ensures that the default view will look good. You can then set up all alternative stylesheets using this:

<link rel="alternate stylesheet" type="text/css" href="extraPretty.css" title="Pretty">
<link rel="alternate stylesheet" type="text/css" href="bigFont.css" title="Big Font">
<link rel="alternate stylesheet" type="text/css" href="contrast.css" title="High Contrast">

Because these stylesheets are set up using 'alternate stylesheet' for the 'rel' attribute, lesser browsers will not use these stylesheets at all, and in browsers that can switch stylesheets, these stylesheets will be disabled by default.

Changing the stylesheets with the browsers' view menu

Opera 7+, Mozilla, Internet Explorer 8+, Konqueror 3+ and iCab 3+ will allow users to choose from these alternative stylesheets in the 'view' menu. However, this setting is not remembered by the browser (except by Konqueror), so the user will have to choose this for every page they view on your site. Also, other 'good' browsers, like Internet Explorer 7- and Safari/Chrome do not allow the user to choose stylesheets in any menus, so you will have to use the DOM to change them manually. Note that when using the view menu or the DOM technique, stylesheets that share the same title will be treated as if they were the same stylesheet and will be switched together.

Using the view menu only allows you to select stylesheets whose titles are identical. If you want to enable combinations, you would either have to produce combined stylesheets or include the same sheet multiple times with different titles to allow all combinations. This is also a problem with most basic stylesheet switching scripts. The script I will show you allows you to choose a combination of stylesheet titles, making it superior to most other scripts.

Referencing the stylesheet's disabled property and title property

document.stylesheets

Microsoft first came up with the document.styleSheets collection. The W3C decided this was a good idea and introduced it in DOM Level 2 CSS. All stylesheets are available in this collection, even if the rel attribute is set to 'alternate stylesheet'. Setting the disabled property of the collection entry disables and enables the stylesheet, and the title attribute is available here as a JavaScript property.

Referencing the tags

The equivalent to document.styleSheets can be produced by referencing the relevant LINK and STYLE tags. The disabled property can be read and modified, and the title attribute is available. You will need to make sure that the link tags are being used to import stylesheets by checking their 'rel' attribute as link tags have many uses.

You can see that from these points, the following is required:

The W3C says the correct method is to use the styleSheets collection, but since that would only work in three browsers, and cause problems for others, I will use the link and style tag technique. I will add support for ICEbrowser, just in case they ever fix its handling, or in case you only want to switch preferred stylesheets.

The best way to check if the user has used the view menu is to check what stylesheets are enabled onload and onunload. If they are different, the user has chosen something from their view menu (this is not possible in Opera 7-8, as the disabled property does not reflect changes made in the view menu). Of course, you should also check if the changeStyle function has been run by making it store a variable to say so.

You may want to use the correct technique, but if you do, you will still need to do the link and style tag technique for Opera 7-8 and iCab (using if(!document.styleSheets) etc.), and you will need to do a browser detect to make KHTML/WebKit use the link and style tag technique, and you will still need to make sure you do not store the preference in KHTML/WebKit, iCab and Opera 7-8 until the user has chosen, and you will need to compensate for the lack of title in IE 4 Mac.

The script

Note, because getElementsByTagName returns an object with element 'index' and 'length' properties, and not a true collection, we cannot use the array.concat method to append the 'arrays' of link tags and style tags. Instead, we must cycle through the collections and add each element in turn.

function getAllSheets() {
  //if you want ICEbrowser's limited support, do it this way
  if( !window.ScriptEngine && navigator.__ice_version ) {
  	//IE errors if it sees navigator.__ice_version when a window is closing
  	//window.ScriptEngine hides it from that
    return document.styleSheets; }
  if( document.getElementsByTagName ) {
    //DOM browsers - get link and style tags
    var Lt = document.getElementsByTagName('link');
    var St = document.getElementsByTagName('style');
  } else if( document.styleSheets && document.all ) {
    //not all browsers that supply document.all supply document.all.tags
    //but those that do and can switch stylesheets will also provide
    //document.styleSheets (checking for document.all.tags produces errors
    //in IE [WHY?!], even though it does actually support it)
    var Lt = document.all.tags('LINK'), St = document.all.tags('STYLE');
  } else { return []; } //lesser browser - return a blank array
  //for all link tags ...
  for( var x = 0, os = []; Lt[x]; x++ ) {
    //check for the rel attribute to see if it contains 'style'
    if( Lt[x].rel ) { var rel = Lt[x].rel;
    } else if( Lt[x].getAttribute ) { var rel = Lt[x].getAttribute('rel');
    } else { var rel = ''; }
    if( typeof( rel ) == 'string' && rel.toLowerCase().indexOf('style') + 1 ) {
      //fill os with linked stylesheets
      os[os.length] = Lt[x];
    }
  }
  //include all style tags too and return the array
  for( var x = 0; St[x]; x++ ) { os[os.length] = St[x]; } return os;
}
function changeStyle() {
  for( var x = 0, ss = getAllSheets(); ss[x]; x++ ) {
    //for each stylesheet ...
    if( ss[x].title ) {
      //disable the stylesheet if it is switchable
      ss[x].disabled = true;
    }
    for( var y = 0; y < arguments.length; y++ ) {
      //check each title ...
      if( ss[x].title == arguments[y] ) {
        //and re-enable the stylesheet if it has a chosen title
        ss[x].disabled = false;
      }
    }
  }
  if( !ss.length ) { alert( 'Your browser cannot change stylesheets' ); }
}

...

eg.
<body onload="changeStyle('High Contrast','Big Font');">

Reduced, that becomes this:

function getAllSheets() {
  if( !window.ScriptEngine && navigator.__ice_version ) { return document.styleSheets; }
  if( document.getElementsByTagName ) { var Lt = document.getElementsByTagName('link'), St = document.getElementsByTagName('style');
  } else if( document.styleSheets && document.all ) { var Lt = document.all.tags('LINK'), St = document.all.tags('STYLE');
  } else { return []; } for( var x = 0, os = []; Lt[x]; x++ ) {
    var rel = Lt[x].rel ? Lt[x].rel : Lt[x].getAttribute ? Lt[x].getAttribute('rel') : '';
    if( typeof( rel ) == 'string' && rel.toLowerCase().indexOf('style') + 1 ) { os[os.length] = Lt[x]; }
  } for( var x = 0; St[x]; x++ ) { os[os.length] = St[x]; } return os;
}
function changeStyle() {
  for( var x = 0, ss = getAllSheets(); ss[x]; x++ ) {
    if( ss[x].title ) { ss[x].disabled = true; }
    for( var y = 0; y < arguments.length; y++ ) {
     if( ss[x].title == arguments[y] ) { ss[x].disabled = false; }
} } }

Test it using the stylesheet switcher demo page.

See my stylesheet switching header file for a working example that can store the user's choice of stylesheet, even if they use the view menu in Gecko.

Last modified: 19 March 2011

  1. Previous
  2. Next
This site was created by Mark "Tarquin" Wilton-Jones.
Don't click this link unless you want to be banned from our site.