JavaScript权威指南--脚本化CSS

时间:2022-09-25 08:49:20

 知识要点

JavaScript权威指南--脚本化CSS

客户端javascript程序员对CSS感兴趣的是因为样式可以通过脚本编程。脚本化css启用了一系列有趣的视觉效果。例如:可以创建动画让文档从右侧“滑入”。创造这些效果的javascriptcss技术在以前统称为动态HTML(DHTML).而现在,这个技术术语已经不流行了。

为了理解CSS脚本化,我们必须CSS的基础和最常用的样式属性。

1.CSS概述

HTML的视觉显示包含很多变量:字体,颜色、间距等。css标准列举了这些变量,称为样式属性。

紧跟属性名的是冒号和值。多个属性时用分号隔开。CSS忽略了/* */之间的注释,但是它不支持//后面的注释。

两种方式将一组定义视觉表现的CSS属性和对于的HTML元素关联在一起。第一种是通过给每个单独的HTML元素设置style属性的方式,称为内联样式。

尽管如此,通常将单独的HTML元素和CSS样式表分开,并把他们定义在一个样式表(stylesheet)中会更有用,样式表通过选择器将一组样式属性和使用选择器(selector)描述的一组HTML元素关联在一起。

CSS样式表的基本元素是样式规则,它们由选择器和包裹在一对{}中的css属性和值所组成。每个样式表可以包含任意数量的样式规则。在<style>标签使用或者保存为单独文件并通过<link>引入。

1.1.层叠

回想下,在CSS的“C”代表了“层叠”、该术语指定了应用于文档中任何给定元素的样式规则是各个“来源”的“层叠”效果:

  • web浏览器的默认样式表
  • 文档的样式表
  • 每个独立的HTML元素的style属性 

style属性的样式表覆盖了样式表中的样式,并且文档的样式表中的样式覆盖了浏览器的默认样式。

为了显示文档元素,web浏览器“必须”组合元素的style属性。计算结果是一组实际用于显示元素的样式属性和值。这组值就是元素的“计算样式”(computed style)。

1.2.CSS历史

CSS历史是一个相对较老的标准,CSS1在1996年12月被采纳,它定义了具体的颜色,字体,外边距,边框和其它的旗本样式。该标准的第二版css2在1998年被采纳,定义了很多高级特性,最著名的就是元素的绝对定位。css2.1澄清和更正了css2,并且它删除了浏览器供应商从未实现的功能。现在的浏览器基本上都完全支持css2.1,但是低于IE8的IE还有一些遗漏问题。在css后续的工作中,针对版本3,CSS规范意见拆分成各种各样的专门化模块,分别来通过标准化进程。可以通过http://www.w3.org/Style/CSS/current-work找到css规范和工作草案。

1.3.复合属性

某些经常在一起使用的样式属性可以组合起来使用一个特殊的复合属性。例如font-family、font-size、font-weight属性可以用font的复合属性一次性设置

1.4.非标准属性

当浏览器厂商实现非标准CSS属性时,他们将属性名前加了一个厂商前缀。Firefox使用-moz-,Chrome使用-wibkit-,而IE则使用-ms-,它们甚至用这种方式来实现将来会标准化的属性。

在不同的浏览器中不同名字的CSS属性一起工作,你可以能发现一个属性定义一个类方式比较好:

.radius10{
  border-radius:10px; /*针对现代浏览器*/
  -moz-border-radius:10px; /*针对firefox 3.x*/
  -webkit-border-radius:10px; /*针对safari 3.2和4*/
}

像这样定义一个类叫“radios10”,可以将它添加到任意需要10像素圆角的元素的类上。

1.5.CSS举例

 

2.重要的css属性

对于客户端程序员来说,最重要的css特性是那些指定文档中每个元素的可见性、尺寸和精确定位的属性。其它css属性允许指定堆叠的次序、透明度、裁剪区域、外边距、内边距、边框、颜色。为了脚本化css。理解这些样式属性的工作原理是非常重要的。

JavaScript权威指南--脚本化CSS

2.1.用css定位元素

