Scripting Rules

Instead of scripting className, to change the appearance of several elements we can also script a rule that targets them.

Rather than swapping className, we could just as well change the rule for the blue class in eight.css.

JavaScript represents a style sheet like eight.css with a CSSStyleSheet object. Those implement the members listed in two DOM interfaces, StyleSheet and CSSStyleSheet.

The following seven members come from StyleSheet:

  • disabled
  • href
  • media
  • ownerNode
  • parentStyleSheet
  • title
  • type

Additionally, four CSS-only members come from the CSSStyleSheet interface.

  • cssRules
  • ownerRule
  • deleteRule()
  • insertRule()

Internet Explorer does not implement any members from CSSStyleSheet. But there are Internet Explorer–only members which are as follows:

  • rules
  • imports
  • addRule()
  • addImport()
  • removeRule()
  • removeImport()
  • cssText

Before we can query a rule, we need to get at the style sheet that contains the rule. One way is to query the sheet member of a <link> or <style> element in Firefox, Safari, and Opera. Internet Explorer deviates from DOM, and implements a proprietary styleSheet member instead. With this in mind, our first steps will be the following:

var myStyleSheet = document.getElementsByTagName("link")[0];
myStyleSheet = myStyleSheet.sheet || myStyleSheet.styleSheet;

Another way to query a style sheet is by way of document.styleSheets, which contains an array-like object with one member for every <style> or <link> element having a rel attribute value set to "stylesheet". No browser adds imported style sheets to document.styleSheets.

we could rewrite the previous sample like so:

var myStyleSheet = document.styleSheets[0];
Note
Note document.styleSheets is provided by the DocumentStyle interface. In turn, styleSheets contains an array-like object provided by the StyleSheetList interface. Members contained by a StyleSheetList are objects that have the features listed in the StyleSheet and CSSStyleSheet interfaces. So, there are four interfaces for you to consult in a DOM reference.
Finding Rules

Now myStyleSheet contains an object representing eight.css. Let’s find the rule for the blue class. It’s in a cssRules member for Firefox, Safari, and Opera, but in a rules member for Explorer. Those are both CSSRuleList objects. Those are array-like objects, which is to say their members are elements.cssRules.length or rules.length contains the number of members.

cssRules contains both styling rules and @ directives like @import. On the other hand, rules contains only styling rules. In other words, it contains the ones comprised of a selector and declaration block. So if a style sheet contains @ directives, cssRules.length will be greater than rules.length. In Internet Explorer, @import directives are nowhere to be found, but any @page directives are in an array-like object named pages.

Note
Although @import directives are missing in Internet Explorer, scripting imported style sheets remains doable by way of imports, addImport(), and removeImport().

Note that Internet Explorer splits grouped selectors into more than one rule. Therefore, for the following rule, Internet Explorer would add two members to rules, while Firefox, Safari, and Opera would add one member to cssRules:

snippet
div#mast form, div#mast h1 {
	 display:inline;
}
 In other words, Internet Explorer separates the previous rule into two like so: div#mast form {
	 display:inline;
}
 div#mast h1 {
	 display:inline;
}

The rules are numerically indexed in source code order. To find the rule with the selector "ul.blue a" in order to change the sprite to fuchsia; do a for loop like the following example.

snippet
var myStyleSheet = document.getElementsByTagName("link")[0];
myStyleSheet = myStyleSheet.sheet || myStyleSheet.styleSheet;
var myRules = myStyleSheet.cssRules || myStyleSheet.rules;
for (var i = myRules.length - 1; i > -1; i--) {
    if (myRules[i].selectorText && myRules[i].selectorText.toLowerCase() === "ul.blue a") {
        myRules[i].style.backgroundImage = "url(images/fuchsia.gif)";
        break;
    }
}

Three things in the for loop bear explaining.

  • First, we loop through the rules in reverse order because of CSS precedence. If more than one rule in the style sheet has the selector we are looking for, we want to change the last one.
  • Second, @import and other @ rules do not define a selectorText or style member Calling String.toLowerCase() on undefined returns an error. So, we use the && operator to skip any rules that do not define selectorText.
  • Third, the string in selectorText may or may not match the CSS selector. For this reason, we lowercase selectorText prior to comparing it with ===.

Lets code a helper function named findRule() that takes two parameters.

elementcontain the <link> or <style> element
selectorcontain the selector for the rule we want to find.
function findRule(element, selector) {
}

Let’s modify the body of the 'for' loop from the previous sample. In case there are no matching CSSStyleRule object, return null following the for loop.

snippet
function findRule(element, selector) {
    var sheet = element.sheet || element.styleSheet;
    var rules = sheet.cssRules || sheet.rules;
    selector = selector.toLowerCase()
    for (var i = rules.length - 1; i > -1; i--) {
        if (rules[i].selectorText && rules[i].selectorText.toLowerCase() === selector) {
            return rules[i];
        }
    }
    return null;
}

Now let’s call findRule() and change style by CSSStyleRule.style contains an object with the members listed in the CSSStyleDeclaration and CSS2Properties interfaces.

snippet
var myRule = findRule(document.getElementsByTagName("link")[0], "ul.blue a");
if (myRule !== null) {
    myRule.style.backgroundImage = "url(images/fuchsia.gif)";
}
Now rework the previous sample by way of CSSStyleDeclaration.cssText.
snippet
var myRule = findRule(document.getElementsByTagName("link")[0], "a#saucony");
if (myRule !== null) {
    myRule.style.cssText = "background:url(images/green.gif) -99px -135px; top:205px";
}
Note
Style sheet differs from a <link> or <style>. The latter is markup, while the former is CSS. In other words, a style sheet is the CSS code in the file included by a <link> element or contained by a <style> element. So, you cannot, for example, retrieve a style sheet by its id member, since it does not have one. However, you can and probably retrieve the corresponding <link> or <style> element by its id.

Lets see an example by referring its id.

snippet
var myRule = findRule(document.getElementById("spriteStyles"), "a#saucony");
if (myRule !== null) {
    myRule.style.cssText = "background:url(images/green.gif) -99px -135px; top:205px";
}
Related Tutorial
Follow Us
https://www.facebook.com/Rookie-Nerd-638990322793530 https://twitter.com/RookieNerdTutor https://plus.google.com/b/117136517396468545840 #
Contents +