48. 动态样式 —— 用 JavaScript 操作 CSS
- 详细资料
- 发布于 2012年9月18日
- 点击数:5520
引言
在本教程的 JavaScript 部分中,到目前为止我们已经学过了 JavaScript 的基础用法,研究了如何通过 DOM 来获取元素并如何在获取成功后对其进行操作。
本文我们会讨论如何通过 JavaScript 在运行时操作 CSS,从而动态地更新应用到我们的元素上的式样。本文所用的技术是我们已经看到过的,但在利用 CSS DOM 来进行操作的时候还需要注意几个特殊点。下面的章节将讲述这些内容:
访问样式表
浏览器提供了与样式表进行交互的接口——在 JavaScript 代码中可以通过 document.styleSheets
. document.styleSheets
来访问页面上所应用的所有样式表列表,包括通过 link
元素引用的外部样式表,以及位于 style
元素之内的内部样式表。如果我们的 style
元素包含 id
属性,就可以通过 document.getElementById(element_id)
来快速地对其进行引用。
我们也可以给页面添加新样式表——可以通过 document.createElement
函数来创建新的 style
元素。这个函数会很有用,比如你想向网站用户提供一些选择,使他们可以动态改变你网站的风格,你可以用一些按钮控件来实现这个效果。下面就是关于你该如何创建一个新样式表的一个例子:
var sheet = document.createElement('style')
sheet.innerHTML = "div {border: 2px solid black; background-color: blue;}";
document.body.appendChild(sheet);
删除样式表的操作也很简单。首先你必须要通过 document.getElementById
获取自己要删除的样式表,具体代码如下面的简例所示。你可以使用 DOM 函数 parent.removeChild(element)
来删除某个样式表,此处的 element
就是你想要删除的样式表对象,而 parent
就是该样式表的父节点。如下面的例子所示,要删除该样式表(sheetToBeRemoved
) ,你首先要获取该样式表的父元素—— var sheetParent = sheetToBeRemoved.parentNode
——然后调用 removeChild
,参数为 sheetToBeRemoved
—— sheetParent.removeChild(sheetToBeRemoved)
。
var sheetToBeRemoved = document.getElementById('styleSheetId');
var sheetParent = sheetToBeRemoved.parentNode;
sheetParent.removeChild(sheetToBeRemoved);
样式表访问示例演示显示了如何访问该页面上所有的样式表,并向该页面添加或删除样式表。
样式表属性
通过 JavaScript 可以获取 stylesheet
对象,可以访问被当前的 Web 页面所引用的样式表的信息,比如该样式表是否是禁用的,该样式表的地址,以及其包含的所有 CSS 规则的列表。要了解 stylesheet
对象的全部属性清单(以及其他信息),请查看 W3C 文档对象模型样式表文档。
我们来看一个的例子——假设我们有一个展示一系列的技术性文章的网站。我们想要以一种美观的动画卷动的方式来突出显示某些文章,但对于那些没有启用 JavaScript 的人来说又该怎么办呢?想到非干扰性的 JavaScript ,我们希望这一类用户仍能使用自己网站的功能——针对这些用户,我们应以不同方式来样式化网站,从而使他们在没有图片卷动的情况下仍然能得到舒适的用户体验。
我们需要的就是一张仅在 JavaScript 被禁用时才有效的样式表。你运气不错——DOM 样式表接口为我们提供了使用 disabled
属性的权限,通过该属性我们就可以启用或关闭样式表了。
stylesheet
对象的大多数属性都是只读的,但有些属性,比如 disabled
,就不是这样。
你也可以利用样式表属性来区分一个页面上的多个样式表。src
属性有助于识别外部样式表,但它不能帮你引用内部样式表。有一种更好的方法可以让你引用内部和外部样式表,那就是使用 title
属性。对 document.styleSheets
进行迭代处理,就可以区分你网页中包含的所有样式表了。下面的例子展示的如何来实现该迭代:
function getStyleSheet(unique_title) {
for(var i=0; i<document.styleSheets.length; i++) {
var sheet = document.styleSheets[i];
if(sheet.title == unique_title) {
return sheet;
}
}
}
对于每个从 stylesheet
数组中检索到的 stylesheet
对象,我们都可以对其 title
属性进行访问,以检查它是否具有我们的代码所要查找的那个标题。你可以在规则的添加和删除示例中看到关于这一点的一个实用的例子,在下一章节中我就会谈到规则的添加和删除。
按照用户喜好在不同的样式表之间进行切换是一种非常常见的 Web 站点功能——通过我们迄今为止所讨论的这些技术,你可以建立起多个样式表,但仅启用当前的网站用户选择的那些样式表。我们来看一个实际的例子——开始的时候文本是样式化过的,但如果我们将 disabled
属性设置为 true
,我们定义好的 CSS 就会被禁用。只需将 disabled
设置为 false
,你就可以把 CS 改回去。关于如何使用这一技术,具体情况你可以查看样式表属性示例。
添加和删除 CSS 规则
还记得我们前面讨论过的网站吗?假设该网站有一系列文章;有些文章是关于 CSS 的,有些是关于 HTML 的,还有些文章是关于 JavaScript 的。在我们的网页上,我们会同时显示出所有的文章,但用户只想看关于 CSS 的文章。我们该怎么来满足这个需求呢?由于所有的文章都已经被显示出来了,我们不愿意再往服务器跑一趟,来获取一个只包含了 CSS 文章的页面——这是在浪费时间。
为了解决这个问题,我们可以用 JavaScript 来对所有文章进行迭代,并仅仅让 CSS 文章可见(稍后我会谈论如何实现这一点);另一个方法是向我们的其中一个样式表添加一条规则,该规则使 CSS 文章成为唯一可见的。
stylesheet
对象有两个函数可以帮助我们解决这个问题。第一个是 insertRule
函数,就像这样:
stylesheet.insertRule(rule,index)
rule
是一个字符串,它包含的是我们要添加到该样式表的规则。index 所指定的是该规则应放在该样式表的规则列表中的什么地方。下面的代码是一个具体的使用例子:
stylesheet.insertRule(".have-border { border: 1px solid black;}", 0);
我创建了一个例子来演示如何使用 insertRule
函数。在这个例子中有一张列表,包含了一个样式表中的所有规则。如果我们按下该按钮,该函数就会添加一条 index 为2的规则,通过为 p { ... }
规则添加 color: red
属性将文本变成红色。点击查看这个添加和删除规则示例。
如果想删掉这条规则,可以调用 stylesheet.deleteRule(index)
函数,此处 index 就是你想要删除的规则的 index。
在我们的文章陈列网站示例中,可以创建一条规则来将所有 HTML 和JavaSrcipt文章的display都改成 none
——具体实例请自行查看图片卷动实例。
注:IE 没有依据标准来实现规则修改。它用的是 rules
,而不是 cssRules
属性。IE 还用 removeRule
代替 deleteRule
,用 addRule(selector, rule, index)
代替 insertRule
。
改变元素样式
现在,你应该知道如何编辑与页面相连接的样式表,以及如何创建和修改其中的 CSS 规则了。如果你想要改变 DOM 中的某个特定元素的话,又该怎么办?通过 DOM API 可以访问页面上的特定元素。回顾一下我们的图片卷动示例,当我们点击某篇文章的时候,该文章标题就会被高亮,而文章的正文则会被显示在下面。
通过 DOM 可以访问描述某元素的样式的style
对象。style
对象被定义为 CSSStyleDeclaration;详细解释可以查看 W3C CSSStyleDeclaration
接口文档。style
对象与 HTML 元素中定义的其它属性的工作方式并不是完全一样的。与 element.href
或 element.id
不同,element.style
返回的是一个对象而不是字符串。因此我们不能通过将一个字符串赋给 element.style
的方式来设置样式。
style
对象的属性对应我们所设置的各种 CSS 属性。比如说,style.color
返回的是某个元素上所设置的颜色。通过调用 element.style.color = "red";
你就可以动态地改变样式。下面是一个函数,如果我们将某个元素的 id
传递给它的话,该函数就可以将该元素的颜色改成红色。
function colorElementRed(id) {
var el = document.getElementById(id);
el.style.color = "red";
}
你还可以用 setAttribute(key, value)
来为一个元素设置样式。比如说,你可以在某个元素上调用 element.setAttribute('style', 'color: red');
来将该元素的颜色设成红色,但是这种方式会擦去你之前对 style
对象所做的一切改动,所以在使用的时候必须小心。
通过这种方式来设置元素的样式,跟在 html
元素的 style
属性中对其进行声明是一样的。只有当该规则的重要性和具体性比应用在该元素上的其它规则要高时(具体见 CSS 的继承和级联),该样式才会得以应用。
有人可能会想,要是我们要设置的 CSS 属性名带有连字符的话,又会发生什么呢?在这种情况下语法就不能再跟以前一样了,我们举个例子来说明其原因,如果你写的是 element.style.font-size
, JavaScript 就从 element.style.font
中减去 size
,这可不是你想要的结果。为了避免这种问题,所有的 CSS 属性都是用驼峰大小写来书写的。如下所示,你可以这样写 element.style.fontSize
,来访问该元素的字号:
function changeElement(id) {
var el = document.getElementById(id);
el.style.color = "red";
el.style.fontSize = "15px";
el.style.backgroundColor = "#FFFFFF";
}
还记得那些样式表对象吗?styleSheet.cssRules
会返回 style
对象列表,该列表包含了所有位于该样式表中的 CSS 规则。你可以像使用其它元素的 style
对象一样来使用这些 style
对象。但此处的改动会改变所有应用了该 CSS 规则的元素,而不是只改变我们页面上的某一个特定元素。
在下面的例子中,使文本变大的函数使用了 style
对象,使文本变小的函数则用了 setAttribute
。如果你将文本设置为红色,然后点击缩小文本按钮调用 setAttribute
,就会发现我们所做的改动被重写了。具体实例请看元素样式改变示例。
元素的 Class 名
另一种修改元素样式的方法是改变其 class
属性。class
是一个 JavaScript 保留字,你可以用 element.className
来访问某个元素的 class。如果你想将一个 class
添加到某个元素,就可以在 className
后面追加字符串,或者直接重写 className
,并为其赋一个全新的 class 。具体示例请看元素的 class 名示例 。
总结
知道如何动态修改页面上所应用的样式,对创建时髦而又富于交互的 Web 页面来说是极其有用的——本文中所阐述的知识构成了诸如 JavaScript 动画之类更高级的技术的基础。需要注意的是,你应当负责任地使用动态样式修改,而且不要过度滥用。如前面所述,样式修改还能提高Web效率——内容的显示和隐藏可以有助于避免在客户端和服务器之间不必要的数据交互。
练习题
setAttribute
和通过 CSSStyleDeclaration 对象来设置样式之间的区别是什么?- 列出两种方式,说明该怎样实现这样的效果:当用户点击一个按钮时,所有的图像都出现绿色的边框。
- 改变某个元素的 CSSStyleDeclaration 对象总是会引起该元素样式的改变吗?为什么?
- 举出两种方式,说明如何访问某个特定的样式表。