CSS的position指定了应用到元素上的定位类型,如下是4个可能出现的属性值:

  • static:默认属性.指定元素按照常规的文档内容流。静态定位的元素不能使用top,left和类似其它的属性定位。如果想对该文档元素使用css定位技术,必须将position属性值设置为除此之外的其它3个属性值。
  • absolute:该值指定元素是相对于它包含的元素进行定位。相对于所有其它的元素,绝对定位的元素是独立定位的,它不是静态定位的元素中文档流的一部分。它的定位要么是相对于最近定位祖先元素,要么是相对于文档本身。
  • fixed:该值的定位元素是相对于浏览器窗口进行定位的。固定定位的元素始终显示在那里。固定定位的元素和其它元素是独立的。不是文档流的一部分。除了ie6不支持外 ,其它现代的浏览器都支持它。
  • relative:当position属性设置为relative,元素会按照常规的文档流进行布局,它的定位相对于它文档流中的位置进行调整。系统保留着元素正常文档流中的空间。不会因为要填充空间将其各边合拢。也不会将新的元素从新的位置“推开”

一旦设置了元素的position属性为除了static以外的值,就可以通过元素的left,top,right,bottom属性的一些组合指定元素的位置。

如果元素使用绝对定位,它的top和left属性应该解释为它是相对于其position属性设置为除static值以外的祖先元素。如果绝对定位的元素没有定位过的祖先,则使用文档坐标进行度量——就是相对于文档左上角的偏移量。如果想相对于一个属于常规文档流中的容器绝对定位一个元素,则将容器的position指定为relative,top和left指定为0px。这就让容器变成了动态定位,但它仍留在文档流中原来的位置。

指定元素的宽度可以用width,另一种方法是同时指定left和right属性,高度也一样。如果同时指定left、right和width,那么width属性将覆盖right属性,height属性优先于bottom属性。

<head>
    <meta charset="utf-8">
