使用 CSS Animation 制作网页上的动画(只要 CSS3,不用 JavaScript!)
这里介绍如何使用 CSS3 的 animation 功能在网页上制作动画,而且不需要使用到 JavaScript。
CSS3 所提供的动画(animation)功能可以让网页元素的 CSS 样式(style)从一个设置转换到另外一个,借着这样的方式产生动画的效果。CSS 的再设置动画时包含两个部份,一个是用来设置 CSS 动画的样式,另外一个则是指定动画开始、结束或中途路径的关键影格(keyframes)设置。

使用 CSS 产生的动画跟传统上以 JavaScript 制作的动画比较起来,有一些优点:
- 使用 CSS 会比 JavaScript 容易很多,对于简单的动画而言,不需要学习 JavaScript 即可马上制作出来。
- 使用 CSS 的动画比较节省资源,甚至在有一定负载量的系统中也可以很平顺的执行,但是 JavaScript 的动画就很容易因为效能问题而跑不起来(除非经过很精心的设计),而且一般浏览器的绘图引擎(rendering engine)还可以通过 frame-skipping 这类的方式,提升整体的效能。
- CSS 把动画播放的控制权交给浏览器控制,这样可以让浏览器进行更多的最佳化动作,例如当一个动画放在背景的签页时,浏览器就可以减低这个动画的升级频率。
设置 CSS 动画
要在网页上制作 CSS 动画,可以使用 animation 相关的 CSS 属性,它可以让你设置动画的播放速度、时间与其他跟动画播放有关的属性,而动画真正的外观则是使用 @keyframes at-rule 来设置(请看随后的说明)。
在 animation 相关属性的部份,可以使用的 CSS 属性有:
| CSS 属性 | 说明 |
| animation-delay | 设定网页元素在被载入之后到开始播放动画之间的等待时间。 |
| animation-direction | 设定网页元素在动画播放完之后,是否要以相反方向的方式播放,或是从头开始以塬来的方向重复播放。 |
| animation-duration | 设定整个动画播放一次的时间长度。 |
| animation-iteration-count | 设定动画播放的次数,若要不断重复播放,则可设为 infinite。 |
| animation-name | 设定 @keyframes at-rule 所使用的动画名称。 |
| animation-play-state | 这个属性可用来暂停或继续动画播放。 |
| animation-timing-function | 透过加速曲线(acceleration curves),设定动画播放的速度。 |
| animation-fill-mode |
设定动画元素在播放前与播放后,如何套用 CSS 的样式。 |
使用 @keyframes 设置动画关键影格(keyframes)
在使用 animation 相关的 CSS 属性定义完动画的速度与时间之后,接着还要再设置动画实际要显现的样子,这个部份则是使用 @keyframes at-rule 来设置,每一个关键影格描述了网页元素在动画中的某个时间点应该呈现的样子。
由于实际的动画播放时间在 CSS 样式中已经定义好了,在关键影格的部份则是使用百分比来指定动画在每个时间点呈现的方式,0% 代表动画一开始播放的起始点,而 100% 则代表动画的结尾,由于这两个时间点很常使用,所以你也可以使用 from 与 to 来分别代表 0% 与 100%。如果没有指定动画的开始点(from)或结束点(to),那么浏览器就会自己计算网页元素在动画开始或结束时的各种属性(大概是使用外差的方式吧)。
除了 0% 与 100% 之外,你也可以再另外加上任何比例的关键影格,设置整个动画的播放方式。
范例
接下来我们以实际的范例让大家了解如何以 CSS 制作网页动画。
滑动的文字标题
第一个例子是让一行文字标题从右方滑进来,下面这些是操作的源程序。
h1 {
animation-duration: 3s;
animation-name: slidein;
}
@keyframes slidein {
from {
padding-left: 100%;
width: 300%;
}
to {
padding-left: 0%;
width: 100%;
}
}
这里使用 animation-duration 这个属性指定 <h1> 的文字标题执行历时 3 秒的动画,animation-name 指定这个动画名称为 slidein,而 @keyframes at-rule 则定义 slidein 这个动画的关键影格。
这里我们是为了让大家容易了解 CSS 动画的用法,所以才尽量让源程序保持简洁,如果你希望让一些不支援 CSS 动画的浏览器可以显示一些其他的 CSS 效果,也可以在这里加入一些其他的 CSS 属性。
动画中的关键影格都是使用 @keyframes at-rule 来设置,在这个例子中只指定了两个关键影格,一个是动画的起始点(from),在这个时间点设置网页元素的 padding-left 为 100%,并且设置元素的宽度 width 为 300%,这样可以让这个网页元素在动画一开始的时候完全隐藏在整个画面的右边。
第二个关键影格是指定动画的结束点(to),在这个时间点上 padding-left 设置为 0%,而 width 设置为 100%,这样就可以让文字标题在动画结束时滑到它该被放置的位置。
这里的 CSS 属性都没有加上任何的 prefix,如果是 WebKit 为基础的浏览器(Chrome 与 Safari 等)或其他比较旧版的浏览器都要加上 prefix 才能正常运作,例如上面的例子如果要让大部份的浏览器都可以运作,就要加上 -webkit- 与 -moz- 这两个 prefix:
h1 {
-webkit-animation-duration: 3s;
-moz-animation-duration: 3s;
-webkit-animation-name: slidein;
-moz-animation-name: slidein;
}
@-webkit-keyframes slidein {
from {
padding-left: 100%;
width: 300%;
}
to {
padding-left: 0%;
width: 100%;
}
}
@-moz-keyframes slidein {
from {
padding-left: 100%;
width: 300%;
}
to {
padding-left: 0%;
width: 100%;
}
}
虽然这样源程序显得很冗长,但是为浏览器的兼容性也只能这样,在接下来的 CSS 源程序中都有这样的状况,以下就不再赘述,请大家自己注意一下。
下面这个是实际的示范,请把鼠标移到文字上,动画就会开始播放。
滑动的文字标题
增加动画关键影格
接着我们在上面的例子中再加入一个关键影格,让这个文字标题在滑动时,字体大小会跟着慢慢变大再缩小成原来的样子:
75% {
font-size: 300%;
padding-left: 25%;
width: 150%;
}
这段源程序是设置在整段动画播放到 75% 的时间点上,文字标题的字型大小 font-size 应该变为 300%、padding-left 应该变为 25%,宽度 width 则为 25%。
下面这个是实际的示范,请把鼠标移到文字上,动画就会开始播放。
重复播放动画
若要让动画重复播放,只要加入 animation-iteration-count 这个属性并指定重复的次数即可。这里我们将重复次数指定为 infinite,让动画一直持续重复播放。
h1 {
animation-duration: 3s;
animation-name: slidein;
animation-iteration-count: infinite;
}
下面这个是实际的示范,请把鼠标移到文字上,动画就会开始播放。
让文字标题来回滑动
如果只是让动画重复播放,当一段动画播放结束后再重新播放时,就会发生文字突然从最左边(动画结尾)跳到最右边(动画开头),这样其实感觉不是很自然。
如果想让整个文字标题动画看起来可以比较平顺的来回滑动,可以将 animation-direction 这个属性设置为 alternate。
h1 {
animation-duration: 3s;
animation-name: slidein;
animation-iteration-count: infinite;
animation-direction: alternate;
}
下面这个是实际的示范,请把鼠标移到文字上,动画就会开始播放。
使用动画事件(events)
动画的事件(events)提供网页设计者更多的操控方式与动画的相关信息,这类的事件都是以 AnimationEvent 对象来表示,它可以用来侦测动画的开始、结束或重新播放的时间点,每个事件中都纪录该事件发生的时间与产生该事件的动画名称。
接下来我们将修改上面的滑动文字标题范例,让它输出一些动画播放的信息,藉此了解整个动画的运作过程。
加入动画的事件倾听者(event listeners)
这里我们使用 JavaScript 来接收动画所产生的事件,下面这个 setup() 函数内容就是设置动画的事件倾听者(event listeners),这个函数通常都是在网页一开始载入时就被调用,作为初始化的一部分。
function setup() {
var e = document.getElementById("watchme");
e.addEventListener("animationstart", listener, false);
e.addEventListener("animationend", listener, false);
e.addEventListener("animationiteration", listener, false);
var e = document.getElementById("watchme");
e.className = "slidein";
}
这里设置了三个事件的倾听者,分别为 animationstart(动画开始播放)、animationend(动画结束) 与 animationiteration(动画重新播放)。这段源程序是非常标准的写法,如果想更了解它是如何运作的,可以参考 element.addEventListener() 的说明文件。
在这个 setup() 函数的最后将这个网页元素的 className 设置为 slidein,这个动作会让动画开始播放。
由于动画一开始播放的时候就会产生 animationstart 事件了,在这个范例中如果让动画太早播放,JavaScript 的程序就会来不及初始化,所以这里我们使用这样的方式让动画开始的时间放在 JavaScript 程序的最后,确保动画开始播放时,所有的准备工作都已经完成了。
由于每一个浏览器对于这些事件的命名都不太一样,这里我们是使用 W3C 的标准,以下是各种浏览器的事件命名方式:
| W3C 标准 | animationstart | animationiteration | animationend |
| Firefox | animationstart | animationiteration | animationend |
| webkit | webkitAnimationStart | webkitAnimationIteration | webkitAnimationEnd |
| Opera | oanimationstart | oanimationiteration | oanimationend |
| IE10 | MSAnimationStart | MSAnimationIteration |
MSAnimationEnd |
所以在指定事件倾听者时,如果想要涵盖各种不同的浏览器,就要把这些状况都考虑进去,以下是一个简单的小函数,可以一次加入所有浏览器需要的事件倾听者:
var pfx = ["webkit", "moz", "MS", "o", ""];
function PrefixedEvent(element, type, callback) {
for (var p = 0; p < pfx.length; p++) {
if (!pfx[p]) type = type.toLowerCase();
element.addEventListener(pfx[p]+type, callback, false);
}
}
// animation listener events
PrefixedEvent(e, "AnimationStart", listener);
PrefixedEvent(e, "AnimationIteration", listener);
PrefixedEvent(e, "AnimationEnd", listener);
接收事件
上面的设置中,我们将所有的事件都递送给 listener() 这个函数,而这个函数定义如下:
function listener(e) {
var l = document.createElement("li");
switch(e.type) {
case "animationstart":
l.innerHTML = "Started: elapsed time is " + e.elapsedTime;
break;
case "animationend":
l.innerHTML = "Ended: elapsed time is " + e.elapsedTime;
break;
case "animationiteration":
l.innerHTML = "New loop started at time " + e.elapsedTime;
break;
}
document.getElementById("output").appendChild(l);
}
这段源程序也很简单,他做的事情就是检查 event.type,判断事件的种类,然后将输出放到一个 id 为 output 的 <ul> 中。
这里如果也要考虑不同浏览器的状况的话,可以把判断式改写成这样的形式:
if (e.type.toLowerCase().indexOf("animationend") >= 0) {
// ...
}
这样就可以处理各种浏览器所产生的事件。
HTML 网页源程序
这里的 HTML 网页源程序主要包含会滑动文字标题与输出用的 <ul>。
<body onload="setup()"><h1 id="watchme">Watch me move</h1><ul id="output"></ul></body>
下面这个是实际的示范,请把鼠标移到文字上,动画就会开始播放。
滑动的文字标题
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
- Started: elapsed time is 0
这里我们放在网页上的源程序都尽量以比较简单的方式撰写,方便大家理解其中的重点,而在这个网页中实际示范部分,因为要把一些 JavaScript 与 CSS 等源程序内崁在 Blogger 博客的文章中,所以有经过一些小修改,不过大致上的概念都是一样的。如果你对于这样内崁的方式有兴趣,当然也可以直接查看这个网页的源代码,比较看看这些源程序跟网页上的差异。
參考资料:Mozilla Developer Network、unmatchedstyle、sitepoint
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
