Section 16.6. Scripting Stylesheets


16.6. Scripting Stylesheets

Previous sections have explained two techniques for CSS scripting: altering the inline styles of an element and altering the class of an element. It is also possible to script the stylesheets themselves, as the subsections that follow demonstrate.

16.6.1. Enabling and Disabling Stylesheets

The simplest stylesheet scripting technique is also the most portable and robust. The HTML DOM Level 2 standard defines a disabled property for both <link> and <script> elements. There is no corresponding disabled attribute on the HTML tags, but there is a property that you can query and set in JavaScript. As its name implies, if the disabled property is TRue, the stylesheet related to the <link> or <style> element is disabled and ignored by the browser.

Example 16-8 demonstrates this. It is an HTML page that includes four stylesheets. It displays four checkboxes that allow the user to enable and disable each of the four stylesheets individually.

Example 16-8. Enabling and disabling stylesheets

 <head> <!-- Here we define four stylesheets, using <link> and <style> tags. --> <!-- Two of the <link>ed sheets are alternate and so disabled by default. --> <!-- All have id attributes so we can refer to them by name. --> <link rel="stylesheet" type="text/css" href="ss0.css" > <link rel="alternate stylesheet" type="text/css" href="ss1.css"        title="Large Type"> <link rel="alternate stylesheet" type="text/css" href="ss2.css"        title="High Contrast"> <style  title="Sans Serif"> body { font-family: sans-serif; } </style> <script> // This function enables or disables a stylesheet specified by id. // It works for <link> and <style> elements. function enableSS(sheetid, enabled) {     document.getElementById(sheetid).disabled = !enabled; } </script> </head> <body> <!-- This is a simple HTML form for enabling and disabling stylesheets --> <!-- It is hardcoded to match the sheets in this document but could be --> <!-- dynamically generated using stylesheet titles instead. --> <form> <input type="checkbox" onclick="enableSS('ss0', this.checked)" checked>Basics <br><input type="checkbox" onclick="enableSS('ss1', this.checked)">Large Type <br><input type="checkbox" onclick="enableSS('ss2', this.checked)">Contrast <br><input type="checkbox" onclick="enableSS('ss3', this.checked)" checked> Sans Serif </form> 

16.6.2. Stylesheet Objects and Stylesheet Rules

In addition to allowing you to enable and disable the <link> and <style> tags that refer to stylesheets, the Level 2 DOM also defines a complete API for querying, traversing, and manipulating stylesheets themselves. At the time of this writing, the only browser to support a substantial portion of this standard stylesheet traversal API is Firefox. IE 5 defines a different API, and other browsers have limited (or no) support for working with stylesheets directly.