</head>
<style type="text/css">
    .out{position: relative;left: 0;right: 0;width: 500px;height: 500px;background: #ccc;}
    .in{position: absolute;left: 100px;right: 100px;top: 100px;bottom: 100px;width: 200px;background: #aaa;}
</style>
<body>
    <div class="out">
        <div class="in">绝对定位</div>
    </div>
</body>

单位:px、in、cm、pt、em等等。

1.第三个维度

上面讲的是在二维坐标中指定X和Y坐标,z-index定义第三个维度允许指定元素的堆叠次序。默认为0,可以是正负整数如果重叠元素的z-index值一样,则按照在文档中出现的顺序绘制,即最后一个重叠的元素显示在最上面

注意:z-index只对兄弟元素应用堆叠效果。

非定位元素(例如,默认使用position:static定位)总是以防止重叠的方式进行布局,因为z-index属性不会应用到他们上面。尽管如此,它们默认的z-index值为0,这意味着z-index为正值的定位元素显示在常规文档流的上面,而z-index为负直的定位元素显示在常规文档流的下面。

2.CSS定位示例:文本阴影

CSS3有text-shadow属性可以产生文本阴影效果,用CSS定位也可以实现,只要重复输出这段文本并重新定义一下样式:

<body>
    <!-- text-shadow属性 -->
    <span style="text-shadow: 3px 3px 1px #888">Shadowed</span>

    <!-- 利用定位 -->
    <span style="position: relative;">
        Shadowed
        <span style="position: absolute;top: 3px;left: 3px;z-index: -1;color: #888">
            Shadowed
        </span>
    </span>
</body>

2.2.边框,外边距,内边距

边框样式border,指定边框的样式、样式和厚度,也可以单独指定。

在CSS3中可以用border-radius指定圆角,也可以设置单独的圆角。

margin和padding属性。

2.3.CSS盒模型和定位细节

以上描述的margin,border和padding等样式属性在脚本化时很可能不经常使用。因为他们是CSS盒模型(box model)的一部分

left和top属性指定了从容器边框内侧到定位元素边框外侧的距离。这些属性不是从容器内容区域的左上角开始度量的,而是从容器内边距的左上角开始的。同样,right和bottom属性是从容器内边距的右下角开始度量的。

有一个例子说明这点。假设已创建一个在内容区域四周有10px padding和5px border的动态定位的容器元素。假设一个定位的子元素将left设为0px,则子元素会靠在容器左边框的右边,覆盖了容器的内边距。所以如果要这样做的话需要设置left为10px。

边框盒模型和box-sizing属性

标准CSS盒模型规定width和height样式属性给定内容区域尺寸,而且不包含内边距和边框。可以称此为“内容盒模型”。在老版的IE和新版的CSS都有一些例外 ,在IE6之前和当IE6-8在怪异模式下,显示一个页面(页面缺少<!DOCTYPE>或有一个不严格的doctype时),width和height属性确是包含内边距和边框宽度的。

但是这样也有用,所以CSS3引进了box-sizing属性,默认值是content-box,它指定执行页面的标准盒模型,如果替换为box-sizing:border-box,浏览器将会为那个元素应用IE的盒模型,即:width和height包含边框和内边框。当想以百分比形式为元素设置总体尺寸,又想以像素指定边框和内边距时,边框盒模型特别有用。

<div style="box-sizing:border-box;width: 50%;padding: 10px;border: 2px solid red;"></div>

box-sizing属性在当今的浏览器中都支持,但是还没不带前缀通用地实现。可以在chrome和safari中使用-webikit-box-sizing,在firefox中,使用-moz-box-sizing。在IE后等其他浏览器更高的版本中,可以使用不带前缀的box-sizing。

在CSS3中一个可选方案是使用盒子尺寸的计算值:

<div style="width: calc(50%-12px);padding:10px;border: solid red 2px;"></div>

在IE9中支持使用calc()计算css的值。在Firefox4中为-moz-calc()。

2.4.元素的显示和可见性

两个CSS的属性影响了文档元素的可见性:visibility和displayvisibility属性很简单。当其值设置为hidden时,该元素不显示。当其值设置为visible时,该元素显示。display属性更加通用。它用来接收它的容器指定元素显示的类型。它指定元素是块级元素、内联元素、列表项等。但当display设置为none,受影响的元素将不显示,甚至根本没有布局。

visibility和display属性之间的差别可以从他们对使用静态或相当定位元素的影响中看到。对于一个常规布局流中的元素,设置visibility属性为hidden使得元素不可见,但在文档布局中保留了它的空间。类似的元素可以重复隐藏和显示而不改变文档布局。但是,当display属性设置为none,在文档布局中不给它分配空间。使得各边元素会靠拢,就当不存在。例如在创建和展开折叠的效果时display属性就很有用。

visibility和display属性对绝对和固定定位的元素影响是等价的。因为这些元素都不是文档布局的一部分。然而,在隐藏和显示定位元素时一般首选visibility属性。

注意,使用visibility和display属性是的元素不可见没有什么意义。除非使用javascript动态设置这些属性让元素在某一刻可见!

2.5.颜色、透明度和半透明度

文本元素、背景颜色、边框颜色。

在CSS中更一般指定颜色的语法是使用十六进制数分别指定组成颜色的红、绿和蓝色分量,每个分量可以使用一位后两位数字

CSS3也指定RGBA彩色空间。CSS3也定义了对HSL(色相-饱和度-值)和HSLA颜色规范的支持。他们在FIrefox、Safari、Chrome中都支持,除了IE。

除了background-color属性,也可以为元素指定背景图像:background-image属性以及一些高级细节设置。使用复合属性background直接搞定。

如果没有为元素指定背景颜色或图象,它的背景通常透明,理解这点非常重要,例如一个空的<div>绝对定位。尽管如此,默认情况下不是所有元素都是透明的,例如,具有透明背景的表单元素看起来不透明,并且元素<button>有默认的背景颜色用background-color属性可以覆盖默认颜色,如果强烈要求可以将其显式设置为"transpanrent"。

CSS3的opacity属性处理元素的透明,该属性值为0-1之间的数字、opacity属性在当今所有的浏览器都支持。除了IE,IE提供可选方式:特有的filter属性。

opacity:.75
filter:alpha(opacity=75);

2.6.部分可见:overflow和clip

visibility属性可以让文档元素完全隐藏,而overflow和clip属性允许只显示元素的一部分。overflow属性指定内容超出元素的大小(例如:用width和 height样式属性指定)时如何显示。该属性的值和含义如下所示:

  • visible :默认值。如果需要,内容可以溢出并绘制在元素边框的外面
  • hidden:裁剪掉和隐藏溢出的内容。
  • scroll:元素一直显示水平和垂直滚动条。
  • auto:滚动条只在内容超出元素的尺寸时显示,而非一直显示。

clip属性确切地指定了应该显示元素的哪个部分,不管是否溢出在创建元素渐进显示的脚本效果时特别有用

clip属性的值指定了元素的裁剪区域,在css2中,裁剪区域是矩形的,不过clip属性的语法预留了开放的可能性,该标准在将来的版本可能将支持更多形状的裁剪。它的语法是:

/*相对于元素边框的左上角*/
rect(top right bottom left)

例如只显示元素的100X100的部分:

style="clip:rect(0px 100px 100px 0);"

注意:圆括号4个值时长度,所以必须包含明确单位。不允许使用百分比,可以指定负值,也可以为任何4个值使用auto关键字来指定裁剪区域的边缘就是元素边框的对应边缘。例如只显示元素最左的100像素:

style = "clip:rect(auto 100px auto auto);"

值之间没有逗号。将clip设置为auto来停用裁剪功能。

2.7.示例:重叠半透明窗口

 

3.脚本化内联样式

脚本化css最直接了当的方法就是更改单独的文档元素的style属性,类似大多数HTML属性,style也是元素对象的属性,它可以在javascript操作,但是style属性不同寻常:它的值不是字符串,而是一个CSSStyleDeclaration对象。该style对象的javascript属性代表了HTML代码中通过style指定的css属性。例如让元素e的文本变大号、加粗和蓝色,可以使用如下代码设置font-size,font-weight和color样式属性对应的javascript属性。

e.style.fontSize = "24px";
e.style.fontWeight = "bold";
e.style.color = "#007F9F";

名字约定:JavaScript中的CSS属性

有连字符的属性,在JavaScript是减号,不能用。因此,CSSStyleDeclaration对象中的属性名和实际的CSS属性名有所区别。例如连字符改为首字母大写:CSS属性border-left-width的值在JavaScript中为borderLeftWidth。另外,当一个CSS属性(如float)在JavaScript中对应的名字是保留字时,在之前加"css"前缀来创建合法的CSSStyleDeclaration名字。如float为cssFloat。

使用CSSStyleDeclaration对象的style属性时,记住所有值都应该是字符串,所有的定位都有有单位。

e.style.left = (x0 + left_margin + left_border + left_padding) + "px";

回想一下,一些css属性(如margin)是margin-top/margin-right/margin-bottom/margin-left)的复合属性。CSSStyleDeclaration对象也有与之对应的复合属性,例如。也能像这样设置magin属性:

e.style.margin = topMargin + "px" + rightMargin + "px" + bootomMargin + "px" + leftMargin + "px";

独立设置4个margin属性值更加便捷:

e.style.marginTop = topMargin + "px";
e.style.marginRight = rightMargin + "px";
e.style.marginBottom = bottomMargin + "px";
e.style.marginLeft = leftMargin + "px";

HTML元素的style属性是它的内联样式,它覆盖在样式表中的任何样式说明。内联样式一般在设置样式值时非常有用,就像上面的例子所说的一样。CSSStyleDeclaration对象的属性可以理解为代表内联样式,但是它只返回有意义的值:javascript代码已经设置过的值或者HTML元素显式设置了想要的内联样式的值。例如,文档可能包含一个样式表以设置所有段落的左边距为30px,但是挡在读取段落元素的marginLeft属性时会得到一个空字符串,除非该段落有一个style属性覆盖了样式表中的设置。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <style type="text/css">
        #mar0,#mar1{
            width: 100px;height: 100px;border: 2px solid #ccc;margin-left: 10px;
        }
    </style>
