Chapter 9 – CSS Style Sheets & CSS rules

最后更新于:2022-04-01 04:39:27

## 9.1 CSS Style sheet overview A style sheet is added to an HTML document by either using the *HTMLLinkElement* node (i.e. *`<link href="stylesheet.css" rel="stylesheet" type="text/css">`*) to include an external style sheet or the*HTMLStyleElement* node (i.e. *`<style></style>`*) to define a style sheet inline. In the HTML document below both of these *Element* node's are in the DOM and I verify which constructor, constructs these nodes. live code: [http://jsfiddle.net/domenlightenment/yPYyC](http://jsfiddle.net/domenlightenment/yPYyC) ~~~ <!DOCTYPE html> <html lang="en"> <head> <link id="linkElement" href="http://yui.yahooapis.com/3.3.0/build/cssreset/reset-min.css" rel="stylesheet" type="text/css"> <style id="styleElement"> body{background-color:#fff;} </style> </head> <body> <script> //logs function HTMLLinkElement() { [native code] } console.log(document.querySelector('#linkElement').constructor); //logs function HTMLStyleElement() { [native code] } console.log(document.querySelector('#styleElement').constructor); </script> </body> </html> ~~~ Once a style sheet is added to an HTML document its represented by the *CSSStylesheet* object. Each CSS rule (e.g. *body{background-color:red;}*) inside of a style sheet is represent by a *CSSStyleRule* object. In the code below I verify which constructor constructed the style sheet and each CSS rule (selector & its css properties and values) in the style sheet. live code: [http://jsfiddle.net/domenlightenment/UpLzm](http://jsfiddle.net/domenlightenment/UpLzm) ~~~ <!DOCTYPE html> <html lang="en"> <head> <style id="styleElement"> body{background-color:#fff;} </style> </head> <body> <script> //logs function CSSStyleSheet() { [native code] } because this object is the stylesheet itself console.log(document.querySelector('#styleElement').sheet.constructor); //logs function CSSStyleRule() { [native code] } because this object is the rule inside of the style sheet console.log(document.querySelector('#styleElement').sheet.cssRules[0].constructor); </script> </body> </html> ~~~ Keep in mind that selecting the element that includes the style sheet (i.e. *`<link>`* or *`<style>`*) is not the same as accessing the actual object (*CSSStyleSheet*) that represents the style sheet itself. ## 9.2 Accessing all style sheets (i.e. *CSSStylesheet* objects) in the DOM *document.styleSheets* gives access to a list of all style sheet objects (aka *CSSStylesheet*) explicitly linked (i.e.*`<link>`*) or embedded (i.e. *`<style>`*) in an HTML document. In the code below *styleSheets* is leverage to gain access to all of the style sheets contained in the document. live code: N/A ~~~ <!DOCTYPE html> <html lang="en"> <head> <link href="http://yui.yahooapis.com/3.3.0/build/cssreset/reset-min.css" rel="stylesheet" type="text/css"> <style> body{background-color:red;} </style> </head> <body> <script> console.log(document.styleSheets.length); //logs 2 console.log(document.styleSheets[0]); // the <link> console.log(document.styleSheets[1]); // the <style> </script> </body> </html> ~~~ ### Notes *styleSheet* is live just like other node lists The *length* property returns the number of stylesheets contained in the list starting at 0 index (i.e.*document.styleSheets.length*) The style sheets included in a *styleSheets* list typically includes any style sheets created using the *`<style>`* element or using a *`<link>`* element where *rel* is set to *"stylesheet"* In addtion to using *styleSheets* to access a documents styles sheets its also possible to access a style sheet in an HTML document by first selecting the element in the DOM (*`<style>`* or *`<link>`*) and using the *.sheet* property to gain access to the *CSSStyleSheet* object. In the code below I access the style sheets in the HTML docment by first selecting the element used to include the style sheet and then leveraging the *sheet* property. live code: [http://jsfiddle.net/domenlightenment/jFwKw](http://jsfiddle.net/domenlightenment/jFwKw) ~~~ <!DOCTYPE html> <html lang="en"> <head> <link id="linkElement" href="http://yui.yahooapis.com/3.3.0/build/cssreset/reset-min.css" rel="stylesheet" type="text/css"> <style id="styleElement"> body{background-color:#fff;} </style> </head> <body> <script> //get CSSStylesheeet object for <link> console.log(document.querySelector('#linkElement').sheet); //same as document.styleSheets[0] //get CSSSstylesheet object for <style> console.log(document.querySelector('#styleElement').sheet); //same as document.styleSheets[1] </script> </body> </html> ~~~ ## 9.3 CSSStyleSheet properties and methods To get accurate information pertaining to the available properties and methods on an *CSSStyleSheet* node its best to ignore the specification and to ask the browser what is available. Examine the arrays created in the code below detailing the properties and methods available from a *CSSStyleSheet* node. live code: [http://jsfiddle.net/domenlightenment/kNyL2](http://jsfiddle.net/domenlightenment/kNyL2) ~~~ <!DOCTYPE html> <html lang="en"> <head><style id="styleElement">body{background-color:#fff;}</style></head> <body> <script> var styleSheet = document.querySelector('#styleElement').sheet; //text own properties console.log(Object.keys(styleSheet).sort()); //text own properties & inherited properties var styleSheetPropertiesIncludeInherited = []; for(var p in styleSheet){ styleSheetPropertiesIncludeInherited.push(p); } console.log(styleSheetPropertiesIncludeInherited.sort()); //text inherited properties only var styleSheetPropertiesOnlyInherited = []; for(var p in styleSheet){ if(!styleSheet.hasOwnProperty(p)){ styleSheetPropertiesOnlyInherited.push(p); } } console.log(styleSheetPropertiesOnlyInherited.sort()); </script> </body> </html> ~~~ A *CSSStyleSheet* object accessed from a *styleSheets* list or via the *.sheet* property has the following properties and methods: * *disabled* * *href* * *media* * *ownerNode* * *parentStylesheet* * *title* * *type* * *cssRules* * *ownerRule* * *deleteRule* * *inserRule* ### Notes *href*, *media*, *ownerNode*, *parentStylesheet*, *title*, and *type* are read only properties, you can't set its value using these properteis ## 9.4 CSSStyleRule overview A *CSSStyleRule* object represents each CSS rule contained in a style sheet. Basicly a *CSSStyleRule* is the interface to the CSS properties and values attached to a selector. In the code below we programaticlly access the details of each rule contained in the inline style sheet by accessing the *CSSStyleRule* object that represents the CSS rule in the style sheet. live code: [http://jsfiddle.net/domenlightenment/fPVS8](http://jsfiddle.net/domenlightenment/fPVS8) ~~~ <!DOCTYPE html> <html lang="en"> <head> <style id="styleElement"> body{background-color:#fff;margin:20px;} /*this is a css rule*/ p{line-height:1.4em; color:blue;} /*this is a css rule*/ </style> </head> <body> <script> var sSheet = document.querySelector('#styleElement'); console.log(sSheet.cssRules[0].cssText); //logs "body { background-color: red; margin: 20px; }" console.log(sSheet.cssRules[1].cssText); //logs "p { line-height: 1.4em; color: blue; }" </script> </body> </html> ~~~ ## 9.5 *CSSStyleRule* properties and methods To get accurate information pertaining to the available properties and methods on an *CSSStyleRule* node its best to ignore the specification and to ask the browser what is available. Examine the arrays created in the code below detailing the properties and methods available from a *CSSStyleRule*node. live code: [http://jsfiddle.net/domenlightenment/hCX3U](http://jsfiddle.net/domenlightenment/hCX3U) ~~~ <!DOCTYPE html> <html lang="en"> <head><style id="styleElement">body{background-color:#fff;}</style></head> <body> <script> var styleSheetRule = document.querySelector('#styleElement').sheet.cssRule; //text own properties console.log(Object.keys(styleSheetRule).sort()); //text own properties & inherited properties var styleSheetPropertiesIncludeInherited = []; for(var p in styleSheetRule){ styleSheetRulePropertiesIncludeInherited.push(p); } console.log(styleSheetRulePropertiesIncludeInherited.sort()); //text inherited properties only var styleSheetRulePropertiesOnlyInherited = []; for(var p in styleSheetRule){ if(!styleSheetRule.hasOwnProperty(p)){ styleSheetRulePropertiesOnlyInherited.push(p); } } console.log(styleSheetRulePropertiesOnlyInherited.sort()); </script> </body> </html> ~~~ Scripting the rules (e.g. *body{background-color:red;}*) contained inside of a style sheet is made possible by the *CSSrule* object. This object provides the following properties: * *cssText* * *parentRule* * *parentStylesSheet* * *selectorText* * *style* * *type* ## 9.6 Getting a list of CSS Rules in a style sheet using *CSSRules* As previously discussed the *styleSheets* list provides a list of style sheets contained in a document. The*CSSRules* list provides a list (aka *CSSRulesList*) of all the CSS rules (i.e. *CSSStyleRule* objects) in a specific style sheet. The code below logs a *CSSRules* list to the console. live code: [http://jsfiddle.net/domenlightenment/qKqhJ](http://jsfiddle.net/domenlightenment/qKqhJ) ~~~ <!DOCTYPE html> <html lang="en"> <head> <style id="styleElement"> body{background-color:#fff;margin:20px;} p{line-height:1.4em; color:blue;} </style> </head> <body> <script> var sSheet = document.querySelector('#styleElement').sheet; //array like list containing all of the CSSrule objects repreesenting each CSS rule in the style sheet console.log(sSheet.cssRules); console.log(sSheet.cssRules.length); //logs 2 //rules are index in a CSSRules list starting at a 0 index console.log(sSheet.cssRules[0]); //logs first rule console.log(sSheet.cssRules[1]); //logs second rule </script> </body> </html> ~~~ ## 9.7 Inserting & deleting CSS rules in a style sheet using *.insertRule()*and *.deleteRule()* The *insertRule()* and *deleteRule()* methods provided the ability to programatically manipulate the CSS rules in a style sheet. In the code below I use *insertRule()* to add the css rule *p{color:red}* to the inline style sheet at index 1\. Remeber the css rules in a style sheet are numerical index starting at 0\. So by inserting a new rule at index 1 the current rule at index 1 (i.e. *p{font-size:50px;}*) is push to index 2. live code: [http://jsfiddle.net/domenlightenment/T2jzJ](http://jsfiddle.net/domenlightenment/T2jzJ) ~~~ <!DOCTYPE html> <html lang="en"> <head> <style id="styleElement"> p{line-height:1.4em; color:blue;} /*index 0*/ p{font-size:50px;} /*index 1*/ </style> </head> <body> <p>Hi</p> <script> //add a new CSS rule at index 1 in the inline style sheet document.querySelector('#styleElement').sheet.insertRule('p{color:red}',1); //verify it was addedconsole.log(document.querySelector('#styleElement').sheet.cssRules[1].cssText); //Delete what we just added document.querySelector('#styleElement').sheet.deleteRule(1); //verify it was removedconsole.log(document.querySelector('#styleElement').sheet.cssRules[1].cssText); </script> </body> </html> ~~~ Deleting or removing a rule is as simple as calling *deleteRule()* method on a style sheet and passing it the index of the rule in the style sheet to be deleted. ### Notes Inserting and deleting rules is not a common practice given the difficulty around managing the cascaade and using a numeric indexing system to update a style sheet (i.e. determining at what index a style is located without previewing the contents of the style sheet itself.). Its much simpler working with CSS rules in CSS and HTML files before they are served to a client than programaticlly altering them in the client after the fact. ## 9.8 Editing the value of a *CSSStyleRule* using the *.style* property Just like the *.style* property that facilitates the manipulation of inline styles on element nodes there is a also*.style* property for *CSSStyleRule* objects that orchestrates the same manipulation of styles in style sheets. In the code below I levereage the *.style* property to set and get the value of css rules contained in the inline style sheet. live code: [http://jsfiddle.net/domenlightenment/aZ9CQ](http://jsfiddle.net/domenlightenment/aZ9CQ) ~~~ <!DOCTYPE html> <html lang="en"> <head> <style id="styleElement"> p{color:blue;} strong{color:green;} </style> </head> <body> <p>Hey <strong>Dude!</strong></p> <script> var styleSheet = document.querySelector('#styleElement').sheet; //Set css rules in stylesheet styleSheet.cssRules[0].style.color = 'red'; styleSheet.cssRules[1].style.color = 'purple'; //Get css rules console.log(styleSheet.cssRules[0].style.color); //logs 'red' console.log(styleSheet.cssRules[1].style.color); //logs 'purple' </script> </body> </html> ~~~ ## 9.9 Creating a new inline CSS style sheets To craft a new style sheet on the fly after an html page is loaded one only has to create a new *`<style>`* node, add CSS rules using *innerHTML* to this node, then append the*`<style>`* node to the HTML document. In the code below I programatily craft a style sheet and add the *body{color:red}* CSS rule to the style sheet, then append the stylesheet to the DOM. live code: [http://jsfiddle.net/domenlightenment/bKXAk](http://jsfiddle.net/domenlightenment/bKXAk) ~~~ <!DOCTYPE html> <html lang="en"> <head></head> <body> <p>Hey <strong>Dude!</strong></p> <script> var styleElm = document.createElement('style'); styleElm.innerHTML = 'body{color:red}'; //notice markup in the document changed to red from our new inline stylesheet document.querySelector('head').appendChild(styleElm); </script> </body> </html> ~~~ ## 9.10 Programatically adding external style sheets to an HTML document To add a CSS file to an HTML document programatically a *`<link>`* element node is created with the appropriate attributes and then the *`<link>`* element node is appended to the DOM. In the code below I programatically include an external style sheet by crafting a new *`<link>`* element and appending it to the DOM. live code: [http://jsfiddle.net/domenlightenment/dtwgC](http://jsfiddle.net/domenlightenment/dtwgC) ~~~ <!DOCTYPE html> <html lang="en"> <head></head> <body> <script> //create & add attributes to <link> var linkElm = document.createElement('link');linkElm.setAttribute('rel', 'stylesheet');linkElm.setAttribute('type', 'text/css'); linkElm.setAttribute('id', 'linkElement');linkElm.setAttribute('href', 'http://yui.yahooapis.com/3.3.0/build/cssreset/reset-min.css'); //Append to the DOM document.head.appendChild(linkElm); //confrim its addition to the DOM console.log(document.querySelector('#linkElement')); </script> </body> </html> ~~~ ## 9.11 Disabling/Enabling style sheets using *disabled* property Using the *.disabled* property of a *CSSStyleSheet* object its possible to enable or disabled a style sheet. In the code below we access the current disabled value of each style sheet in the document then proceed to disabled each style sheet leveraging the *.disabled* property. live code: [http://jsfiddle.net/domenlightenment/L952Z](http://jsfiddle.net/domenlightenment/L952Z) ~~~ <!DOCTYPE html> <html lang="en"> <head> <link id="linkElement" href="http://yui.yahooapis.com/3.3.0/build/cssreset/reset-min.css" rel="stylesheet" type="text/css"> <style id="styleElement"> body{color:red;} </style> </head> <body> <script> //Get current boolean disabled value console.log(document.querySelector('#linkElement').disabled); //log 'false' console.log(document.querySelector('#styleElement').disabled); //log 'false' //Set disabled value, which of courese disabled all styles for this document document.document.querySelector('#linkElement').disabled = true; document.document.querySelector('#styleElement').disabled = true; </script> </body> </html> ~~~ ### Notes Disabled is not an avaliable attributre of a or element according to the specification. Trying to add this as an attribute in the HTML document itself will fail (and likley cause parsing errors where styles are ignored) in the majority of modern browsers in use today.
';