In general, manipulating stylesheets directly is not normally a useful thing to do. Instead of adding new rules to a stylesheet, for example, it is typically better to leave your stylesheets static and script the className property of your elements instead. On the other hand, if you want to allow the user complete control over the styles used on your pages, you might need to dynamically manipulate a stylesheet (perhaps storing the user's preferred styles in a cookie). If you decide to script stylesheets directly, the code shown in this section works in Firefox and IE, but may not work in other browsers.

The stylesheets that apply to a document are stored in the styleSheets[] array of the document object. If a document has only a single stylesheet, you can refer to it as:

 var ss = document.styleSheets[0] 

The elements of this array are CSSStyleSheet objects. Note that these objects are not the same as the <link> or <style> tags that refer to or hold the stylesheet. A CSSStyleSheet object has a cssRules[] array that contains the rules of the stylesheet:

 var firstRule = document.styleSheets[0].cssRules[0]; 

IE does not support the cssRules property but does have an equivalent rules property.

The elements of the cssRules[] or rules[] arrays are CSSRule objects. In the W3C standards, a CSSRule object may represent any kind of CSS rule, including at-rules such as @import and @page directives. In IE, however, the CSSRule object represents only the actual style rules of the stylesheet.

CSSRule objects have two properties that can be used portably. (In the W3C DOM, a rule that is not a style rule will not have these properties defined, and you probably want to skip over it when traversing the stylesheet.) selectorText is the CSS selector for the rule, and style refers to a CSS2Properties object that describes the styles associated with that selector. Recall that CSS2Properties is the same interface used to represent the inline styles of an HTML element through the style property. You can use this CSS2Properties object to query the style values or to set new styles for the rule. Often, when traversing a stylesheet, you are interested in the text of the rule rather than a parsed representation of the rule. In this case, use the cssText property of the CSS2Properties object to obtain the text representation of the rules.

The following code loops through the rules of a stylesheet, demonstrating what you can do with them:

 // Get the first stylesheet of the document var ss = document.styleSheets[0]; // Get the rules array using W3C or IE API var rules = ss.cssRules?ss.cssRules:ss.rules; // Iterate through those rules for(var i = 0; i < rules.length; i++) {     var rule = rules[i];     // Skip @import and other nonstyle rules     if (!rule.selectorText) continue;     // This is the text form of the rule     var ruleText = rule.selectorText + " { " + rule.style.cssText + " }";     // If the rule specifies a margin, assume it is in pixels and double it     var margin = parseInt(rule.style.margin);     if (margin) rule.style.margin = (margin*2) + "px"; } 

In addition to querying and altering the existing rules of a stylesheet, you can also add rules to and remove rules from a stylesheet. The W3C CSSStyleSheet interface defines insertRule() and deleteRule() methods for adding and removing rules:

 document.styleSheets[0].insertRule("H1 { text-weight: bold; }", 0); 

IE does not support insertRule() and deleteRule() but defines largely equivalent addRule() and removeRule() functions. The only real difference (aside from the different names) is that addRule() expects the selector text and styles text as two separate arguments. Example 16-9 defines a Stylesheet utility class that demonstrates both the W3C and IE APIs for adding and deleting rules.

Example 16-9. Stylesheet utility methods

 /**  * Stylesheet.js: utility methods for scripting CSS stylesheets.  *  * This module defines a Stylesheet class that is a simple wrapper  * around an element of the document.styleSheets[] array. It defines useful  * cross-platform methods for querying and modifying the stylesheet.  **/ // Construct a new Stylesheet object that wraps the specified CSSStylesheet. // If ss is a number, look up the stylesheet in the styleSheet[] array. function Stylesheet(ss) {     if (typeof ss == "number") ss = document.styleSheets[ss];     this.ss = ss; } // Return the rules array for this stylesheet. Stylesheet.prototype.getRules = function() {     // Use the W3C property if defined; otherwise use the IE property     return this.ss.cssRules?this.ss.cssRules:this.ss.rules; } // Return a rule of the stylesheet. If s is a number, we return the rule // at that index.  Otherwise, we assume s is a selector and look for a rule // that matches that selector. Stylesheet.prototype.getRule = function(s) {     var rules = this.getRules();     if (!rules) return null;     if (typeof s == "number") return rules[s];     // Assume s is a selector     // Loop backward through the rules so that if there is more than one     // rule that matches s, we find the one with the highest precedence.     s = s.toLowerCase();     for(var i = rules.length-1; i >= 0; i--) {         if (rules[i].selectorText.toLowerCase() == s) return rules[i];     }     return null; }; // Return the CSS2Properties object for the specified rule. // Rules can be specified by number or by selector. Stylesheet.prototype.getStyles = function(s) {     var rule = this.getRule(s);     if (rule && rule.style) return rule.style;     else return null; }; // Return the style text for the specified rule. Stylesheet.prototype.getStyleText = function(s) {     var rule = this.getRule(s);     if (rule && rule.style && rule.style.cssText) return rule.style.cssText;     else return ""; }; // Insert a rule into the stylesheet. // The rule consists of the specified selector and style strings. // It is inserted at index n. If n is omitted, it is appended to the end. Stylesheet.prototype.insertRule = function(selector, styles, n) {     if (n == undefined) {         var rules = this.getRules();         n = rules.length;     }     if (this.ss.insertRule)   // Try the W3C API first         this.ss.insertRule(selector + "{" + styles + "}", n);     else if (this.ss.addRule) // Otherwise use the IE API         this.ss.addRule(selector, styles, n); }; // Remove the rule from the specified position in the stylesheet. // If s is a number, delete the rule at that position. // If s is a string, delete the rule with that selector. // If n is not specified, delete the last rule in the stylesheet. Stylesheet.prototype.deleteRule = function(s) {     // If s is undefined, make it the index of the last rule     if (s == undefined) {         var rules = this.getRules();         s = rules.length-1;     }     // If s is not a number, look for a matching rule and get its index.     if (typeof s != "number") {         s = s.toLowerCase();    // convert to lowercase         var rules = this.getRules();         for(var i = rules.length-1; i >= 0; i--) {             if (rules[i].selectorText.toLowerCase() == s) {                 s = i;  // Remember the index of the rule to delete                 break;  // And stop searching             }         }         // If we didn't find a match, just give up.         if (i == -1) return;     }     // At this point, s will be a number.     // Try the W3C API first, then try the IE API     if (this.ss.deleteRule) this.ss.deleteRule(s);     else if (this.ss.removeRule) this.ss.removeRule(s); }; 




JavaScript. The Definitive Guide
JavaScript: The Definitive Guide
ISBN: 0596101996
EAN: 2147483647
Year: 2004
Pages: 767

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net