</head>
<body>
    <div id="mar0">margin</div><br>
    <div id="mar1" style="margin-left: 20px">margin</div>
    <script type="text/javascript">      
        window.onload = function(){
            var ma0 = document.getElementById("mar0");
            var ma1 = document.getElementById("mar1");            
            console.log(ma0.style.marginLeft);
            console.log(ma1.style.marginLeft);
        }
    </script>
</body>

读取元素的内联样式特别困难,对style属性来说必须包含单位,对复合属性来说,在真正使用这些值的时候,代码不得不包含非同寻常的css解析能力。总之,元素的内联样式只有在设置样式的时候有用,但如果需要查询元素的样式,就要使用计算样式,这将在本章4节讨论。

有时,发现单个字符串值来设置或查询元素的内联样式反而比作为CSSStyleDeclaration对象更加简单。为此,可以使用元素的getAttribute()和setAttribute()方法或CSSStyleDeclaration对象的cssText属性来实现:

 //两者都可以设置e的样式属性为字符串s
e.setAttribute("style", s);
s = e.style.cssText;
 //两者都可以查询元素的内联样式
s = e.getAttribute("style");
s = e.style.cssText;

CSS动画

脚本化的css最常见的用途之一就是产生视觉动画,使用setTimeout()或setTinterval()(12章1节),重复调用函数来修改元素的内联样式达到目的。下面的例子用shake()和fadeOut()来举例说明。shake()将元素从一边快速移动到另一边震动。例如当输入无效数据时,会吸引用户注意力。fadeOut()通过制定时间(默认500毫秒)降低元素不透明度,使得元素淡出和消失。

