JavaScript DOM2和DOM3——“样式”的注意要点 - 前端学习笔记
层次:
访问style对象:
style
对象是CSSStyleDeclaration
的实例;getComputedStyle
方法也返回CSSStyleDeclaration
的实例;
访问样式表:
<link>
元素包含的样式表由HTMLLinkElement
表示;<style>
元素包含的样式表由HTMLStyleElement
表示;StyleSheetList
表示所有的样式表;(document.styleSheets
)CSSStyleSheet
表示该样式表;(document.styleSheets[0]
或document.getElementsByTagName("link").sheet/styleSheet
);
访问CSS规则:
CSSRuleList
表示所有的CSS规则;(document.styleSheets[0].rules/cssRules
);CSSStyleRule
表示该CSS规则;(document.styleSheets[0].cssRules[0]
);CSSStyleDeclaration
则通过style属性访问;(document.styleSheets[0].cssRules[0].style
);
举例:
var div = document.getElementById("myDiv");console.log(div.style.border); //1px solid black console.log(div.style.length); //18console.log(div.style.cssText); //order: 1px solid black; background-color: red;console.log(div.style[0]); //background-color;div.style.removeProperty("border");div.style.setProperty("border","1px solid blue");console.log(div.style.getPropertyValue("border")); //1px solid blueconsole.log(document.defaultView.getComputedStyle(div).length); //263console.log(document.defaultView.getComputedStyle(div).width); //100px;//以上是访问元素的样式var styleElem = document.getElementsByTagName("style")[0]; //获得style元素var styleSheet = styleElem.sheet; //获得样式表var rule = styleSheet.rules[0]; //获得第一个css规则console.log(rule.cssText); //#myDiv { width: 100px; height: 200px; background-color: blue; }console.log(rule.selectorText); //#myDivconsole.log(rule.style); //CSSStyleDeclaration 此方法可以返回这个规则的样式并可以赋值,设置新的样式console.log(rule.style.width); //100pxrule.style.width = "200px";console.log(rule.style.width); //200pxvar styleSheet2 = document.styleSheets[0];console.log(styleSheet == styleSheet2); //True证明document.styleSheets与style标签返回的styleSheet是一样的styleSheet.insertRule("body{background-color:gray}",0); //在样式表中插入新的CSS规则styleSheet.deleteRule(0); //在样式表中删除某个CSS规则//以上是操作样式表
要确定浏览器是否支持DOM2级定义的CSS能力,可以使用下列代码:
var supportsDOM2CSS = document.implementation.hasFeature("CSS","2.0");var supportsDOM2CSS2 = document.implementation.hasFeature("CSS2","2.0");
访问元素的样式
需要注意的是,由于float
是js中的保留字,因此不能用作属性名。而是cssFloat
或IE中的styleFloat
;style对象是CSSStyleDeclaration的实例。
另外,在标准模式下,所有度量值都必须指定一个度量单位。
DOM样式属性和方法
DOM2级样式
规范还为style对象定义了一些属性和方法:
cssText
;length
;parentRule
;getPropertyCSSValue(propertyName)
;getPropertyPriority(propertyName)
;getPropertyValue(propertyName)
;item(index)
;removeProperty(propertyName)
;setProperty(propertyName,value,priority)
;
cssText
属性
style的属性,该模式可以访问style特性中的CSS代码。读取模式下,返回style特性中CSS代码的内部表示;在写入模式下,赋给cssText的值会重写整个style特性的值。如:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <style> p { font-size: 2em; /*嵌入式样式*/ } </style></head><body> <p id="p" style="text-transform:capitalize">this is a paragraph.</p> <!-- style特性的方式设置css样式 --> <script> var p = document.getElementById("p"); p.style.fontFamily = "monospace"; // 用js通过style设置 console.log(p.style.cssText); //text-transform: capitalize; font-family: monospace; p.style.cssText = "font-size:2em"; //重写cssText console.log(p.style.cssText); //font-size:2em; </script></body></html>
length
属性
style的属性,length的目的,就是将其与item()方法配套使用,以便迭代在元素中定义的CSS属性。如:
<body> <p id="p" style="color:red;font-family: monospace;">this is a paragraph.</p> <script> var p = document.getElementById("p"); for (var i = 0, len = p.style.length; i < len; i++) { console.log(p.style[i]); //color //font-family }; </script></body>
getPropertyValue()
方法
style的属性,可以使用属性名进一步取得属性的值。如:
<body> <p id="p" style="color:red;font-family: monospace;">this is a paragraph.</p> <script> var p = document.getElementById("p"); var i, prop; for (i = 0, len = p.style.length; i < len; i++) { prop = p.style[i]; value = p.style.getPropertyValue(prop); console.log(prop + "-->" + value); //color-->red //font-family-->monospace }; </script></body>
getPropertyCSSValue()
方法
style属性,返回一个包含两个属性的CSSValue对象,这两个属性分别是cssText和cssValueType。其中,cssText属性的值与getPropertyValue()返回的值相同,而cssValueType属性则是一个数值常量,表示值的类型:0为继承的值;1为基本的值;2为列表;3为自定义的值。如下面的代码即输出CSS属性值,也输出值的类型:
var p = document.getElementById("p");var i, prop;for (i = 0, len = p.style.length; i < len; i++) { prop = p.style[i]; value = p.style.getPropertyCSSValue(prop); console.log(prop + ":" + value.cssText + "," + value.cssValueType); // [Log] color:red,1 (testingjs.js, line 6) // [Log] font-family:monospace,2 (testingjs.js, line 6)}
或许兼容性有问题,这个代码在chrome中运行不了。不过,此方法不常用,一般都是用getPropertyValue()
方法
removeProperty()
方法
该属性的目的是要移除某个CSS属性。如:
var p = document.getElementById("p");p.style.removeProperty("color");
setProperty()
方法
该属性的目的是要添加某个CSS属性。如:
var p = document.getElementById("p");console.log(p.style.setProperty("color","orange"));
计算的样式getComputedStyle()
方法和currentStyle
属性
前者是增强了document.defaultView
,这个方法接收两个参数:计算样式的元素以及一个伪元素字符串(如:after)。如果不需要伪元素信息,第二个值设置为null即可。该方法返回一个CSSStyleDeclaration对象,以下面代码为例:
<style>#myDiv { background-color: blue; width: 100px; height: 200px;}</style><div id="myDiv" style="background-color:red;border:1px solid black"></div>
使用getComputedStyle()
方法,用法是document.defaultView.getComputedStyle()
返回CSSStyleDeclaration
实例:
var myDiv = document.getElementById("myDiv");var computedStyle = document.defaultView.getComputedStyle(myDiv, null);console.log(computedStyle.length); //263console.log(myDiv.style.length); //18console.log(computedStyle.backgroundColor); //rgb(255,0,0)console.log(computedStyle.border); //1px solid rgb(0, 0, 0)console.log(computedStyle.width + computedStyle.height); //100px200px
currentStyle
属性则是用在IE上的,与上述类似。用法是element.currentStyle
返回CSSStyleDeclaration
实例。
操作表样式
CSSStyleSheet类型表示的是样式表,包括link元素包含的样式表和在style元素中定义的样式表。这两个元素本身是由HTMLLinkElement和HTMLStyleElement类型表示的。但是CSSStyleSheet类型相对更加通用一些,它只表示样式表,而不管这些样式表在HTML中是如何定义的。CSSStyleSheet继承自StyleSheet,接口属性如下:
disabled:表示样式表是否被禁用的布尔值;
href:如果是link元素表示的样式表,则是样式表的URL,否则是null;
media:当前样式表支持的所有媒体类型的集合,可用length属性和item()方法,在IE中返回字符串;
ownerNode:指向拥有当前样式表的节点的指针;IE不支持;
parentStyleSheet:如果样式表是通过@import导入的,这个属性是一个指向导入它的样式表的指针;
title:ownerNode中title值;
type:样式表类型的字符串,一般是“type/css”;
CSSStyleSheet类型还支持下面的属性和方法:
cssRules:样式表中包含的样式规则的集合。IE不支持但有个类似的rules;
ownerRule:样式表是通过@import导入的,这个属性就是一个指针,指向表示导入的规则;否则为null;IE不支持;
deleteRule(index):删除cssRules集合中指定位置的规则;IE不支持但有个类似的removeRule()方法;
insertRule(rule,index):向cssRules集合中指定的位置插入rule字符串,IE不支持但有个类似的addRule()方法;
应用于文档中的所有样式表是通过document.styleSheets
集合来表示的。
另外,也可以直接通过link元素和style元素取得CSSStyleSheet对象。DOM规定了一个包含CSSStyleSheet对象的属性,名叫sheet
;在IE,可以使用styleSheet
属性。如:
console.log(document.getElementsByTagName("style")[0].sheet); //CSSStyleSheet对象console.log(document.getElementsByTagName("style")[0].styleSheet); //CSSStyleSheet对象 只用于IEconsole.log(document.styleSheets[0]); //同样也是CSSStyleSheet对象
CSS规则
层次梳理:
console.log(document.styleSheets); //StyleSheetList对象 该行代码包含着所有包括link元素和style元素的样式表console.log(document.styleSheets[0].cssRules); //CSSRuleList对象 该行代码包含着第一个样式表中的所有规则console.log(document.styleSheets[0].cssRules[0]); //CSSStyleRule对象 该行代码表示第一个样式表中的第一条规则 可通过cssText属性访问
CSSRule对象表示样式表中的每一条规则:
cssText:返回整条规则对应的文本;IE不支持;
parrentRule:如果是导入的规则,这个属性引入的就是导入规则否则为null;
parentStyleSheet:当前规则所属的样式表,IE不支持;
selectorText:返回当前规则的选择符文本;
style:可以通过它设置和取得规则中特性的样式值;是一个CSSStyleDeclaration对象;
type:规则类型的常量值,对于样式规则,这个值是1;IE不支持;
比较常用的属性是:cssText、selectorText、style。另外,cssText是只读的,但是style.cssText则是读写的。
以下面的代码为例:
<style>#myDiv { background-color: blue; width: 100px; height: 200px;}p { color: red;}</style>
script代码如下:
var sheet = document.getElementsByTagName("style")[0].sheet; //获得第一个stylesheetvar rule = sheet.rules[0]; //获得该样式表中第一条规则console.log(rule.cssText); //#myDiv { width: 100px; height: 200px; background-color: blue; }(获得该规则对应的文本)console.log(rule.selectorText); //#myDiv(该规则的选择符文本)console.log(rule.style); //CSSStyleDeclarationconsole.log(rule.style[0]); //background-color(取得该规则中特定的样式值)console.log(rule.style[1]); //width
另外,可以用style的方式修改样式信息:
var sheet = document.getElementsByTagName("style")[0].sheet;var targetRule = sheet.rules[0];targetRule.style.height = "300px";
创建规则
insertRule()
方法,向现有样式表中添加新规则;接收两个参数:规则文本和插入规则的索引。IE8及更早的的浏览器支持类似的方法:addRule()
,接收两个必选参数:选择符文本、CSS样式信息和一个可选参数:插入规则的位置;
删除规则
deleteRule()
方法,接收一个参数:要删除的规则的位置,IE中用removeRule()
方法
元素大小
DOM中没有规定如何确定页面中元素的大小,IE为此率先引入了一些属性。
偏移量
offsetHeight:垂直方向上占用的空间大小;
offsetWidth:水平方向上占用的空间大小;
offsetLeft:左外边框至包含元素的左内边框之间的像素距离;
offsetTop:上外边框至包含元素的上内边框之间的像素距离;
如下面的div元素:
<style>* { padding: 0; margin: 0;}</style><div id="myDiv" style="background-color:red;height:100px;width:80px;border:1px solid gray;margin:10px;margin-top:20px;padding:10px;padding-left:20px"></div>
script:
var div = document.getElementById("myDiv");console.log(div.offsetHeight); //122 包括了100px的高度、2个1px的border、2个10px的padding,共122pxconsole.log(div.offsetWidth); //112 包括了80px的高度、2个1px的border、1个10px的padding和1个20px的padding-left,共112pxconsole.log(div.offsetLeft); //10 包括了10px的marginconsole.log(div.offsetTop); //20 包括了20px的margin-top
对块级元素来说,offsetTop、offsetLeft、offsetWidth 及 offsetHeight 描述了元素相对于 offsetParent 的边界框。
offsetParent
属性,该属性不一定与parentNode值相等,可能是body也有可能是table;要想知道某个元素在页面上的偏移量,用下面函数:
<body> <div style="margin-top:10px;margin-left:20px;padding-top:20px;padding-left:10px;width:200px;height:200px;background-color:gray;"> <div id="myDiv" style="background-color:red;height:100px;width:80px;border:1px solid gray;margin:10px;margin-top:20px;padding:10px;padding-left:20px"></div> </div> <table id="myTable" style="margin:25px;border:1px solid gray;" cellspacing=0;> <tr><th>th1</th><th>th2</th> </tr> <tr><td>td1</td><td>td2</td> </tr> </table> <script> var div = document.getElementById("myDiv"); function getElementLeft(element) { var actualLeft = element.offsetLeft; var currentParent = element.offsetParent; while (currentParent !== null) {actualLeft += currentParent.offsetLeft;currentParent = currentParent.offsetParent; } return actualLeft; } console.log(getElementLeft(div)); //40 var data = document.getElementById("myTable").getElementsByTagName("td")[0]; console.log(getElementLeft(data)); //25 console.log(data.offsetLeft); //0 </script></body>
对于使用表格和内嵌框架布局的页面,不同浏览器实现这些元素的方式不同,得到的值不会太准确。
客户区大小
指的是内容及内边距所占据的空间大小:clientWidth、clientHeight;如:
<div id="myDiv" style="background-color:red;height:100px;width:80px;border:1px solid gray;margin:10px;margin-top:20px;padding:10px;padding-left:20px"></div>console.log(div.clientHeight); //120 height加上padding,不包括margin和borderconsole.log(div.clientWidth); //110 width加上padding,不包括margin和border
又如使用该属性取得浏览器视口大小:
var div = document.getElementById("myDiv");function getViewport() { if (document.compatMode == "BackCompat") { return {width: document.body.clientWidth,height: document.body.clientHeight }; } else { return {width: document.documentElement.clientWidth,height: document.documentElement.clientHeight }; }}console.log(getViewport()); //{width: 1280 height: 913}
滚动大小
指的是包含滚动内容的元素的大小:
scrollHeight:在没有滚动条的情况下,元素内容的总高度;
scrollWidth:在没有滚动条的情况下,元素内容的总宽度;
scrollLeft:被隐藏在内容区域左侧的像素数;
scrollTop:被隐藏在内容区域上方的像素数;
如:
#pId{ width: 100px; height: 100px; border: 1px solid gray; overflow: scroll; }<p id="pId" class="info">thisisamessage.thisisamessage.thisisamessage. thisisamessage.thisisamessage. thisisamessage. thisisamessage. thisisamessage. thisisamessage.thisisamessage. thisisamessage.thisisamessage.thisisamessage.thisisamessage.thisisamessage.thisisamessage.thisisamessage.</p>var x = document.getElementById("pId");var t = setTimeout(echoo, 1000);function echoo() { console.log(x.scrollLeft); var y = setTimeout(echoo, 1000);}
另外,带有垂直滚动条的页面总高度就是document.documentElement.scrollHeight
。
在不包含滚动条的页面而言,scrollWidth和scrollHeight与clientWidth和clientHeight之间的关系并不是分清晰。一些浏览器会出现不一致问题,如:
Firefox 中这两组属性是相等的,大小代表的是文档内容区域的实际尺寸,非视口尺寸;
Opera、Safari >= 3.1、Chrome中这两组属性是有差别的,s...是视口大小,c...是文档内容区域的大小;
IE在标准模式下,s...是内容区域大小,c...是视口大小;
要确定文档的总高度时,必须取得s...或c...之间的最大值(Math.max),如:
var docHeight = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight);console.log(docHeight); //913var docWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.scrollWidth);console.log(docWidth); //1280
下面的函数会检测元素是否位于顶部,如果不是就会将其自动滚到顶部:
#pId{ width: 150px; height: 200px; border: 1px solid gray; overflow: scroll; }<p id="pId">HTMLElement.offsetParent 是一个只读属性,返回一个指向最近的(closest,指包含层级上的最近)包含该元素的定位元素。如果没有定位的元素,则 offsetParent 为最近的 table 元素对象或根元素(标准模式下为 html;quirks 模式下为 body)。当元素的 style.display 设置为 "none" 时,offsetParent 返回 null。offsetParent 很有用,因为 offsetTop 和 offsetLeft 都是相对于其内边距边界的。</p><input type="button" value="scroll to top" id="stt">var pElem = document.getElementById("pId");var btn = document.getElementById("stt");btn.onclick = scrollToTop;function scrollToTop() { if (pElem.scrollTop !== 0) { pElem.scrollTop = 0; }}
确定元素大小
getBoundingClientRect()
方法会返回一个矩形对象,包含4个属性:left、top、right和bottom:
var p = document.getElementById("divId");console.log(p.getBoundingClientRect().right); //110console.log(p.getBoundingClientRect().left); //10console.log(p.getBoundingClientRect().top); //10console.log(p.getBoundingClientRect().bottom); //60
注意:IE、Firefox3+、Opera9.5、Chrome、Safari支持,在IE中,默认坐标从(2,2)开始计算,导致最终距离比其他浏览器多出两个像素,我们需要做个兼容。
document.documentElement.clientTop; // 非IE为0,IE为2document.documentElement.clientLeft; // 非IE为0,IE为2functiongGetRect(element) { var rect = element.getBoundingClientRect(); var top = document.documentElement.clientTop; var left = document.documentElement.clientLeft; return { top: rect.top - top, bottom: rect.bottom - top, left: rect.left - left, right: rect.right - left }}