一.CSS动画
CSS动画相对JS动画有2个主要优势:
1.流畅
因为渲染引擎可以通过跳帧(frame-skipping)及其它技术来确保性能尽量流畅
2.浏览器性能优化
把动画序列交给浏览器去控制,这样浏览器就能优化性能和效率,比如对于看不见的tab,可以减少刷新频率
定义动画分为2部分
配置
animation
各项子属性通过
@keyframes
定义关键帧样式
浏览器根据这些东西来创建补间动画,计算插值把各个关键帧连接起来
二.animation子属性
animation-name @keyframes定义的关键帧名,默认none
animation-duration 动画时长,默认0s,与transition完全一致
animation-timing-function easying函数,默认ease,与transition完全一致
animation-delay 延迟时间,默认0s,,与transition完全一致
animation-iteration-count 重复次数,默认1
animation-direction 方向,默认normal
animation-fill-mode 样式应用模式,默认none
animation-play-state 用来暂停/恢复动画序列,默认running
需要注意:
先
duration
后delay
,其它参数顺序随意animation-name
不要和关键字重名,会优先匹配属性
animation-iteration-count
animation-iteration-count = infinite | <number>
动画重复次数,各值分别表示无限次、指定次数
animation-direction
animation-direction = normal | reverse | alternate | alternate-reverse
动画执行方向,各值分别表示正向、反向、交替(奇数次正向偶数次反向)、反向交替(奇数次反向偶数次正向)
animation-fill-mode
animation-fill-mode = none | forwards | backwards | both
样式应用模式,各值分别表示不应用关键帧样式、(结束后)应用终态样式、(delay期间)应用初态样式、(delay期间)应用初态样式且(结束后)应用终态样式
注意:初态和终态可能是0%
也可能是100%
,由animation-iteration-count
和animation-direction
共同决定
关键字含义如下:
none 在动画结束后,去掉@keyframes定义的样式,恢复原样式
forwards 在动画结束后,保持终态样式
backwards 在动画开始前(delay期间),保持初态样式
both 同时具有forwards和backwards的效果,即在delay期间保持初态样式,在动画结束后保持终态样式
具体差异见Demo:http://www.ayqy.net/temp/animation/animation-fill-mode.html,点击红色块开始动画
animation-play-state
animation-play-state = running | paused
决定动画执行还是暂停,可以用来控制动画暂停/恢复,比delay
更强大更灵活一些
具体效果见Demo:http://www.ayqy.net/temp/animation/animation-play-state.html
三.@keyframes
语法如下:
@keyframes anmiationName {
0% {}
/*...*/
100% {}
}
如果没有定义0%
和100%
,浏览器就根据其它时刻的关键帧给所有属性算一组值
P.S.to
和from
分别是0%
和100%
的别名,因为初态和终态比较重要,有权申请英文名
四.事件
transition
只有一个end
事件,animation
提供了3个事件:
animationstart 开始
animationend 结束
animationiteration 开始下一次重复
事件对象有3个特殊属性:
animationName
即
animation-name
elapsedTime
单位是秒,对于
animationstart
和animationend
表示动画执行到此刻的时间,对于animationiteration
,表示下一次重复开始的时间,与transitionend
事件类似,一般不受delay影响特殊的,
animationstart
中的elapsedTime
一般为0
,除非animation-delay
是个负值,此时elapsedTime
为-1 * delay
pseudoElement
以
::
开头的伪元素名,如果动画不是应用在伪元素上,就是空串
注意:最后一次重复结束的时候,不会触发animationiteration
,而是触发animationend
五.技巧
1.steps(1)去掉平滑过渡
steps(1)
与linear
很像,去掉一个linear
动画的补间过渡,只留下关键帧,关键帧之间的帧延续上一个关键帧,就得到了steps(1)
制作Flash时,先插入两个关键帧,此时两个关键帧之间的都是普通帧(用来延长上一个关键帧的播放时间),这时的效果就是steps(1)。右键后一个关键帧,创建补间动画,此时得到的就是linear
效果
实例如下:
.rgb {
-webkit-animation: rgb 1.5s linear infinite;
animation: rgb 1.5s linear infinite;
}
@keyframes rgb {
0% {
opacity: red;
}
33% {
background: green;
}
66% {
background: blue;
}
}
效果是背景色红绿蓝平滑渐变,想去掉渐变的平滑过渡,直接把linear
改为steps(1)
即可,如下:
.rgb-step {
-webkit-animation: rgb 1.5s steps(1) infinite;
animation: rgb 1.5s steps(1) infinite;
}
效果就变成了每0.5秒切换一次背景色,没有渐变过渡
具体应用:两种状态无限切换(闪烁)
.blink {
-webkit-animation: blink 1s steps(1) infinite;
animation: blink 1s steps(1) infinite;
}
@keyframes blink {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
}
2.添加关键帧去掉平滑过渡
闪烁效果有另一种有趣的实现方式:
.blink {
-webkit-animation: blink 1s linear infinite;
animation: blink 1s linear infinite;
}
@keyframes blink {
0% {
opacity: 0;
}
50% {
opacity: 0;
}
50.01% {
opacity: 1;
}
100% {
opacity: 1;
}
}
虽然还是linear
平滑过渡,但插入的:
50.01% {
opacity: 1;
}
去掉了50% -> 100%
的补间,把透明度补间转移到50% -> 50.01%
,时间较短的情况下,这个补间变化不会被察觉,当然,如果时间足够长,比如:
.blink {
-webkit-animation: blink 10000s linear infinite;
animation: blink 10000s linear infinite;
}
就应该能看到透明度在某1秒内从0渐变到1,但一般情况下,这样实现闪烁在效果上是没有问题的
3.关键帧控制延迟
animation-delay
只在动画开始前有效,每次重复不会插入延迟。类似于上面50.01%
的技巧,可以通过插入空白关键帧来给每次重复插入延迟,实现loading转一圈等一等的效果:
.wait {
-webkit-animation: wait 1s linear infinite;
animation: wait 1s linear infinite;
}
@keyframes wait {
0% {
-webkit-transform: rotateZ(0);
transform: rotateZ(0);
}
40% {
-webkit-transform: rotateZ(0);
transform: rotateZ(0);
}
100% {
-webkit-transform: rotateZ(360deg);
transform: rotateZ(360deg);
}
}
做到了每转一圈等0.4s
4.steps逐帧动画
把序列帧平铺在一张图片上,修改background-position
用steps()
实现的话需要在末尾复制第一帧(比如6帧动画,需要7帧平铺图),例如:
.walk {
background: url(walk.svg);
width: 162px;
height: 230px;
-webkit-animation: walk 1s steps(22) infinite;
animation: walk 1s steps(22) infinite;
}
@keyframes walk {
0% {
background-position: 0 0;
}
100% {
background-position: -3564px 0;
}
}
其中walk.svg
横向铺满了23帧,每帧尺寸是162 * 230
,向左抽背景图片,最多能抽162 * 22 = 3564
,此时显示最后一帧(图片帧内容与第一帧相同),首尾接起来
当然,还有另一种方法,用steps(1)
去掉平滑过渡,然后手动设置22个关键帧,比较费劲,这里不给例子,但肯定是可行的
在线Demo:http://www.ayqy.net/temp/animation/css-animation-tricks.html
六.总结
CSS animation的定义方式和Flash非常相似,比如Flash中的几个概念:
关键帧:如果你希望某处的内容要跟前面不一样,就插入关键帧
空白关键帧:表示上面没内容,以小白点显示。他可以跟关键帧互相转换,放了内容就成关键帧了。关键帧上的内容去掉就是空白关键帧
普通帧:关键帧或者空白关键帧后面延续的是普通帧。普通帧是延续之前关键帧的内容,所以他的作用可以来控制动画的显示时间
对应到CSS的@keyframes
定义中感受一下,是不是有点意思?
1