//将e转化为相对定位的元素,使之左右“震动”
//第一个参数可以是圆度对象或者元素的id
//如果第二个参数是函数,以e为参数,将在动画结束时调用;第三个参数指定e震动的距离,例如5px
//第四个参数指定震动多久,默认500毫秒
function 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的x位置
            //使用正弦函数将完成的比例乘以4pi
            //所以,它来回往复两次
            var x = distance * Math.sin(fraction * 4 * Math.PI);
            e.style.left = x + "px";
            //在25毫秒之后或在总时间最后尝试再次运行函数
            //目的是为了产生每秒40帧的动画
            setTimeout(animate, Math.min(25, time - elapsed));
        } else { //否则动画完成
            e.style.cssText = originalStyle //恢复原始样式
            if (oncomplete) oncomplete(e); //调用完成后回调函数
        }
    }
}
//以毫秒级时间将e从完全不透明到透明
//在调用函数时假设e是完全不透明的
//oncomplate是一个可选函数,以e为参数,在动画结束调用
//如果不指定time.默认500
//本函数ie中不能正常构造
//除了opacity,ie使用非标准的filter属性
function 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); //设置在e上
            setTimeout(animate,Math.min(25,time-elapsed));
        }
        else{
            e.style.opacity = "0";
            if(oncomplete) oncomplete(e); //调用完成后回调函数
        }
    }
}

shake()和fadeOut()都能接受可选的回调函数作为第二个参数,如果指定了,当动画结束时函数将被调用。该动画元素将作为回调函数的参数传递进去。下面的代码创建了一个按钮,当单击时,左右震动并淡出。

<button onclick="shake(this,fadeOut)">点击我</button>

注意,shake()和fadeOut()示例函数之间非常相似,都能作为类似css属性动画的模板。客户端类库,如jQury通常支持预定义的视觉效果,因此,除非想创建特别复杂的视觉效果,实际上不用写类似shake()动画函数。scriptaculous是早期一个值得关注的类库,它是为prototype框架设计的。http://scripty2.com/

为了避免使用任何脚本,CSS3的过渡模块定义了在样式表中指定动画效果的方式。例如,为了替代定义类似fadeOut()这样的函数,可以使用如下的css:

.fadeable{transition:opacity .5s ease-in}

4.查询计算出的样式

元素的style属性代表了元素的内联样式,它覆盖所有的样式表,它是设置CSS属性值来改变元素的视觉表现最好的地方。但是,它在查询元素实际应用的样式时用处不大。为此,你想要使用计算样式。元素的计算样式是一组属性值,它由浏览器通过把内联样式结合所有链接样式表中所有可应用的样式规则后导出(或计算)得到的:它就是一组在显示元素时实际使用的属性值类似内联样式,计算样式也是一个CSSStyleDeclaration对象来表示的,区别是,计算样式是只读的。虽然不能设置这些样式,但为元素计算出的CSSStyleDeclaration对象确切地决定了浏览器在渲染元素时使用的样式属性值。

