本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
JavaScript也可以针对CSS进行编程,也就是所谓的脚本化CSS;通过脚本化CSS,同样可以达到一系列的视觉效果;
在HTML中定义样式的方式有3种:通过<link>元素包含外部样式表文件、使用<style>元素定义嵌入式样式、以及使用style特性定义特定元素的内联样式;
DOM2级样式模块围绕这3种应用样式的机制提供了一套API,可以检测浏览器支持DOM2级定义的CSS能力;
var supportsDOM2CSS = document.implementation.hasFeature("CSS","2.0");var supportsDOM2CSS2 = document.implementation.hasFeature("CSS2","2.0");
脚本化内联样式:
脚本化CSS最简单直接的方式就是更改文档元素的style属性;任何支持style特性的HTML元素在Javascript中都有一个对应的style属性,这个style属性比较特殊,它不是字符串,而是一个CSSStyleDeclaration对象,包含着通过HTML的style特性指定的所有样式信息,但不包含从外部样式表或嵌入样式表经层叠而来的样式;
var mydiv = document.getElementById("mydiv");console.log(mydiv.style); // CSSStyleDeclarationmydiv.style.fontSize = "24px";mydiv.style.color = "purple";
style属性作为CSSStyleDeclaration对象,其就代表了内联样式,其保存了所有的样式属性,但如果元素没有设置style特性或没有使用脚本设置该特性,style中的样式属性值均为空字符串;
只要取得一个有效的DOM元素的引用,就可以随时使用Javascript为其设置样式;
var myDiv = document.getElementById("myDiv");myDiv.style.backgroundColor = "red";myDiv.style.width = "100px";myDiv.style.height = "200px";myDiv.style.border = "1px solid black";
以这种方式改变样式时,元素的外观会自动被更新;
通过style对象,同样可以取得style特性中指定的样式;
var mydiv = document.getElementById("mydiv");console.log(mydiv.style.backgroundColor);console.log(mydiv.style.width);console.log(mydiv.style.height);
脚本化的CSS属性的名称和值:
在style特性中指定的任何CSS属性都将表现为这个style对象的相应属性;对于使用短划线的CSS属性名,必须将其转换成驼峰大小写形式,才能通过js来访问,如:
CSS属性 JS属性background-imagestyle.backgroundImagecolor style.colordisplay style.displayfont-family style.fontFamily
多数情况下,都可以通过简单地转换属性名的格式来实现转换,但是,当一个CSS属性名在Javascript中如果是保留字或关键字时,在其前加”css”前缀,例如float属性,由于float是JS中的保留字,因此不能被用作属性名,其值应为cssFloat;低版本IE支持styleFloat;
mydiv.style.backgroundColor = "purple";mydiv.style.borderRightStyle = "solid";mydiv.style.borderRightColor = "green";mydiv.style.cssFloat = "left";mydiv.style.styleFloat = "left";
通过CSSStyleDeclaration对象设置style属性值时,值都应该是字符串,都应该放到引号内,并且不带分号;
在标准模式下,所有度量值都必须指定一个度量单位;在混合模式下,可以省略单位;
mydiv.style.width = 300; // 错误,但在混杂模式下默认为300pxmydiv.style.width = "300"; // 错误,但在混杂模式下默认为300px
通过计算得来的值,也要在最后加上单位;
var x = 10, leftMargin=20, leftBorder=10;mydiv.style.left = (x + leftMargin + leftBorder) + "px";
带单位唯一不好的地方就是,如果要获取这个值,参与其他的数学运算,因为其是字符串,所以不能直接使用,必须转换为数值才能参与运算,例如使用parseInt()或parseFloat()等方法进行转换;
var rect = mydiv.getBoundingClientRect();console.log(rect);var borderWidth = parseFloat(mydiv.style.width);console.log(borderWidth);
一些CSS属性是复合属性,比如:margin就是margin-top、margin-right、margin-bottom、margin-left的复合属性;CSSStyleDeclaration对象也有与之对应的复合属性;
mydiv.style.margin = "20px 30px 40px 50px";mydiv.style.marginTop = "50px";mydiv.style.marginLeft = "50px";
当设置复合属性margin时,其会自动计算其所对应的相关联的属性;
即然style是元素的特性,那么也可以通过setAttribute()、getAttribute()等方法来设置style特性;
mydiv.setAttribute("style","width: 300px; height:200px; background-color: purple;");console.log(mydiv.style);console.log(mydiv.getAttribute("style"));
style对象的属性和方法:
style对象中还定义一些属性和方法,这些属性和方法在提供元素的style特性值的同时,也可以修改样式;
cssText:能够访问到style特性中的CSS代码;
length:应用给元素的CSS属性的数量;
parentRule:表示CSS信息的CSSRule对象;
getPropertyCSSValue(propertyName):返回包含给定的属性的值CSSValue对象;已废弃;
getPropertyPriority(propertyName);如果给定的属性使用了!important设置,则返回important;否则返回空字符串;
getPropertyValue(propertyName):返回给定的属性的值;
item(index):返回给定位置的CSS属性的名;
removeProperty(propertyName):从样式中删除给定的属性;
setProperty(propertyName,value,priority):为给定的属性设置为属性值,并加上优先权标志(”important”或一个空字符串);
cssText属性:返回浏览器对style特性中CSS代码的内部表示,在写入模式下,赋给cssText的值会重写整个style特性的值;
mydiv.style.cssText = "width: 300px; height:200px; background-color: purple;";console.log(mydiv.style.cssText);console.log(mydiv.getAttribute("style"));
设置cssText属性的目的就是为元素快速应用多个CSS特性,可以一次性应用所有的变化;
item()方法和length属性:设计length属性的目的,就是将其与item()方法配套使用,以便迭代元素中定义的CSS属性名;在使用length和item()时,style对象实际上是一个集合,可以使用方括号来代替item()来取得给定位置的css属性名;
console.log(mydiv.style.length);for(var i=0; i<mydiv.style.length; i++){ // console.log(mydiv.style.item(i)); console.log(mydiv.style[i]);}
getPropertyValue(propertyName)方法:取得给定的属性的值;
console.log(mydiv.style.getPropertyValue("background-color"));for(var i=0; i<mydiv.style.length; i++){ var prop = mydiv.style[i]; // 取得属性名 var value = mydiv.style.getPropertyValue(prop); // 取得属性值 console.log(prop + ":" + value);}
getPropertyCSSValue(propertyName)方法:该方法会返回一个包含两个属性的CSSValue对象,这两个属性分别是:cssText和cssValueType,其中cssText属性的值与getPropertyValue()方法返回的值相同,而cssValueType属性则是一个数值常量,表示值的类型:0表示继承的值,1表示基本的值,2表示值列表,3表示自定义的值;
var value = mydiv.style.getPropertyCSSValue("background-color");console.log(value);console.log(value.cssText);console.log(value.cssValueType);
这个方法已经被废弃了,几乎所有的浏览器都不支持;
getPropertyPriority(propertyName);如果给定的属性使用了!important设置,则返回important;否则返回空字符串;
console.log(mydiv.style.getPropertyPriority("background-color")); // important
setProperty(propertyName,value,priority):为给定的属性设置为属性值,并加上优先权标志,priority 为可选(”important”或一个空字符串);
mydiv.style.setProperty("background-color","purple","important");
removeProperty(propertyName)方法:可以从元素的样式中移除某个CSS属性,移除一个属性,意味着该属性将应用默认的样式(从其他样式表经层叠而来);
mydiv.style.removeProperty("background-color");
parentRule:只读,表示CSS信息的CSSRule对象;
var rule = mydiv.style.parentRule;console.log(rule); // null
计算的样式:
虽然style对象能够提供style特性所有样式信息,但它不包含那些从其他样式表层叠而来并影响到当前元素的实际样式信息;所以,需要使用计算样式;
计算样式是一组属性值,它由浏览器通过把内联样式结合所有链接样式表中所有可应用的样式规则后导出(计算)得到的,也就是一组在呈现元素时实际使用的属性;
getComputedStyle()方法:
该方法是window对象的方法,可以通过window.getComputedStyle(),或者document.defaultView.getComputedStyle()方法调用,而document.defaultView的返回值就是window;
该方法接受两个参数:要取得计算样式的元素和一个伪元素字符串(如::after);如果不需要伪元素,第二个参数可以为null或一个空字符串;该方法返回一个CSSStyleDeclaration对象,与style属性的类型相同,区别在于它是只读的,其中包含当前元素的所有计算的样式;
<style> #mydiv{background-color: purple; width: 100px; height: 100px;}</style><div id="mydiv" >mydiv</div><script>var mydiv = document.getElementById("mydiv");var computedStyle = document.defaultView.getComputedStyle(mydiv,null);console.log(computedStyle);console.log(computedStyle.backgroundColor);console.log(computedStyle.width);console.log(computedStyle.height);console.log(computedStyle.border);</script>
注:以上border属性可能不会返回实际的border规则(如IE和Firefox返回空字符串),原因是不同浏览中解释复合属性的方式不同,因为设置这种属性实际上会涉及很多其他属性,例如:border,实际上调协了四个边的边框宽度、颜色等,因此border不会返回,但computedStyle.borderleftWidth会返回值;
console.log(computedStyle.borderLeftWidth);console.log(computedStyle.borderLeftColor);
另外,不同浏览器表示值的方式可能会有所区别;
计算后的样式也包含属于浏览器内部样式表的样式信息,因此任何具有默认值的CSS属性都会表现在计算后的样式中;如visibility属性都有一个默认值,有些浏览器设置为visible,而有些设置为inherit;
计算样式的CSSStyleDeclaration对象和表示内联样式的对象之间有一些重要的区别:
计算样式的属性是只读的;
计算样式的值是绝对值,类似百分比和点之类的相对的单位将全部转换为绝对值;所有指定尺寸,例如外边距大小和字体大小等属性都有一个以像素为度量单位的值;相关颜色的属性将以”rgb(#,#,#)”或”rgba(#,#,#,#)”的格式返回;
不计算复合属性,它们只基于最基础的属性,例如,不要查询margin属性,应该使用marginLeft或marginTop等;
计算样式的cssText属性未定义(也就是该属性返回空字符串);
计算样式和内联样式可以同时使用;
// 用指定的因子缩放元素e的文本尺寸function scale(e, factor){ // 用计算样式查询当前文本的尺寸 var size = parseInt(window.getComputedStyle(e,"").fontSize); // 用内联样式来放大尺寸 e.style.fontSize = factor * size + "px";}// 用指定的因子修改元素的背景颜色// factors > 1 颜色变浅,factors < 1颜色变暗function scaleColor(e, factor){ var color = window.getComputedStyle(e,"").backgroundColor; var components = color.match(/[\d\.]+/g); // 解析r、g、b分量 for(var i=0; i<3; i++){ // 循环r,g,b var x = Number(components[i]) * factor; // 缩放每个值 x = Math.round(Math.min(Math.max(x, 0), 255)); // 设置边界并取整 components[i] = String(x); } if(components.length == 3) // rgb()颜色 e.style.backgroundColor = "rgb(" + components.join() + ")"; else // rgba()颜色 e.style.backgroundColor = "rgba(" + components.join() + ")";}var mydiv = document.getElementById("mydiv");scale(mydiv, 1.5);scaleColor(mydiv, .5);
低版本的IE不支持getComputedStyle()方法,但它有一种类似的概念;在IE中,具有style属性的元素还有一个currentStyle属性,该属性是CSSStyleDeclaration的实例,包含当前元素全部计算后的样式,但只有IE支持;
var computedStyle = mydiv.currentStyle;console.log(computedStyle.backgroundColor);console.log(computedStyle.width);console.log(computedStyle.height);console.log(computedStyle.borderLeftWidth);
兼容函数:
function getStyle(obj, attr){ if(window.getComputedStyle) return getComputedStyle(obj, null)[attr]; else return obj.currentStyle[attr];}var mydiv = document.getElementById("mydiv");var backgroundColor = getStyle(mydiv, "background-color");console.log(backgroundColor); // rgb(245, 222, 179)// 或者function getCss(obj, css){ return (document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(obj,null) : obj.currentStyle)[css];}var borderTopWidth = getCss(mydiv, "border-top-width");console.log(borderTopWidth); // 1px
封装一下函数,用来获取CSS属性值,如:
function getComputedStyles(elem,prop) { var cs = window.getComputedStyle(elem,null); if (prop) { console.log(prop+" : "+cs.getPropertyValue(prop)); return; } var len = cs.length; for (var i=0;i<len;i++) { var style = cs[i]; console.log(style+" : "+cs.getPropertyValue(style)); }}getComputedStyles(mydiv); // 查询所有getComputedStyles(mydiv,"background-color"); // 只查询一个属性
与伪元素一起使用:getComputedStyle可以从伪元素中提取样式信息(例如:::after, ::before, ::marker, ::line-marker);
<style> #mydiv::after{content: "大师哥王唯";}</style><div id="mydiv"></div><script>var mydiv = document.getElementById("mydiv");var computedStyle = document.defaultView.getComputedStyle(mydiv,":after");console.log(computedStyle.content);<script>
使用计算样式是可以获取元素的几何尺寸和位置的,但是其获得的结果并不一定是我们所期望的,此时可以使用getBoundingClientRect(),其返回的值是与呈现的效果是一致的;
console.log(computedStyle.left); // autoconsole.log(computedStyle.top); // autoconsole.log(computedStyle.width); // 300px// left:8 top:8 width:302,包括了bordervar rect = mydiv.getBoundingClientRect();console.log(rect);
脚本化CSS类:
也可以脚本化元素的class属性,改变元素的class就改变了应用于元素的一组样式表选择器,它能在同一时刻改变多个CSS属性;
className属性:
与元素的class特性对应,即为元素指定的CSS类;由于class是ECMAScript保留字,所以在Javascript中使用className;
在操作类名时,需要通过className属性添加、删除和替换类名;
var mydiv = document.getElementById("mydiv");mydiv.className = "container"; // 设置mydiv.className = ""; // 删除mydiv.className = "other"; // 替换// 或if(mydiv.className == ""){ mydiv.className = "container";}
元素可以设置多个CSS类,其className中保存的是拥有多个类名的字符串,因此即使只修改字符串一部分,都会覆盖之前的值,所以每次都必须设置整个字符串的值;
var mydiv = document.getElementById("mydiv");console.log(mydiv.className); // db user disablemydiv.className = "container";console.log(mydiv.className); // container
如果要从class中只删除一个类名,需要把多个类名拆开,删除不想要的那个,然后再把其他类名拼成一个新字符串,如:
// 如,删除user类// 首先,取得类名字符串并拆分成数组var mydiv = document.getElementById("mydiv");var classNames = mydiv.className.split(/\s+/);// 找到要删的类名var pos = -1, i, len;for(i=0, len = classNames.length; i<len; i++){ if(classNames[i] == "user"){ pos = i; break; }}// 删除类名classNames.splice(i,1);// 把剩下的类名拼成字符串并重新设置mydiv.className = classNames.join(" ");
如果要添加类名,是可以直接通过拼接字符串完成,但在拼接之前,必须要通过检测确定不会多次添加相同的类名;
Element.classList属性:
HTML5新增了一种操作类名的方式,可以让操作更简单也更安全,即classList属性,其是一个DOMTokenList对象,其是只读的类数组对象,与其他DOM集合类似,它也有一个表示自己包含多少个元素的length属性,而要取得每个元素可以使用item()方法,也可以使用方括号语法,此外,这个新类型还定义如下的方法:
add(value):将给定的字符串值添加到列表中,如果值存在,就不添加;contains(value):表示列表中是否存在给定的值,如果存在返回true,否则,返回false;remove(value):从列表中删除给定的字符串;toggle(value):如果列表中已经存在给定的值,删除它,否则,添加它;console.log(mydiv.classList); // DOMTokenListmydiv.classList.add("container");mydiv.classList.remove("container");
使用classList,可以确保其他类名不受此次修改的影响,可以极大地减少类似的基本操作的复杂性;
mydiv.classList.toggle("user"); // 切换user类// 确定元素中是否包含既定的类名if(mydiv.classList.contains("bd") && !mydiv.classList.contains("disabled")){ // To Do }// 迭代类名for(var i=0,len=mydiv.classList.length; i<len; i++){ // To Do console.log(mydiv.classList[i]);}
有了classList属性,除非需要全部删除所有类名,或者完全重写元素的class属性,否则也就用不到className了;
需要确定的一点,classList这个DOMTokenList对象,它是实时的,如果className属性改变了,它也会及时更新,同样的,classList改变了,className属性也会及时更新;
IE9以下的浏览器不支持classList属性,可以自定义一个CSSClassList类,模拟DOMTokenList对象的方法;
function classList(e){ // 以下两行先注释,否则后面的toArray默认调用的是DOMTokenList对象的的toArray,而它并不存在 // 或者扩展内置的DOMTokenList的toArray // if(e.classList) return e.classList; // 如果e.classList存在,则返回它 // else return new CSSClassList(e); // 否则,说伪造一个 return new CSSClassList(e);}// CSSClassList是一个模拟DOMTokenList的对象function CSSClassList(e) { this.e = e;}// 如果e.className包含类名c则返回true,否则返回falseCSSClassList.prototype.contains = function(c){ // 检查c是否是合法的类名 if(c.length === 0 || c.indexOf(" ") != -1) throw new Error("Invalid class name: '" + c + "'"); // 首先是常规检查 var classes = this.e.className; if(!classes) return false; // e不含类名 if(classes === c) return true; // e有一个完全匹配的类名 // 否则,把c自身看做一个单词,利用正则表达式搜索c return classes.search("\\b" + c + "\\b") != -1;};// 如果c不存在,将c添加到e.className中CSSClassList.prototype.add = function(c){ if(this.contains(c)) return; // 如果存在,什么也不做 var classes = this.e.className; if(classes && classes[classes.length - 1] != " ") c = " " + c; // 如果需要加一个空格 this.e.className += c; // 将c添加到className中};// 将在e.className中出现的所有c都删除CSSClassList.prototype.remove = function(c){ if(c.length === 0 || c.indexOf(" ") != -1) throw new Error("Invalid class name: '" + c + "'"); // 将所有作为单词的c和多余的尾随空格全部删除 var pattern = new RegExp("\\b" + c + "\\b\\s*", "g"); this.e.className = this.e.className.replace(pattern, "");};// 如果c不存在,将c添加到e.className中,并返回true// 否则,将e.className中出现的所有c都删除,并返回falseCSSClassList.prototype.toggle = function(c){ if(this.contains(c)){ // 如果e.className包含类名c thsi.remove(); // 删除它 return false; }else{ this.add(c); // 添加 return true; }};// 返回e.className本身CSSClassList.prototype.toString = function(){ return this.e.className;};// 返回在e.className中的类名CSSClassList.prototype.toArray = function(){ return this.e.className.match(/\b\w+\b/g) || [];};// 应用var mydiv = document.getElementById("mydiv");var ccl = classList(mydiv);console.log(ccl);console.log(ccl.contains("newsdiv")); // trueccl.add("topDiv");ccl.remove("newsdiv");ccl.toggle("newsdiv");console.log(ccl.toString());console.log(ccl.toArray());
脚本化样式表:
在脚本化样式表时,会使用到两种类型的对象:
第一类是元素对象,包括通过<link>元素包含的样式表和在<style>元素中定义的样式表,这两个元素本身是常规的文档元素,分别是由HTMLLinkElement和HTMLStyleElement类型表示,它们都可以修改元素的特性,如果它们有id,可以通过getEleementById()来获取它们;
// var mylink = document.getElementById("mylink");var mylink = document.getElementsByTagName("link")[0];console.log(mylink);var mystyle = document.getElementsByTagName("style")[0];console.log(mystyle);
所有浏览器都会包含<style>元素和rel特性被设置为stylesheet的<link>元素引入的样式表;
第二类是CSSStyleSheet类型,表示样式表本身;通过document.styleSheets属性会返回一个只读的类数组StyleSheetList对象集合,该集合具有length属性和item()方法,集合内保存着CSSStyleSheet对象,表示与文档关联在一起的样式表;
var styleList = document.styleSheets;console.log(styleList); // StyleSheetListconsole.log(styleList.length); // 3console.log(styleList[0]); // CSSStyleSheet// 遍历var sheet = null;for(var i=0, len=document.styleSheets.length; i<len; i++){ sheet = document.styleSheets[i]; console.log(sheet.href);}
可以直接通过HTMLLinkElement(<link>)或HTMLStyleElement(<style>)元素的sheet属性获取CSSStyleSheet对象;低版本的IE不支持sheet,但提供了一个同样作用的styleSheet属性;
var mylink = document.getElementById("mylink");var mylink = document.getElementsByTagName("link")[0];console.log(mylink.sheet); // CSSStyleSheetconsole.log(mylink.styleSheet); // 在低版本的IE中返回CSSStyleSheetvar mystyle = document.getElementsByTagName("style")[0];console.log(mystyle.sheet); // CSSStyleSheetconsole.log(mystyle.styleSheet); // 在低版本的IE中返回CSSStyleSheet
兼容处理:
function getStyleSheet(element){ return element.sheet || element.styleSheet;}var link = document.getElementsByTagName("link")[0];var sheet = getStyleSheet(link);console.log(sheet.href);
在使用之前,检测浏览器是否支持DOM2级样式表;
var supportsDOM2StyleSheet = document.implementation.hasFeature("StyleSheets","2.0");
CSSStyleSheet对象:
接口代表一个 CSS 样式表,并允许检查和编辑样式表中的规则列表;其继承自StyleSheet接口,后者可以作为一个基础接口来定义非CSS样式表;从接口继承的属性如下:
disabled:表示样式表是否被禁用的布尔值,R/W,将这个值设置为true可以禁用样式表;
var styleList = document.styleSheets;var ss = styleList[2];console.log(ss.disabled);ss.disabled = true; // 元素的样式失效// 封装一个小函数,用来开启或关闭样式表// 如果传递一个数字,将其当做document.styleSheets对象中一个索引// 如果传递一个字符串,将其当作CSS选择器并传递给document.querySelectorAll()function disableStyleSheet(ss){ if(typeof ss === "number") document.styleSheets[ss].disabled = true; else{ var sheets = document.querySelectorAll(ss); for(var i=0; i<sheets.length; i++) sheets[i].disabled = true; }}disableStyleSheet(0);disableStyleSheet("style");disableStyleSheet("link");
href:如果样式表是通过<link>包含的,则是样式表的URL,否则null;
media:当前样式表支持的所有媒体类型的MediaList类数组集合;与所有DOM集合一样,这个集合也有一个length属性和一个item()方法;如果集合为空,表示样式表适用于所有媒体;
<style media="screen and (min-width: 500px),tv and (max-width: 1000px)"> .container{width:300px;height:200px;background-color: salmon;}</style><script>var styleList = document.styleSheets;var ss = styleList[2];console.log(ss.media); // MediaListconsole.log(ss.media.length); // 2console.log(ss.media[0]); // screen and (min-width:500px)console.log(ss.media.item(1)); // tv and (max-width:1000px)
MediaList对象还拥有mediaText属性,返回元素media特性的值;
console.log(ss.media.mediaText);
MediaList对象拥有appendMedium(medium)和deleteMedium()方法,分别用作添加和删除媒介;
ss.media.appendMedium("print");ss.media.deleteMedium("tv and (max-width:1000px)");
一般来说,很少去操作media属性;
ownerNode:指向拥有当前样式表的节点的指针,样式表可能是在HTML中通过<link>或<style>引入的,如果样式表是其他样式表是通过@import导入的,该属性值为null,低版本IE不支持该属性;
console.log(styleList[0].ownerNode); // linkconsole.log(styleList[1].ownerNode); // style
parentStyleSheet:在当前样式表是通过@import导入的情况下,该属性是一个指向导入它的样式表的指针;
// styleList[1]获取的是一个<style>其中使用@import导入一个CSS文件console.log(styleList[1].cssRules[0]); console.log(styleList[1].cssRules[0].parentStyleSheet); // CSSStyleSheet
title:ownerNode中title属性的值;
type:表示样式表类型的字符串,对CSS样式表而言,是”text/css”;
注:除了disabled属性之外,其他属性都是只读的;
操作样式表规则:
除了以上所有这些属性,CSSStyleSheet类型还定义了用来查询、插入和删除样式表规则的API;
cssRules:返回样式表中包含的所有样式规则的CSSRuleList类型的实时集合,该集合中的元素为CSSStyleRule对象;低版本的IE不支持,但有个类似的rules属性;
var ss = styleList[1];console.log(ss);console.log(ss.cssRules);console.log(ss.rules); // 是IE专用console.log(ss.cssRules[0]); // CSSStyleRule
ownerRule:如果样式表是通过@import导入的,该属性就是一个指针,返回表示导入的规则的CSSImportRule对象,否则为null,低版本的IE不支持;
insertRule(rule, index):创建(插入)规则,向CSSRules集合中指定的位置插入rule字符串,该方法接受两个参数:规则文本和表示在哪里插入规则的索引;
var sheet = document.styleSheets[1];sheet.insertRule("body{background-color:silver}",0);console.log(sheet.cssRules);
低版本的IE支持一个类似的addRule(selector, style, index)方法,接受两个必选和一个可选参数:选择器和CSS样式信息,一个可选参数:插入规则的位置;
document.styleSheets[1].addRule("h1","font-size:3em;color:red;",2);console.log(document.styleSheets[1].cssRules);
这个方法所有浏览器也都支持;
跨浏览器方式:
var sheet = document.styleSheets[0];function insertRule(sheet, selectorText, cssText, position){ if(sheet.insertRule){ sheet.insertRule(selectorText + "{" + cssText + "}", position); }else{ sheet.addRule(selectorText, cssText, position); }}insertRule(sheet, "body", "background-color:silver", 0);
deleteRule(index):删除cssRules集合(样式表)中指定位置的规则;低版本的IE不支持,但支持一个类似的removeRule()方法,这个方法所有浏览器也都支持;
document.styleSheets[1].deleteRule(0);document.styleSheets[1].removeRule(0);console.log(document.styleSheets[1].cssRules);
跨浏览器方式:
var sheet = document.styleSheets[0];function deleteRule(sheet, index){ if(sheet.deleteRule){ sheet.deleteRule(index); }else{ sheet.removeRule(index); }}deleteRule(sheet,0);
CSSStyleRule规则对象:
CSSStyleRule对象表示样式表中的每一条规则;继承自CSSRule接口,实际上CSSRule是专供其他类型继承的基类,其中最常见的是CSSStyleRule类型,表示样式信息;
var sheet = document.styleSheets[2];var rules = sheet.cssRules || sheet.rules;var rule = rules[0];console.log(rule); // CSSStyleRule
CSSRule接口属性:
cssText:返回整条规则对应的文本;低版本的IE不支持parentRule:只读,如果当前规则是导入的规则,这个属性引用的就是导入规则,否则为null;或此规则是 @media 块中的样式规则, 则其父规则将是该 CSSMediaRule;IE不支持parentStyleSheet:当前规则所属的样式表,低版本的IE不支持;type:表示规则类型的常量值,对于样式规则,值为1;IE不支持;
这些常量被定义在CSSRule接口中,值为:
常量值接口
CSSRule.STYLE_RULE1CSSStyleRuleCSSRule.IMPORT_RULE3CSSImportRuleCSSRule.MEDIA_RULE4CSSMediaRuleCSSRule.FONT_FACE_RULE5CSSFontFaceRuleCSSRule.PAGE_RULE6CSSPageRuleCSSRule.KEYFRAMES_RULE7CSSKeyframesRuleCSSRule.KEYFRAME_RULE8CSSKeyframeRule9 保留供将来使用CSSRule.NAMESPACE_RULE10CSSNamespaceRuleCSSRule.COUNTER_STYLE_RULE11CSSCounterStyleRuleCSSRule.SUPPORTS_RULE12CSSSupportsRuleCSSRule.DOCUMENT_RULE13CSSDocumentRuleCSSRule.FONT_FEATURE_VALUES_RULE14CSSRule.VIEWPORT_RULE15CSSViewportRuleCSSRule.REGION_STYLE_RULE16CSSRegionStyleRuleCSSRule.UNKNOWN_RULE0CSSUnknownRuleCSSRule.CHARSET_RULE2CSSCharsetRule
CSSStyleRule对象属性:
selectorText:只读,返回当前规则的选择器;style:只读,返回一个CSSStyleDeclaration对象,可以通过它设置和取得规则中特定的样式值;styleMap:一个StylePropertyMap对象;console.log(rule.cssText); // 定义规则的字符串console.log(rule.parentRule);console.log(rule.parentStyleSheet); // CSSStyleSheetconsole.log(rule.selectorText); // 选择器console.log(rule.style); // CSSStyleDeclarationconsole.log(rule.styleMap); // StylePropertyMapconsole.log(rule.type); // 1
最常用的是cssText、selectorText和style这三个属性;cssText属性与style.cssText属性类似,但并不相同,前者包含选择器和围绕样式信息的花括号,后者只包含样式信息;cssText是只读的,style.cssText是可写的;
console.log(rule.cssText); // .container{color:white}console.log(rule.style.cssText); // color:whiterule.style.cssText = "background-color:purple";console.log(rule.cssText); // .container{background-color:purple;}console.log(rule.style.cssText); // background-color:purplerule.style.cssText += "color:white;";
大多数情况下,仅使用style属性就可以满足所有操作样式规则的需求了;这个对象就像每个元素上的style属性一样,可以通过它读取和修改规则中的样式信息;
console.log(rule.style.width);console.log(rule.style.height);rule.style.backgroundColor = "lightgray";console.log(rule.style.cssText);
CSSStyleRule对象的style属性,使用方式和内联style对象的使用方式是一致的,但要注意,一个是规则对象的style属性对象,一个是内联style对象;
// 遍历样式表的规则var ss = document.styleSheets[0]; // 第一个样式表var rules = ss.cssRules ? ss.cssRules : ss.rules; // 样式表规则for(var i=0; i<rules.length; i++){ var rule = rules[i]; if(!rule.selectorText) continue; // 跳过@import和非样式规则 var selector = rule.selectorText; // 选择器 var ruleText = rule.style.cssText; // 文本形式的样式 // 如果规则应用在h1元素上,也将其应用到h2元素上 // 注意,仅当选择器在字面上为h1时这才起作用 if(selector == "h1"){ if(ss.insertRule) ss.insertRule("h2 {" + ruleText + "}", rules.length); else if(ss.addRule) ss.addRule("h2", ruleText, rules.length); } // 如果规则设置了text-decoration属性,则将其删除 if(rule.style.textDecoration){ if(ss.deleteRule) ss.deleteRule(i); else if(ss.removeRule) ss.removeRule(i); i--; // 调整循环索引,因为以上的规则i+1现在即为规则i }}
创建新样式表:
可以创建一个新样式表并将其添加到文档中;使用DOM技术,创建一个<style>元素,并将其插入到文档的头部,然后再用其innerHTML属性来设置样式表内容;在低版本的IE中,CSSStyleSheet对象通过非标准方法document.createStyleSheet()来创建,其样式文本用cssText属性值为指定;
// 创建一个新样式表// 对文档添加一个样式表,用指定的样式填充它// style参数可能是字符串或对象,如果它是字符串,就把它作为样式表的文本// 如果它是对象,将每个定义样式规则的每个属性添加到样式表中// 属性名即为选择器,其值即为对应的样式function addStyles(styles){ var styleElt, styleeSheet; // 先创建一个新样式表 if(document.createStyleSheet) // 如果是IE styleSheet = document.createStyleSheet(); else{ var head = document.getElementsByTagName("head")[0]; styleElt = document.createElement("style"); // 新的<style>元素 head.appendChild(styleElt); // 这个新样式表应该是最后一个 styleSheet = document.styleSheets[document.styleSheets.length - 1]; } // 向其中插入样式 if(typeof styles === "string"){ if(styleElt) styleElt.innerHTML = styles; else styleSheet.cssText = styles; // IE }else{ // 参数是规则对象 var i = 0; for(selector in styles){ if(styleSheet.insertRule){ var rule = selector + "{" + styles[selector] + "}"; styleSheet.insertRule(rule, i++); }else{ styleSheet.addRule(selector, styles[selector], i++); } } }}// 应用var styles = "h2 {font-size: 2em; color: red;}";addStyles(styles);var rule = document.styleSheets[1].cssRules[0];addStyles(rule);
CSS动画:脚本化CSS的最常见的用途之一就是产生视觉动画效果;其原理是使用setTimeout()或setInterval()重复调用函数来修改元素的内联样式,以达到产生视觉差的动画效果;
// 将e转化为相对定位的元素,使之左右震动// 第一个参数可以是元素对象也可以是元素的id// 第二个参数是回调函数,将以e为参数,将在动画结束时调用// 第三个参数指定e震动的距离,默认是5px// 第四个参数指定震动多久,默认是500msfunction shake(e, oncomplete, distance, time){ if(typeof e === "string") e = document.getElementById(e); if(!time) time = 500; if(!distance) distance = 5; var originalStyle = e.style.cssText; // 保存e的原始style e.style.position = "relative"; // 使e相对定位 var start = (new Date()).getTime(); // 动画的开始时间 animate(); // 开始动画 // 函数检检查消耗的时间,并更新e的位置 // 如果动画完成,它将e还原为原始状态 // 否则,它更新e的位置,安排它自身重新运行 function animate(){ var now = (new Date()).getTime(); // 得到当前时间 var elapsed = now - start; // 从开始以来消耗了多长时间 var fraction = elapsed / time; // 是总时间的几分之几 if(fraction < 1){ // 如果动画未完成 // 作为动画完成比例的函数,计算e的位置 // 使用正弦函数将完成比例乘以4pi,所以它来回往复两次 var x = distance * Math.sin(fraction * 4 * Math.PI); e.style.left = x + "px"; // 在25ms后或在总时间的最后尝试再次运行函数 // 目的是为了产生每秒40帧的动画 setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.cssText = originalStyle; // 恢复原始样式 if(oncomplete) // 调用回调函数 oncomplete(e); } }}// 应用var mydiv = document.getElementById("mydiv");shake(mydiv,function(e){console.log(e.style)},5,500);// 以毫秒级的时间将e从完全不透明谈出到完全透明// 在调用函数时假设e是完全不透明// oncomplete是一个可选的函数,以e为参数,它将在动画结束时调用// 如果不指定time,默认为500msfunction fadeOut(e, oncomplete, time){ if(typeof e === "string") e = document.getElementById(e); if(!time) time = 500; // 使用Math.sqrt作为一个简单的缓动函数来创建动画 // 非线性,由快到慢 var ease = Math.sqrt; var start = (new Date()).getTime(); // 动画的开始时间 animate(); // 开始动画 function animate(){ var elapsed = (new Date()).getTime() - start; // 消耗时间 var fraction = elapsed / time; // 总时间的几分之几 if(fraction < 1){ // 如果动画未完成 var opacity = 1 - ease(fraction); // 计算元素的不透明度 e.style.opacity = String(opacity); // 设计不透明度 setTimeout(animate, Math.min(25, time - elapsed)); }else{ e.style.opacity = "0"; // 完全透明 if(oncomplete) oncomplete(e); } }}fadeOut(mydiv,null,500);