JavaScript tutorial - DOM Style Sheets

Navigation

Skip navigation.

Site search

Site navigation

JavaScript tutorial

Printing

Other tutorials

DOM Style Sheets

DOM Style Sheets allow you to step through the rules of each stylesheet, change the selectors, read and write styles, and add new rules. This allows you to create or change CSS that affects several elements at the same time, instead of just one element as with traditional DHTML. It allows you to take advantage of CSS selectors to target the desired elements, and enter rules into the CSS cascade.

Currently this is supported according to the DOM standard by Opera 9+, Mozilla/Firefox and Internet Explorer 9+ (in standards mode). It is partially supported by Safari, Chrome, Konqueror and ICEbrowser, but their support is so bad it is largely unusable. I will give details of what fails in these browsers for each operation. Supposedly you can use the hasFeature method to check if a browser supports DOM 2 Style Sheets well enough, but unfortunately Safari/Chrome and ICEbrowser return true for the StyleSheets and CSS features. Their support is so poor that this is an insult to the spec. I suggest you ignore Safari/Chrome, Konqueror and ICEbrowser for now, and hope that their support improves in the future.

If you need compatibility with Safari/Chrome, Konqueror, ICEbrowser, or any browser that does not support DOM Style Sheets (like iCab or Opera 8 or below), then you should ensure that your script does not requre document.styleSheets to be supported, and that if it uses it, it does not produce errors when something fails in one of these browsers.

Internet Explorer 8- does not comply with the standard here, so if you are testing, use a browser that supports the standard correctly, such as Opera 9+ or Mozilla. I will give details later on how to get support for Internet Explorer 8- as well. Internet Explorer 9+ only adds support for DOM Style Sheets in standards mode. In quirks mode or IE 7 compatibility mode, only the Internet Explorer model is provided, along with its limitations. Internet Explorer on Mac supports large parts of the Internet Explorer model, but it also provides the cssRules collection, even though it does not use it according to the spec. I recommend you ignore IE Mac, but I will include it in the Internet Explorer section later on in this chapter.

DOM stylesheets does not provide an exact copy of what you put in your stylesheet. It produces what the browser sees, and what it interprets. Rules that it does not understand are not included, whitespace may be added or removed, combined styles may be split into their components, and split styles may be combined. Styles that are not understood will be ignored. Comments will not be included. Do not expect to be able to recognise your own stylesheet.

