animation
CSS动画
CSS动画相对JS动画有2个主要优势:
1.流畅
因为渲染引擎可以通过跳帧(frame-skipping)及其它技术来确保性能尽量流畅
2.浏览器性能优化
把动画序列交给浏览器去控制,这样浏览器就能优化性能和效率,比如对于看不见的tab,可以减少刷新频率
定义动画分为2部分
1.配置animation各项子属性
2.通过@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 |
动画重复次数,各值分别表示无限次、指定次数
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:https://oss.jqhtml.com/wp-content/uploads/2017/05/animation-fill-mode.html,点击红色块开始动画
animation-play-state
animation-play-state = running | paused
决定动画执行还是暂停,可以用来控制动画暂停/恢复,比delay更强大更灵活一些
具体效果见Demo:https://oss.jqhtml.com/wp-content/uploads/2017/05/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个特殊属性:
1、animationName 即animation-name
2、elapsedTime
单位是秒,对于animationstart和animationend表示动画执行到此刻的时间,对于animationiteration,表示下一次重复开始的时间,与transitionend事件类似,一般不受delay影响
特殊的,animationstart中的elapsedTime一般为0,除非animation-delay是个负值,此时elapsedTime为-1 * delay
3、pseudoElement
以::开头的伪元素名,如果动画不是应用在伪元素上,就是空串
注意:最后一次重复结束的时候,不会触发animationiteration,而是触发animationend
技巧
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; } }
添加关键帧去掉平滑过渡
闪烁效果有另一种有趣的实现方式:
.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,但一般情况下,这样实现闪烁在效果上是没有问题的
关键帧控制延迟
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
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:https://oss.jqhtml.com/wp-content/uploads/2017/05/css-animation-tricks.html
总结
CSS animation的定义方式和Flash非常相似,比如Flash中的几个概念:
关键帧:如果你希望某处的内容要跟前面不一样,就插入关键帧
空白关键帧:表示上面没内容,以小白点显示。他可以跟关键帧互相转换,放了内容就成关键帧了。关键帧上的内容去掉就是空白关键帧
普通帧:关键帧或者空白关键帧后面延续的是普通帧。普通帧是延续之前关键帧的内容,所以他的作用可以来控制动画的显示时间
对应到CSS的@keyframes定义中感受一下,是不是有点意思?