文章目录
脚本化CSS
脚本化CSS就是使用js来操作CSS,配合HTML5、Ajax、jQuery等技术,可以设计出细腻、逼真的页面特效和交互行为,大幅提升用户体验,如网页对象的隐藏/显示、定位、变形、运动等动态样式。
【重点】
- 使用js控制行内样式。
- 使用js控制样式表。
- 控制对象大小。
- 控制对象位置。
- 设计显示、隐藏,以及动画效果。
CSS脚本化基础
CSS样式表包括两种形式:样式表中的样式和行内样式。DOM2级规范针对样式表提供了一套API。在DOM2级规范之前,还可以使用标签对象的style属性访问行内样式。
读写行内样式
任何支持style特性的HTML标签,在js中都有一个对应的style脚本属性。style是一个可读可写的对象,包含了一组CSS样式。
使用style的cssText属性可以返回行内样式的字符串表示。同时style对象还包含一组与CSS样式属性一一映射的脚本属性。这届脚本属性的名称与CSS样式属性的名称对应。在js中,由于连字符是减号运算符,含有连字符的样式属性(如font-family),脚本属性会以驼峰法重新命名(fontFamily)。
- 【实例】对于border-right-color属性来说,在脚本中应该使用borderRightColor。
<body>
<div id="box">盒子</div>
</body>
<script>
var box = document.getElementById("box");
box.style.borderRightColor = "red";
box.style.borderRightStyle = "solid";
</script>
- 提示:使用CSS脚本属性时,需要注意以下几个问题。
- float是js保留字,因此使用cssFloat表示与之对应的脚本属性的名称。
- 在js中,所有CSS属性值都是字符串,必须加上引号。
- CSS样式声明结尾的分号不能够作为脚本属性值的一部分。
- 属性值和单位必须完整。
使用style对象
DOM2级规范为style对象定义了一些属性和方法,简单说明如下:
- cssText:返回style的CSS样式字符串。
- length:返回style的声明CSS样式的数量。
- parentRule:返回style所属的CSSRule对象。
- getPropertyCSSValue():返回包含指定属性的CSSValue对象。
- getPropertyPrioty():返回包含指定属性是否附加了!important命令。
- item():返回指定下标位置的CSS属性的名称。
- getPropertyValue():返回指定属性的字符串值。
- removeProperty():从样式中删除给定属性。
- setProperty():为指定属性设置值,也可以附加优先权标志。
下面重点介绍几个常用的方法:
- getPropertyValue()方法。
getPropertyValue()能够获取指定元素样式属性的值。用法如下:
var value = e.style.getPropertyValue(propertyName);
参数propertyName表示CSS属性名,不是CSS脚本属性名,复合名应使用连字符串进行连接。
- 【实例1】下面代码使用getPropertyValue()方法获取样式中的width属性值,然后输出到盒子内显示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<div id="box" style="width: 300px; height: 200px; border: solid 1px red">盒子</div>
</body>
<script>
window.onload = function() {
var box = document.getElementById("box");
var width = box.style.getPropertyValue("width");
box.innerHTML = "盒子宽度" + width;
}
</script>
</html>
- setProperty()方法。
setProperty()方法为指定元素设置样式。
e.style.setProperty(propertyName, value, priority);
参数说明如下:
-
propertyName:设置CSS属性名。
-
value:设置CSS属性值,包含属性值的单位。
-
priority:表示是否设置!important优先级命令,如果不设置可以为空字符串表示。
-
【实例2】在下面实例中使用setProperty()方法定义盒子的显示宽度和高度分别为400像素和200像素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<div id="box" style="border: solid 1px red">盒子</div>
</body>
<script>
window.onload = function() {
var box = document.getElementById("box");
box.style.setProperty("width", "400px", "");
box.style.setProperty("height", "200px", "");
}
</script>
</html>
- removeProperty()方法。
removeProperty()方法可以移出指定CSS属性的样式声明。具体用法如下:
e.style.removeProperty(propertyName);
- item()方法。
item()方法返回style对象可以移出指定的CSS属性的样式名称。具体用法如下:
var name = e.style.item(index);
参数index表示CSS样式的索引号。
- getPropertyPriority()方法。
getPropertyPriority方法可以获取指定CSS属性中是否附加了!important优先级命令,如果存在则返回”important“字符串,否则返回空字符串。
- 【实例3】在下面实例中,定义鼠标指针移过盒子时,设置盒子的背景色为蓝色,边框颜色为红色,当移出盒子时,又恢复到默认设置的样式;而单击盒子时则在盒子内输入动态信息,显示当前盒子的宽度和高度。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<div id="box" style="width: 100px; height: 100px;background-color: red; border: solid 50px blue"></div>
</body>
<script>
window.onload = function() {
var box = document.getElementById("box");
box.onmouseover = function() {
box.style.setProperty("background-color", "blue", "");
box.style.setProperty("border", "solid 50px red", "");
}
box.onclick = function() {
box.innerHTML = (box.style.item(0) + ":" + box.style.getPropertyValue("width"));
box.innerHTML = box.innerHTML + "<br>" + (box.style.item(1) + ":" + box.style.getPropertyValue("height"));
}
box.onmouseout = function() {
box.style.setProperty("background-color", "red", "");
box.style.setProperty("border", "solid 50px blue", "");
}
}
</script>
</html>
- 【实例4】针对实例3,可以使用点语法快速设计相同的交互效果,这样能够兼容IE早期的版本。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<div id="box" style="width: 100px; height: 100px;background-color: red; border: solid 50px blue"></div>
</body>
<script>
window.onload = function() {
var box = document.getElementById("box");
box.onmouseover = function() {
box.style.backgroundColor = "blue";
box.style.border = "solid 50px red";
}
box.onclick = function() {
box.innerHTML = "width: " + box.style.width;
box.innerHTML = box.innerHTML + "<br>" + "height: " + box.style.height;
}
box.onmouseout = function() {
box.style.backgroundColor = "red";
box.style.border = "solid 50px blue";
}
}
</script>
</html>
使用styleSheets对象
在DOM2级规范中,使用styleSheets对象可以访问页面中的所有样式表,包括用<style>
标签定义的内部 样式表,以及用<link>
标签或@import命令导入的外部样式表。
cssRules对象包含指定样式表中所有的规则(样式)。提示,IE支持rules对象表示样式表中的规则。可以使用下面代码兼容不同的浏览器:
var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
在上面代码中,先判断浏览器是否支持cssRules对象,如果支持则使用cssRules(非IE浏览器),否则使用rules(IE浏览器)。
- 【实例】在下面实例中,通过
<style>
标签定义一个内部样式表,为页面中的<div id = "box">
标签定义4个属性:宽度、高度、背景色、边框。然在脚本中使用styleSheets访问这个内部样式表,把样式表中的第1个样式的所有规则读出来,在盒子中输出显示。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<style>
#box {
width: 400px;
height: 200px;
background-color: #bffb8f;
border: solid 1px blue;
}
</style>
<body>
<div id="box"></div>
</body>
<script>
window.onload = function() {
var box = document.getElementById("box");
var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
box.innerHTML = "<h3>盒子样式</h3>";
box.innerHTML += "<br>边框: " + cssRules[0].style.border;
box.innerHTML += "<br>背景: " + cssRules[0].style.backgroundColor;
box.innerHTML += "<br>高度: " + cssRules[0].style.height;
box.innerHTML += "<br>宽度: " + cssRules[0].style.width;
}
</script>
</html>
- 提示:cssRules(或rules)的style对象在访问CSS属性时,使用的是CSS脚本属性名,因此所有属性名称中不能使用连字符。例如:
cssRules[0].style.backgroundColor;
。
使用selectorText对象
使用selectorText对象可以获取样式的选择器字符串表示。
- 【实例】在下面这个实例中,使用selectorText属性获取第一个样式表(styleSheets[0])中的第三个样式(cssRules[2])的选择器名称。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<style>
#box {
color: green;
}
.red {
color: red;
}
.blue {
color: blue;
}
</style>
<body>
<div id="box"></div>
</body>
<script>
window.onload = function() {
var box = document.getElementById("box");
var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
box.innerHTML = "第一个样式表中第三个样式选择符 = " + cssRules[2].selectorText;
}
</script>
</html>
编译样式
cssRules的style不仅可以读取,还可以写入属性值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<style>
#box {
color: green;
}
.red {
color: red;
}
.blue {
color: blue;
}
</style>
<body>
<p class="blue">原为蓝色字体,现在显示为浅灰色</p>
</body>
<script>
window.onload = function() {
var cssRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
cssRules[2].style.color = "#999";
}
</script>
</html>
- 提示:使用上述方法修改样式表中的类样式,会影响其他对象或其他文档对当前样式表的引用,因此在使用时请务必谨慎。
添加样式
使用addRule()方法可以为样式表添加一个样式。
styleSheet.addRule(selector, style, [index]);
styleSheet表示样式表引用,参数说明如下:
- selector:表示样式选择符,以字符串的形式传递。
- style:表示具体的声明,以字符串的形式传递。
- index:表示一个索引号,表示添加样式在样式表中的索引位置,默认为-1,表示位于样式表的末尾,该参数可以不设置。
Firefox支持使用insetRule()方法添加样式。用法如下:
styleSheet.insertRule(rule, [index])
参数说明:
- rule:表示一个完整的样式字符串。
- index:与addRule()方法中的index参数作用相同,但默认为0,放置在样式表的末尾。
读取显示样式
CSS样式具有重叠特性,因此定义的样式与最终显示的样式并非完全相同。DOM定义了一个方法帮助用户快速检测当前对象的显示样式,不过IE和标准DOM之间实现的方法不同。
- IE浏览器
IE使用currentStyle对象读取元素的最终显示样式,是只读对象。currentStyle对象包含元素的style属性,以及浏览器预定的默认style属性。
- 非IE浏览器
DOM使用getComputedStyle()方法获取目标的显示样式,但是它属于document.defaultView对象。getComputedStyle()方法包含两个参数:第一个参数表示元素,用来获取样式的对象;第二个参数表示伪类字符串,定义显示位置,一般可以省略,或者设置为null。
使用CSS事件
- transitionEnd事件
CSS的过渡效果(transition)结束后,触发transitionEnd事件。例如:
el.addEventListener('transitionend', onTransitionEnd, false);
function onTransitionEnd(){
console.log('Transition end');
}
transitionEnd的事件对象具有以下属性。
- propertyName:发生transition效果的CSS属性名。
- elapsedTime:transition效果持续的秒数,不含transition-delay的时间。
- pseuduElement:如果transition效果发生在伪元素上,会返回改伪元素的名称,以”::“开头,如果没有发生在伪元素上,则返回一个空字符串。
实际上使用transitionend事件时,可能需要添加浏览器前缀。
el.addEventListener('webkitTransitionEnd', function(){
el.style.transition = 'none';
})
- animationstart、animationend、animationiteration事件
CSS动画有以下三个事件:
- animationstart事件:动画开始时触发。
- animationend事件:动画结束时触发。
- animationiteration事件:开始新一轮动画循环时触发。如果animation-iteration-count属性等于1,该事件不触发,即只轮播一轮CSS动画,不会触发animationiteration事件。
设计大小
本节介绍如何获取元素的大小、视图大小和窗口大小。
使用offsetWidth和offsetHeight
使用offsetWidth和offsetHeight属性可以获取元素的尺寸,其中offsetWidth表示元素在页面中所占据的总宽度,offsetHeight表示元素在页面中所占据的总高度。
- 【实例】使用offsetWidth和offsetHeight属性获取元素大小。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<body>
<div style="height: 50%; height: 50%;">
<div style="height: 50%; height: 50%;">
<div style="height: 50%; height: 50%;">
<div style="height: 50%; height: 50%;">
<div id="div" style="height: 50%;width: 50%; border-style:solid;"></div>
</div>
</div>
</div>
</div>
</body>
<script>
window.onload = function() {
var div = document.getElementById("div");
var w = div.offsetWidth;
var h = div.offsetHeight;
console.log(w);
console.log(h);
}
</script>
</html>
- 提示:上面实例在怪异模式和标准模式的浏览器中解析结果差异很大。
- 注意:offsetWidth和offsetHeight是获取元素尺寸最好的方法,但是当元素隐藏显示时,即设置样式属性display的值为none时,offsetWidth和offsetHeight属性返回值为0。
使用scrollLeft和scrollTop
使用scrollLeft和scrollTop可以读写移出可视区域外面的宽度和高度。
- scrollLeft:读写元素左侧已滚动的距离,即位于元素左边界与元素中当前元素可见内容的最左端之间的距离。
- scrollTop:读写元素顶部已滚动的距离,即位于元素顶部边界与当前可见的最顶端之间的距离。
使用这两个属性可以确定滚动条的位置,或者获取当前滚动区域内容。
获取元素大小
除了offsetWidth和offsetHeight,可以使用下面三组属性获取元素的大小。
元素尺寸属性 | 说明 |
---|---|
clientWidth | 获取元素可视部分的宽度,即CSS的width和padding属性值之和,元素边框和滚动条不包括在内,也不包含任何可能滚动的区域。 |
clientHeight | 获取元素可视部分的高度。同上。 |
offsetWidth | 元素在页面中占据的宽度总和,包括width、padding、border以及滚动条的宽度。 |
offsetHeight | 元素在页面中占据的高度总和。 |
scrollWidth | 当元素设置了overflow:visible样式属性时,元素的总宽度,也称滚动宽度。在默认状态下,如果该属性值大于clientWidth属性值,则元素会显示滚动条,以便能够翻阅被隐藏的区域。 |
scrollHeight | 当元素设置了overflow:visible样式属性时,元素的总高度,也称滚动高度。 |
获取窗口大小
获取<html>
标签的clientWidth和clientHeight属性,就可以知道浏览器窗口的可视宽度和高度,而<html>
标签在脚本中表示document.documentElement。
var w = document.documentElement.clientWidth; // 返回值不包含滚动条的宽度
var h = document.documentElement.clientHeight; // 返回值不包含滚动条的宽度
在怪异模式下,body是最顶层的可视元素,而html元素保持隐藏,所以只有通过<body>
标签的clientWidth和clientHeight属性才可以知道浏览器窗口的可视宽度和高度,而<body>
标签在脚本中表示为document.body。可以这样设计:
var w = document.body.clientWidth;
var h = document.body.clientHeight;
把上面两种方法兼容起来,则设计代码如下。
var w = document.document.documentElement.clientWidth || document.body.clientWidth;
var w = document.document.documentElement.clientHeight || document.body.clientHeight;
如果浏览器支持documentElement,则使用documentElement对象读取;如果该对象不存在,则使用body对象读取。
如果窗口包含内容超出了窗口可视区域,则应该使用scrollWidth和scrollHeight属性来获取窗口的实际宽度和高度。
设计位置
本节介绍如何获取和设置元素的相对位置和绝对位置。
使用offsetLeft和offsetTop
offsetLeft和offsetTop属性返回当前元素的偏移位置。IE怪异模式以父元素为参照进行偏移位置,DOM标准模式以最近定位元素为参照进行偏移的位置。
使用offsetParent
offsetParent属性表示最近的上级定位元素。要获取相对父级元素的位置,可以先判断offsetParent属性是否指向父元素,如果是,则直接使用offsetLeft和offsetTop属性获取相对父元素的距离;否则分别获得当前元素和父元素距离窗口的坐标,然后求差。
// 获取指定元素距离父元素左上角的偏移位置
// 参数:e表示获取位置的元素
// 返回值:返回对象直接量,其中属性x表示x轴偏移距离,属性y表示y轴偏移距离
function getP(e) {
if(e.parentNode == e.offsetParent){
var x = e.offseLeft;
var y = e.offsetTop;
} else {
var o = getPoint(e);
var p = getPoint(e.parentNode);
var x = o.x - p.x;
var y = o.y - p.y;
}
return {
"x": x,
"y": y
}
}
下面调用该扩展函数获取指定元素相对父元素的偏移坐标。
var box = document.getElementById("box");
var o = getP(box); //调用扩展函数获取元素获取元素相对父元素的偏移坐标
console.log(o.x); //读取x轴坐标偏移值
console.log(o.y); //读取y轴坐标偏移值
获取指针的页面设置
使用事件对象的pageX和pageY(兼容Safari),或者clientX和clientY(兼容IE)属性,同时还需要配合scrollLefth和scrollTop属性,就可以计算出鼠标指针在页面中的位置。
// 获取鼠标指针的页面位置
// 参数:e表示当前事件对象;返回值:返回鼠标相对页面的坐标,对象格式(x,y)
function getMP(e){
var e = e || window.event;
return {
x: e.pageX || e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft),
y: e.pageY || e.clientY + (document.documentElement.scrollTop || document.body.scrollTop)
}
}
pageX和pageY事件属性不被IE浏览器支持,而clientX和clientY事件属性又不被Safari浏览器支持,因此可以混合使用兼容不同浏览器。
下面实例演示了如何调用上面扩展函数getMP()捕获当前鼠标在文档中的位置。
<body style="width:2000px;height:2000px">
<textarea name="" id="t" cols="15" rows="4" style="position:fixed;left:50px;top:50px"></textarea>
</body>
<script>
var t = document.getElementById("t");
document.onmousemove = function(e) {
var m = getMP(e);
t.value = "moseX = " + m.x + "\n" + "mouseY = " + m.y;
}
</script>
获取滚动条位置
使用scrollLeft和scrollTop属性也可以获取窗口滚动条的位置。
// 获取页面滚动条的位置
// 参数:无;返回值:返回滚动条位置,其中x表示x轴偏移量,y表示y轴偏移位置
function getPS() {
var h = document.documentElement;
var x = self.pageXOffset || (h && h.scrollLeft) || document.body.scrollLeft;
var y = self.pageYOffset || (h && h.scrollTop) || document.body.scrollTop;
return {
x: x,
y: y
}
}
设置滚动条位置
使用window对象的scrollTo(x, y)方法可以定位滚动条的位置,其中参数x可以定位页面内容在x轴方向上的偏移量,参数y可以定位页面在y轴方向上的偏移量。
设计显隐
CSS使用visibility和display属性控制元素显示或隐藏。visibility和display属性各有优缺点,如果担心隐藏元素会被破坏页面结构和页面布局,可以选用visibility属性。visibility属性能够隐藏元素,但会留下一块空白区域,影响页面视觉效果。如果不考虑布局问题,则可以考虑使用display属性。
显示和隐藏
使用style.display属性可以设计元素和显示和隐藏。恢复style.display属性的默认值,只需设置style.display属性值为空字符串(style.display="")即可。
- 【实例】下面设计一个扩展函数,根据参数决定是否进行显示或隐藏。
// 设置或切换元素的显示或隐藏
// 参数:e表示操作元素,b为ture时,将显示元素e;为false时,将隐藏元素e
// 如果省略参数b,则根据元素e的显示状态进行显示或隐藏切换
function display(e, b) {
// 如果第2个参数存在且不为布尔值,则抛出异常
if (b && (typeof b != "boolean")) {
throw new Error("第2个参数应该是布尔值");
}
var c = getStyle(e, "display"); //获取当前元素显示属性值
(c != "none") && (e._display = c);
e._display = e._display || "";
if (b || (c == "none")) {
e.style.display = e.display;
} else {
e.style.display = "none";
}
}
下面在页面中设置一个向右浮动的元素p。连续调用3次display()函数后,相当于隐藏元素,代码如下:
<p style="float:right; border:solid 1px red; width:100px; height:100px>p1</p>
<script>
var p = document.getElmentsByTagName("p")[0];
display(p); //切换隐藏
display(p); //切换显示
display(p); //切换隐藏
</script>
按如下方式调用,则会显示元素。
display(p, true);
半透明显示
设计元素的不透明度实现方法:IE怪异模式支持filters滤镜集,DOM标准浏览器支持style.opacity属性。它们的取值范围也不同,IE的filterrs属性值范围为0~100,其中0表示完全透明,100表示完全不透明;DOM标准的style.opacity属性值范围为0-1,其中0表示完全透明,1表示不透明。
- 【实例】为了兼容不同浏览器,可以把设置元素透明度的功能进行封装。
// 设置元素的透明度
// 参数:e表示要预设置的元素,n表示一个数值,取值范围为0~100,如果省略,则默认为100,即不透明
function setOpacity(e, n) {
var n = parseInt(n);
if (n && (n > 100) || !n) {
n = 100;
}
if (n && (n < 0)) {
n = 0;
}
if (e.filter) {
e.style.filter = "alpha(opacity = " + n + ")";
} else {
e.style.opacity = n / 100;
}
}
- 提示:在获取元素的透明度时,应注意在IE浏览器中不能够直接通过属性读取,而应借助filters集合的item()方法获取Alpha对象,然后读取它的opacity属性值。
设计动画
js动画主要利用定时器(setTimeout和setInterval)来实现。设计思路,通过循环改变元素的某个CSS样式属性,从而达到动态效果,如果移动位置、缩放大小、渐隐渐显。
移动动画
移动动画主要通过动态修改元素的坐标来实现。技术要点如下:
- 考虑元素的初始坐标、终点坐标,以及移动坐标等定位要素。
- 移动速度、频率等问题可以借助定时器来实现。但效果的模拟设计算法问题,不同的算法,可能会设计出不同的移动效果,如匀速运动、加速和减速运动。
渐隐渐显
渐隐渐显效果主要通过动态修改元素的透明度来实现。
- 【实例】下面实例显示了一个简单的渐隐渐显动画效果。
f<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>test02</title>
</head>
<style type="text/css">
.block {
width: 200px;
height: 200px;
background-color: red;
}
</style>
<body>
<div class="block" id="block1"></div>
</body>
<script>
window.onload = function() {
function setOpacity(e, n) {
var n = parseInt(n);
if (n && (n > 100) || !n) {
n = 100;
}
if (n && (n < 0)) {
n = 0;
}
if (e.filter) {
e.style.filter = "alpha(opacity = " + n + ")";
} else {
e.style.opacity = n / 100;
}
}
function fade(e, t, io) {
var t = t || 10;
if (io) {
var i = 0;
} else {
var i = 100;
}
var out = setInterval(function() {
setOpacity(e, i);
if (io) {
i++;
if (i >= 100) {
clearTimeout(out);
}
} else {
i--;
if (i <= 0) {
clearTimeout(out);
}
}
}, t);
}
e = document.getElementById("block1");
fade(e, 50, true);
}
</script>
</html>