Note that you should not try using DOM 2 Style Sheets until you are certain that the stylesheet has completed loading (typically this means waiting for the document's onload event to fire). If you attempt to access it before then, the cssRules collection may be too short or may not exist.

The styleSheets list

All stylesheets are available through the document.styleSheets collection. This includes stylesheets added using <style> and <link> tags, including persistent, preferred and alternate stylesheets, no matter if they are enabled or not. Even stylesheets added using style sheet processing instructions in XML based documents should be included. They are available in the collection in the order that they appear in the document source. Imported stylesheets are not included in the list (as they are included through their parent stylesheet), and will be dealt with later. The collection does not include the contents of <div style="etc"> attributes; they must be accessed through the style property of the element (see the section on DHTML for more details).

This provides an easy way to check if a browser supports some amount of DOM Style Sheets, by checking for the existence of the document.styleSheets collection:

if( document.styleSheets ) {
  //DOM stylesheets are available
}

Each stylesheet has a number of properties that give details of the stylesheet, such as its URL (href), its title (title), its type (type, usually 'text/css'), the media types it applies to (media), and if it is disabled or not (disabled). The disabled property can be set to true or false to disable or enable the stylesheet, but the other properties are all read-only. The properties will only be available if they actually apply to the stylesheet in question. For example, if a link element does not have the title attribute set, then its associated StyleSheet object will not have a title.

Test it here: see the properties of the first stylesheet in this document.

Relationships between the StyleSheet object and the HTML tags that create them

If you have a reference to the LINK or STYLE element, you can reference the associated StyleSheet object using the sheet property of the element.

var theSheet = document.getElementsByTagName('style')[0].sheet;

Similarly, if you have a reference to the StyleSheet object, you can reference the associated LINK or STYLE element by using the ownerNode property of the StyleSheet object.

var theElement = document.styleSheets[0].ownerNode;

Test it here: check for these properties.

Stylesheet media

The media property of the stylesheet references a MediaList object. This allows adding and removing of media types. It has a property mediaText that gives the full contents of the LINK or STYLE element's media attribute. Note that browsers are free to add or remove spaces, as they decide is appropriate. They may also remove any media types they do not understand, or may rename them (typically to 'unknown'). If the text contains the same media type more than once, the browser may remove the extra copies. It is possible to set this text to a new string if desired:

document.styleSheets[0].media.mediaText = 'print,handheld';

Modifying the media types that the stylesheet applies to is mostly useful if the browser supports multiple media types. Of the browsers that support DOM stylesheets, only Opera supports more than just screen and print (Opera also supports projection, handheld, speech, and on some devices, tv). This means that currently, this feature is most useful in Opera, but can also be useful in other browsers if you wish to change between 'all', 'screen', and 'print'. Note that the browser may support media queries, and the specification never took these into account. Currently this affects Opera. Opera normalizes media queries (removing spaces and reformatting), to make sure that only one copy of each equivalent query (with parameters in the same order) exists.

If you set the mediaText to a value containing media types the browser does not recognise, it will allow that, and simply ignore unknown media types. Setting the media text to a value that the browser does not recognise as valid syntax will throw an error, so browsers that do not understand media queries will not allow you to set mediaText containing a media query. You will need to use a try...catch statement around the assignment.

The media object also provides the appendMedium method to allow you to append one media type at a time, and the deleteMedium method to delete one at a time. Deleting a medium that is not in the list, or that the browser does not understand, will cause it to throw an error. Note that a stylesheet with no media is applied to all media types. Adding a medium to a stylesheet that has no specified media will cause it to be applied only to that media type. Deleting all media types from the list will cause the media text to be empty, so it will be applied to all media types.

document.styleSheets[0].media.appendMedium('handheld');
document.styleSheets[0].media.deleteMedium('print');

You can also step through all the listed media types using the item method, and check how many are in the list by checking the length parameter.

for( var i = 0; i < document.styleSheets[0].media.length; i++ ) {
  alert(document.styleSheets[0].media.item[i]);
}

Test it here:

Stylesheet cssRules collection

Stylesheets all have the cssRules collection, that contains all the rules of the stylesheet. This only includes rules that are in the root of the stylesheet, and not, for example in a @media block (these will be dealt with later). Browsers may choose not to include @ rules that they do not recognise (initially the spec said to include them, but the authors of the spec have now said not to). They will not include any rules that they do not understand, such as rules using a selector that they do not recognise as being in a valid format. This means that the cssRules collection will almost certainly be a different length in different browsers, and you cannot rely on it being a certain size if you use features that are not supported by all the browsers. Note that although most browsers understand @namespace rules, they are not part of the specification. Only Mozilla adds these to the cssRules collection, as an unknown rule.

Rules can be added to the collection using the insertRule method of the stylesheet, specifying the text to interpret as a new rule, and the index specifying the rule number that the new rule should be added before. To add a rule at the end, the index should be the number of rules currently in the stylesheet. Rules can be removed using the deleteRule method of the stylesheet, specifying the index of the rule to remove. As always, the index starts at 0 for the first rule.

document.styleSheets[0].deleteRule(1); //delete the second rule
document.styleSheets[0].insertRule('html { color: lime; }',0); //add a new rule at the start
var oLength = document.styleSheets[0].cssRules.length;
document.styleSheets[0].insertRule('body { background: #779; }',oLength); //add a new rule at the end
var oRule = document.styleSheets[0].cssRules[oLength]; //reference the new rule we just added

This part of DOM 2 Style Sheets is one of the most useful and important. Since adding and removing rules is not supported by Safari 2- and Konqueror, and only removing rules is supported by ICEbrowser, they are generally useless for DOM 2 Style Sheets.

Test it here: add the new rule 'p { color: lime; }', and then delete it again.

For security reasons, Opera and Mozilla will not allow you to access the cssRules collection of a stylesheet from another domain or protocol. Attempting to access it will throw a security violation error. If your script is likely to encounter a stylesheet like this, you should use a try...catch structure to prevent your script from halting.

The CSS rule

This is the most fundamental part of DOM 2 Style Sheets; viewing or changing the styles of each rule. Each entry in the stylesheet's cssRules object is a CSS rule. There are several types of rule that may exist in a stylesheet, and the properties they provide will depend on what type of rule they are.

Each rule has a type property, saying what type of rule it is. This will be 1 for normal style rules, 2 for @charset rules, 3 for @import rules, 4 for @media rules, 5 for @font-face rules, and 6 for @page rules. If the browser does not ignore unknown @ rules, their type will be 0. CSS rules will also have the parentStyleSheet property, which is a reference to the stylesheet they are inside. Typically, you would need to use the type property to work out what other properties you will be able to access.

The rule also has a cssText property that gives a text representation of the rule. This may have whitespace added or removed, and styles may be split or combined into component styles. Multiple copies of the same style may be replaced with a single copy of the one that is actually used. In most cases, it no longer looks like the rule that was in the original stylesheet, but it should have the same effect in that browser (though not necessarily in other browsers) as the original rule.

var theRule = document.styleSheets[0].cssRules[0];
alert('Type: '+theRule.type+'\nRule: '+theRule.cssText);

Test it here: alert the first rule in the first stylesheet of this page.

In theory it is possible to set the cssText to a new value, as long as the new value can be interpreted as the same type of rule as the original rule (so it is not possible to convert a @import rule into a @media rule, for example). Unfortunately, browser support is not good enough to use this at the moment.

document.styleSheets[0].cssRules[0].cssText = 'body { background: #779; }';

If the rule is a @charset rule, it will have an encoding property, giving the encoding string, which can be rewritten if desired. Unknown @ rules will have no other properties. All other rule types will be covered below:

Normal style, @page, and @font-face rules

These are the most common rule types, and the majority of stylesheets contain only normal style rules. The normal style rule and the @page rule have the selectorText property, which gives the selector text for the rule. This may have whitespace added or removed. In theory, this can be rewritten if desired, but unfortunately, browser support is not good enough to use this at the moment.

document.styleSheets[0].cssRules[7].selectorText = 'div > p';

All three rule types also have a style property. This is the same in functionality as the style property of elements that is normally used for DHTML. However, browsers that support DOM 2 Style Sheets usually implement more of the less well known methods associated with the style object. As well as the usual .style.color syntax that is well known (and even works in Safari and Konqueror), there are several other ways to access and modify the styles of the rule:

The cssText property gives the text representation of all the styles that the rule contains. This may be reformatted with altered whitespace, may or may not have a final semicolon, and styles may or may not be split or combined. It is possible to set this to a new value, replacing all the original styles with a new set of styles.

document.styleSheets[0].cssRules[7].style.cssText = 'color: lime; font-weight: bold;';

The length property can be used to find how many styles the browser sees, and the item method can be used to retrieve the style names one at a time. The getPropertyValue method retrieves the value of a named style. The getPropertyPriority method retrieves the priority of a named style (typically 'important'). The removeProperty method removes a named style (it will do nothing if the style is not being used). Lastly, the setProperty method creates or rewrites a style. It requires three parameters; the style name, the value, and the priority.

var oStyle = document.styleSheets[0].cssRules[0].style;
oStyle.setProperty('color','lime','');
oStyle.setProperty('font-weight','bold','important');
for( var i = 0, j, s = ''; i < oStyle.length; i++ ) {
  j = oStyle.item(i);
  s += j + ' = '+oStyle.getPropertyValue(j)+' '+oStyle.getPropertyPriority(j)+'\n';
}
alert(s);
oStyle.removeProperty('color');
oStyle.removeProperty('font-weight');
alert('New content: '+oStyle.cssText);

Test it here: the last rule in the demo stylesheet is currently 'p { }'. Try running the script shown above on it.

@import rules and imported stylesheets

@import rules are similar to a HTML LINK element, in that they reference a new stylesheet. They have some extra properties that reflect that role.

The href property gives the URL referred to by the import rule. This may be a complete address (typically beginning with 'http://'), or may be the exact URL given by the @import rule (such as 'imported.css') - this will depend on the browser.

@import rules can contain a list of media types as well, although this feature is not very often used. As a result, the rule object also has the media property, which behaves exactly like the media property of the StyleSheet.

Most importantly, the rule object also has the styleSheet object. This references the StyleSheet object for the imported stylesheet, and its rules can be referenced and modified in exactly the same way as a normal stylesheet. The imported stylesheet also has the ownerRule property that references the @import rule that imports it.

alert(document.styleSheets[0].cssRules[0].styleSheet.cssRules[0].cssText);

@media blocks

@media blocks allow you to target a selection of style rules to a specific set of media types. The @media rule appears as a single rule in the stylesheet's cssRules collection. The style rules inside it do not appear in the stylesheet's cssRules collection at all. Instead, the rule has its own cssRules collection, that contains all the styles within it. This collection behaves in exactly the same way as the cssRules collection for the StyleSheet object.

The @media rule also has the insertRule and deleteRule methods, which behave in the same way as those for the StyleSheet object. As the @media rule also has a list of media types, it also has the media property, which also functions like that of the StyleSheet object.

All rules inside the @media block also have the parentRule property, which references the @media rule that they are inside. @media blocks may contain other @media blocks, and these can be nested as much as needed. If they are nested, their rules must be accessed by going through the chain of cssRules collections.

alert(document.styleSheets[0].cssRules[0].cssRules[0].cssText);

Test it here: show the contents of the last recognised media block in the first stylesheet.

Getting support for legacy Internet Explorer

Internet Explorer 8- on Windows and Mac does not provide many of the DOM 2 Style Sheets methods or properties, but it has an alternative that is not as complete as the standard, but can handle basic stylesheet manipulation. Internet Explorer 9+ follows the DOM standard only in standards rendering mode. Pages rendered in quirks mode will need to use the Internet Explorer model instead. Pages rendered in IE9+'s IE 7 compatibility mode (enabled automatically or by the user on some pages, or by default for intranet sites) will also not be able to use the standard model. If you need Internet Explorer 8- (or 9+ quirks mode) support, you will have to accept the differences and limitations, make sure your code does not rely on the parts that Internet Explorer is missing, and implement the branching code I will show you here.

In standards rendering mode, Internet Explorer 9+ maintains both the DOM and IE models, which are completely separate. When referencing the same rule using both collections, the returned objects are not the same as each other. The common properties in both models (like selectorText) can hold completely different values, depending on the bugs present in the implementation of that model. This can catch scripts out very easily, so it's best to use the least buggy model - the DOM model.

The styleSheets list

Internet Explorer provides the same collection as the other browsers, and to a large extent it works the same way. The type, disabled, href, and title properties all work the same way. The media property is different. Instead of being a media object, it is a string. As a result, there are no methods to add, remove, or list media types. If you want to change it, you will need to treat it as a string. Trying to set it will throw an error in IE Mac, so it will need a try...catch statement. (Note that in IE 9+ standards mode, IE provides both models - the media attribute follows the standards model.)

var oSheet = document.styleSheets[0];
if( typeof(oSheet.media) == 'string' ) {
  try { oSheet.media = 'screen'; } catch(e) {}
} else {
  oSheet.media.mediaText = 'screen';
}

Test it here: set the media type on all stylesheets on this page to 'print' (the page should appear unstyled when viewed normally), use print preview to check if it worked, then return it to normal.

Each stylesheet can reference the element that creates it using owningElement, in the same way as standards compliant browsers use ownerNode.

var oSheet = document.styleSheets[0];
var oElement = oSheet.ownerNode ? oSheet.ownerNode : oSheet.owningElement;

Although IE on Windows provides the styleSheet property of the LINK or STYLE element, in the same way as standards compliant browsers use sheet, this property is not available in IE on Mac.

var oElement = document.getElementsByTagName('style')[0];
var oSheet = oElement.sheet ? oElement.sheet : oElement.styleSheet;

Test it here: check for these properties.

Stylesheet cssRules collection

Internet Explorer provides the rules collection, in the same way as standards compliant browsers use cssRules. However, its behaviour is sufficiently different and incompatible, so it is not possible to simply index the same rule in each collection. @page, @media, @import, @charset, and @font-face rules are not included in the collection. In IE on Windows, all rules inside a @media block are included in the rules collection of the stylesheet. In IE Mac, they are ignored completely, and are not available to the DOM. In both browsers, it is not possible to modify the @media rule itself. Adding new rules into a @media block is not possible in IE on Windows.

Note that the stylesheet itself has a cssText property in IE, which gives all the CSS in the stylesheet. On Windows, this includes any @media blocks. However, it is not much fun to edit the stylesheet using pattern matching, which is all that this can provide.

IE on Mac provides both the rules and cssRules collections, but treats them both the IE way (so the cssRules collection is too short). Internet Explorer 9+, also provides both collections in standards rendering mode, but this time, they are implemented completely separately - using the IE and DOM models. In IE 9+, you would almost certainly want to use the standard one where it is available, while IE on Mac would want to use the IE model. If you don't care about IE on Mac (it's been discontinued, so you probably don't care about it), then simply check for the DOM collection and use it where available, falling back to the IE model otherwise:

var oSheet = document.styleSheets[0];
var oRule = oSheet.cssRules ? oSheet.cssRules[7] : oSheet.rules[3];

However, it is possible to get support for IE on Mac. Check if the stadard DOM collection is available, and make sure that it is not the same as the IE collection (that check will also work in other browsers that do not provide the DOM collection, since the IE collection will be undefined):

var oSheet = document.styleSheets[0];
var oRule = ( oSheet.cssRules && oSheet.cssRules != oSheet.rules ) ? oSheet.cssRules[7] : oSheet.rules[3];

Adding and removing rules in Internet Explorer (on Windows) is done using the addRule and removeRule methods. The removeRule method is exactly the same as the standard deleteRule method (except of course that the index will be different). The addRule method, however, is very different to the standard insertRule method. Firstly, it requires two different parameters; the selector string, and the rule string. Secondly, it can only add a rule at the end of the stylesheet.

var oSheet = document.styleSheets[0];
if( oSheet.deleteRule ) {
  oSheet.deleteRule(7);
} else if( oSheet.removeRule ) {
  oSheet.removeRule(3);
}
if( oSheet.insertRule ) {
  oSheet.insertRule('body { background: #779; }',oSheet.cssRules.length);
} else if( oSheet.addRule ) {
  oSheet.addRule('body','background: #779;');
}

Test it here: add the new rule 'p { color: lime; }', and then delete it again.

The CSS rule

Since the rules collection only contains normal style rules, the rules do not have a type property. In IE on Windows, they also do not have cssText. They do have a selectorText property though, and (apart from a few bugs) it behaves exactly the same as with standards compliant browsers. Similarly, they also have the parentStyleSheet property.

They also have the all important style property. However, here there are some significant differences. The item method does not exist in IE on Windows. You can try using for(i in styleobject) but that does not return what you specify in the stylesheet. Instead, it steps through all possible styles that IE recognises, whether you actually used them or not. It is actually a fairly short list (since IE does not actually support very many styles), but it makes recognising your own styles very hard.

More importantly, however, IE does not provide most of the other methods of the style object. To read or change styles, you will have to stick to the .style.color syntax. Since this works in all browsers, that is not too difficult to work with. Note that IE will throw errors if you set styles to values that it does not support (such as setting display to 'table'). Note that the .style.cssText property is available, but IE Mac makes a bit of a mess of it.

var oSheet = document.styleSheets[0];
var oRule = oSheet.rules ? oSheet.rules[3] : oSheet.cssRules[7];
oRule.style.color = 'lime';

Test it here: the last rule in the demo stylesheet is currently 'p { }'. Set its color property to 'lime', then set it back to ''.

There is also a StyleSheet.pages collection that gives all @page rules, but it does not give any useful information about the styles in that rule.

@import rules and imported stylesheets

@import rules are listed in their own StyleSheet.imports collection in IE. Each entry in this collection is a StyleSheet object, that is the same as the styleSheet property of the @import rule in standards compliant browsers. It has the same properties as a normal stylesheet.

var oSheet = document.styleSheets[0], oImportedSheet;
if( oSheet.imports ) {
  oImportedSheet = oSheet.imports[0];
} else {
  oImportedSheet = oSheet.cssRules[0].styleSheet;
}

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.