# 语法
keyframe
动画的实现原理跟 flash
的实现方式类似,在 CSS 块之间进行关键帧的属性的更新。下面定义一个 keyframe
动画,将元素的水平位置从 -100%
平滑地渐变到 0%
:
@keyframes slide-in { | |
from { | |
transform: translateX(-100%); | |
} | |
to { | |
transform: translateX(0%); | |
} | |
} |
每个 @keyframes
语句都需要一个名称,一般为交互动画效果名称,上面的代码定了一个滑入 slide-in
的效果名称。
和其它 CSS 一样, keyframe
动画也是可以通用的和可重用的,可以将它们应用到特定选择器的 animation
属性中:
.slide-in { | |
animation: slide-in 1000ms; | |
} |
上面的代码定了在 1000ms
内,将 translateX
属性进行改变,并且立即执行。
可以在同一个动画声明中定义多个属性的变化,如下:
.drop-in { | |
animation: drop-in 1000ms; | |
} | |
@keyframes drop-in { | |
from { | |
transform: rotate(-30deg) translateY(-100%); | |
opacity: 0; | |
} | |
to { | |
transform: rotate(0deg) translateY(0%); | |
opacity: 1; | |
} | |
} |
# 动画效果
动画效果使用 animation-timing-function
属性,定义 CSS 动画在每一动画周期中执行的节奏,既是常说的动画效果,类似 jquery
中的 easing
。
.ease-in-out { | |
animation-timing-function: ease-in-out; | |
} |
# 循环动画
默认情况下, keyframe
动画只会运行一次,但可以使用 animation-iteration-count
属性来控制动画执行次数。
.for-three { | |
animation-iteration-count: 3; | |
} |
如果是无限次将其值设置为 infinite
,有限次就按照具体要求输入次数。
.spinner { | |
animation: spin 1000ms; | |
animation-timing-function: linear; | |
animation-iteration-count: infinite; | |
} | |
@keyframes spin { | |
from { | |
transform: rotate(0turn); | |
} | |
to { | |
transform: rotate(1turn); | |
} | |
} |
# 多步动画
除了 from
和 to
关键字,还可以使用百分比,可以定义两个及以上的动画步骤:
.fancy-spinner { | |
animation: fancy-spin 2000ms; | |
animation-iteration-count: infinite; | |
} | |
@keyframes fancy-spin { | |
0% { | |
transform: rotate(0turn) scale(1); | |
} | |
25% { | |
transform: rotate(1turn) scale(1); | |
} | |
50% { | |
transform: rotate(1turn) scale(0.5); | |
} | |
75% { | |
transform: rotate(0turn) scale(0.5); | |
} | |
100% { | |
transform: rotate(0turn) scale(1); | |
} | |
} |
# 交替动画
假设要让一个元素 “呼吸”,充气和放气。 可以将其设置为 3 步动画:
.grow-shrink { | |
animation: grow-and-shrink 4000ms; | |
animation-iteration-count: infinite; | |
animation-timing-function: ease-in-out; | |
} | |
@keyframes grow-and-shrink { | |
0% { | |
transform: scale(1); | |
} | |
50% { | |
transform: scale(0.5); | |
} | |
100% { | |
transform: scale(1); | |
} | |
} |
上面的动画效果还有一种更优雅的方式,使用 animation-direction
属性,用来指示动画是否反向播放。
@keyframes grow-and-shrink { | |
0% { | |
transform: scale(1); | |
} | |
100% { | |
transform: scale(0.5); | |
} | |
} | |
.grow-shrink { | |
animation: grow-and-shrink 2000ms; | |
animation-timing-function: ease-in-out; | |
animation-iteration-count: infinite; | |
animation-direction: alternate; | |
} |
上面定义的动画都是根据不同属性定义不同的值,和其他 CSS 属性一样,可以只定义一个属性值,即
animation
。
上面定义动画属性的方式如下:
animation: grow-and-shrink 2000ms; | |
animation-timing-function: ease-in-out; | |
animation-iteration-count: infinite; | |
animation-direction: alternate; |
更简洁的方式,也是推荐使用的方式,跟 padding
不一样的是顺序无关紧要:
animation: grow-and-shrink 2000ms ease-in-out infinite alternate; |
# 填充模式
keyframe
动画令人困惑的方面可能是填充模式,它们是通往 keyframe
信心之路的最大障碍。例如希望元素淡出,动画本身运行良好,但是当它结束时,元素会重新出现一下导致闪现的效果:
.fade-out { | |
animation: fade-out 1000ms; | |
} | |
@keyframes fade-out { | |
from { | |
opacity: 1; | |
} | |
to { | |
opacity: 0; | |
} | |
} |
为什么元素会执行完动画后重新再闪现一下并完全可见了,这是因为 from
和 to
块中的声明只在动画运行时有效。
1000ms
动画完成过后,元素就按照 CSS 声明显示,而透明度默认情况下是不透明的。因此动画完成后透明度又恢复到不透明了。
解决这个问题的一种方法是在动画之外声明透明度,如下:
.fade-out-2 { | |
animation: fade-out 1000ms; | |
opacity: 0; | |
} |
上面的方案虽然解决了问题,但这不是最佳的方式。最佳的方式是使用属性 animation-fill-mode
,设置 CSS 动画在执行之前和之后如何将样式应用于其目标。
.fade-out-forwards { | |
animation: fade-out 1000ms; | |
animation-fill-mode: forwards; | |
} |
animation-fill-mode
属性的参数有以下四个:
none
:这是默认值,当动画未执行时,动画将不会将任何样式应用于目标,而是已经赋予给该元素的 CSS 规则来显示该元素;forwards
:目标将保留由执行期间遇到的最后一个关键帧计算值,最后一个关键帧取决于animation-direction
和animation-iteration-count
的值;backwards
:动画将在应用于目标时立即应用第一个关键帧中定义的值,并在animation-delay
期间保留此值。 第一个关键帧取决于animation-direction
的值;both
:动画将遵循forwards
和backwards
的规则,从而在两个方向上扩展动画属性。
# 动态动画
keyframe
动画实现了基本的动画效果,将它们与 CSS 变量一起使用的时候可以定义更加复杂的效果。
.bounce-box { | |
animation: bounce 300ms alternate infinite cubic-bezier(0.2, 0.65, 0.6, 1); | |
} | |
@keyframes bounce { | |
from { | |
transform: translateY(0px); | |
} | |
to { | |
transform: translateY(62px); | |
} | |
} |
CSS 动画是可以通用的和可重用的,但是这个动画总是会让一个元素弹跳 62px。如果不同的元素可以提供不同的 “弹跳高度”,就提高了动画的灵活性。
使用 CSS 变量,就可以做到:
@keyframes bounceY { | |
from { | |
transform: translateY(0px); | |
} | |
to { | |
transform: translateY(var(--bounce-offset)); | |
} | |
} | |
.bounceY-box { | |
float: left; | |
animation: bounce alternate infinite cubic-bezier(0.2, 0.65, 0.6, 1); | |
} | |
.bounceY-box.one { | |
--bounce-offset: 62px; | |
animation-duration: 200ms; | |
} | |
.bounceY-box.two { | |
--bounce-offset: 32px; | |
animation-duration: 300ms; | |
} | |
.bounceY-box.three { | |
--bounce-offset: -40px; | |
animation-duration: 400ms; | |
} |