用浏览器窗口对象的getComputedStyle()方法来获取一个元素的计算样式。接收两个参数:第一个是要取得其计算样式的元素,第二个也是必须的,通常是null或空字符串,也可以是命名CSS伪对象字符串,如“:before”、“:after”、“:first-line”、“:first-letter”。

var title = document.getElementById("section1title");
var titlestyles = window.getComputedStyle(element,null);

getComputedStyle()方法返回一个CSSStyleDeclaration对象,其中包含当前元素的所有计算的样式。

表示计算样式的CSSStyleDeclaration对象和表示内联样式的对象之间有一些重要的区别:

  • 计算样式的属性是只读的;
  • 计算样式的值是绝对值,类似百分比和点之类相对的单位将全部转换绝对值。所有指定尺寸的属性都有一个以像素为度量单位的值。该值将是一个冠以"px"后缀的字符串,使用时仍然需要解析它,但是不用担心单位的解析或转换。其值是颜色的属性将以“rgb(#,#,#)”或“rgba(#,#,#,#)”的格式返回;
  • 不计算复合属性,它们只基于最基础的属性,如不要查询margin,应该使用marginTop等;
  • 计算样式的cssText属性未定义;

计算样式和内联样式可以同时使用。下面例子定义了scale()和scaleColor()函数。一个用来查询和解析指定元素的计算文本尺寸,另一个查询和解析元素的计算背景颜色。两个函数都将结果值按比例缩放并作为元素的内联样式设置缩放值。

。。。。。。

计算样式也具有欺骗性,查询它们得到的信息也不总是如人所愿比如font-family属性:为了适应跨平台可移植性,可能会接受字体列表,当查询一个计算样式的fontFamily属性时,可能返回一系列的字体如"arial,helvetica,san-serif",而无法告诉你实际使用哪种字体。类似的,如果没有使用绝对定位,试图通过计算样式的top和left属性会返回"auto",这个是合法的,但不是想要的。

在IE中,每个HTML元素有自己的currentStyle属性,它的值是CSSStyleDeclaration对象。IE的currentStyle组合了内联样式和样式表,但他不是真正的计算样式,因为相对值都没有转换为字符串(会带有"%"、"em"或"red"等等)。

查询元素的计算样式不是判定元素尺寸和位置的完美方法,另一种更简单的在15.8.2节。

5.脚本化CSS类

通过内联style属性脚本化CSS样式的一个可选方案是脚本化HTML的clss属性值。改变了元素的class就改变了应用于元素的一组样式表选择器,它能在同一时刻改变多个CSS属性。例如,假设想让用户对文档中的单独段落(或其它元素)引起注意。首先,为任意元素定义一个名为"attention"的类:

.attention{/*吸引用户注意*/
    background-color:yellow;
    font-weight: bold;
    border: solid black 2px;
}

标识符class在javascript中是保留字,所以HTML属性class在javascript代码中应该可用于使用calssName的javascript代码。如下的代码设置和清除元素的className属性来为元素添加和移除"attention"类:

function grabAttention(e){e.className = "attention";}
function releaseAttention(e) {e.className = "";}

HTML元素可以有多个CSS类名,class属性保存了一个用空格隔开的类名列表。上面的函数假设className属性只指定零个或一个类名,如果有多个类名就无法工作了。如果元素已经有一个类,调用上面grabAttention()函数将覆盖已经存在的类。

HTML5为了解决这个问题,为每个元素定义了classList属性该属性的值是DOMTokenList对象:一个只读的类数组对象(7.11节),它包含元素的单独类名。但是,和数组元素相比,DOMTokenList定义的方法更加重要。add()和remove()从元素的class属性中添加和清除一个类名。toggle()表示如果不存在的类名就添加一个;否则,删除它。最后,contains()方法检测class属性中是否包含一个指定的类名。

类似其他DOM集合类型,DOMTokenList对象“实时的”代表了元素类名集合。而并非是在查询classList属性时类名的一个静态快照。如果从元素的classList属性中获得了一个DOMTokenList对象,然后元素的className属性改变了,这些变化在标识列表中及时可见。同样,改变标识列表,在ClassName属性中及时可见。

不是所有的浏览器都支持classList属性。但是这个重要的功能容易近似实现。如下代码或使用类似的代码,把class属性当做一个类名的集合。使得许多脚本化的css类工作更加简单。

。。。。。。

6.脚本化样式表

到目前为止,我们已经看到如何设置和查询CSS样式和单个元素的类名。脚本化样式表当然是也是可能的。虽然不经常这么做,但偶尔却非常有用。本节概述该技术。

在脚本化样式表时,将会碰到两类需要使用的对象。第一类是元素对象,由<style>和<link>元素表示,两种元素包含或引用样式表。这些是常规的文档元素,如果他们有id属性值,可以使用document.getElementById()函数来选择它们。第二类是CSSStyleSheet对象,它表示样式表本身。document.styleSheets属性是一个只读的类数组对象,它包含CSSStyleSheet对象,表示与文档关联在一起的样式表。如果为定义或引用了样式表的<style>或<link>元素设置title属性值,该title作为对应CSSStyleSheet对象的title属性就可以。

6.1.开启和关闭样式表

最简单的校本化样式表的技术特是最便捷和健壮的。<style>、<link>元素和CSSStyleSheet对象都定义了一个在javascript中可以设置和查询的disabled属性。顾名思义,如果disabled属性为true,样式表就被浏览器关闭并忽略

以下disableStyleSheet()函数就说明了这一点。如果传递一个数字 。函数将其当做document.styleSheet数组中的一个索引,如果传递一个字符串。函数就将其当做CSS选择器并传递给document.querySeleCtorAll()(15.2.5节),然后设置所有返回元素的disabled属性:

function disableStyleSheeet(ss) {
    if (typeof ss === "number")
        document.styleSheets[ss].disabled = true;
    else {
        var sheet = document.querySelectorAll(ss);
        for (var i = 0; i < sheet.length; i++)
            sheet[i].disabled = true;
    }
}

6.2.查询、插入与删除样式表规则

除了样式表的开启和关闭以外,CSSStyleSheet对象也定义了用来查询、插入和删除样式表的规则API。IE8及更早版本实现的API和其它浏览器实现的标准API之间有一些轻微的区别。

直接操作样式表通常没什么意义。典型地,相对编辑样式表或增加新规则而言,让样式表保存静态并对元素className属性编程更好。另一方面,如果允许用户完全控制页面上的样式,可能就需要动态操作样式表。

document.styleSheets[]数组的元素是CSSStyleSheet对象。CSSStyleSheet对象有一个cssRules[]数组,它包含所有样式表规则:

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

IE使用不同的属性名rules代替cssRules

cssRules[]或rules[]数组元素为CSSRule对象。在标准的API中,CSSRule对象代表所有的CSS规则,包含如@import和@page等指令。但是在IE中,rules[]数组只包含样式表中实际存在的样式规则。

CSSRule对象有两个属性可以很便捷的使用。(在标准API中,非样式规则没有定义这些属性,当遍历样式表时希望跳过去它。)selectText是规则的CSS选择器,它引用一个描述与选择器相关联的样式的可写CSSStyleDeclaration对象。回想一个,CSSStyleDeclaration是用来表示内联和计算样式的相同类型。可以利用它来查询规则的样式值或设置新样式。通常,当遍历样式表时。你对规则的文本比它解析后的表示形式更感兴趣。此时,使用CSSStyleDeclaration对象的cssText属性来获得规则的文本表示形式。

除了查询和修改样式表中已存在的规则以外,也能向样式表添加和从中删除规则。标准的API接口定义了insertRule()和deleteRule()方法来添加和删除规则

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

IE不支持insertRule()和deleteRule(),但定义了大致等效的函数addRule()和removeRule()。(除了名字以外)仅有的不同是addRule()希望选择器文本和样式文本作为两个参数。

以下代码遍历样式表样式表的规则,举例说明了用API对样式表进行一些可疑的修改:

。。。。。。

6.3.创建新的样式表

最后,创建整个新样式表并将其添加到文档是中可能的。在大多数浏览器中,可以用标准的DOM技术:只要创建一个新的<style>元素,将其插入到文档的头部,然后用其innerHTML属性来设置样式表内容。但是在IE8以及更早的版本中,CSSStyleSheet对象通过非标准方法document.createStyleSheet()来创建,其样式文本用cssText属性值来指定。请看下面的例子。

。。。。。。