动画
动画
属性
animation-fill-mode
animation-fill-mode
这个 CSS 属性用来指定在动画执行之前和之后如何给动画的目标应用样式。有四个可选值:
animation-fill-mode: none | forwards | backwards | both;
none 默认值。动画执行前后不改变任何样式。
forwards 目标动画执行之后保持动画最后一帧的样式。最后一帧是哪个取决于
animation-direction
和animation-iteration-count
。animation-direction animation-iteration-count last keyframe normal even or odd 100% or to reverse even or odd 0% or from alternate even 0% or from alternate odd 100% or to alternate-reverse even 100% or to alternate-reverse odd 0% or from backwards 目标在动画开始之前(
animation-delay
)保持在第一帧的样式。第一帧是哪个取决于animation-direction
。animation-direction last keyframe normal or alternate 0% or from reverse or alternate-reverse 100% or to both 动画元素在开始之前保持第一帧的样式,在结束之后保持最后一帧的样式。相当于同时设置了 backwards 和 forwards 效果。
另外,该属性可以应用多个参数,使用逗号隔开,各个参数应用于与次序相对应的动画名:
animation-fill-mode: none, backwards
第一个动画不设置填充模式,第二个动画设置 backwards 填充模式。animation-fill-mode: both, forwards, none
第一个动画设置 both 填充模式,第二个动画设置 forwards 填充模式,第三个动画不设置填充模式。
为了加深理解,可以考虑如下的示例:
.box{
transform: translateY(0);
}
.box.on{
animation: move 1s;
}
@keyframes move{
from{transform: translateY(-50px)}
to {transform: translateY( 50px)}
}
那么,对于.box
元素,在加上on
类名之前和之后的translateY
属性的变化与时间的关系图如下:
横轴为表示 时间,为 0 时表示动画开始的时间,也就是向 box 加上 on 类名的时间,横轴一格表示 0.5s。如果设置了
animation-delay
,那么很轴的 0 就会有相应的变化。纵轴表示 translateY 的值,为 0 时表示 translateY 的值为 0,纵轴一格表示 50px。
animation-fill-mode: none
animation-fill-mode: forwards
forwards animation-fill-mode: backwards
backwards animation-fill-mode: both
both
animation-timing-function
该属性定义 CSS 动画在每一动画周期中执行的节奏。
可选值如下:
- ease
- ease-in
- ease-out
- ease-in-out
- linear
<cubic-bezier(0.1, 0.7, 1.0, 0.1)>
- step-start
- step-end
<steps(4, end)>
也可以同时设置多个属性值,使用逗号分隔,各个参数应用于与次序相对应的动画名,表示其独立的执行节奏。
需要注意的是:
- 对于关键帧动画来说,timing function 作用于一个关键帧周期而非整个动画周期,即它会在每一个关键帧都会被执行,而不是应用于动画的整个部分。
- 对于逐帧动画,则是让每帧动画都瞬间完成。
Steps() 函数
动画的时序函数的可选值中,ease
、ease-in
、ease-out
、ease-in-out
、linear
都是三次贝塞尔曲线的特例,效果都是通过三次贝塞尔曲线来做的。
而step-start
、step-end
和steps()
则是另一种方式的动画:逐帧动画。
该函数也可以用于 transition 缓动效果中。
steps
函数指定了一个阶跃函数,第一个参数指定了时间函数中的间隔数量(必须是正整数);第二个参数可选,接受start
和end
两个值,指定在每个间隔的起点或是终点发生阶跃变化,默认为end
。
比如,对于如下的变化效果:
div {
transition: 4s steps(4);
}
div:target {
left: 400px;
}
当时间函数分别设置为transition-time-function: step(4, start)``transition-time-function: step(4, end)
的时候,两者之间的差异如下图所描述:

可以看到,start
值,只要动画被触发,它就会立即开始,而end
值,它开始于第一个步骤的结尾处(在这个案例中,将会在一秒钟之后被触发)。
为了确保这个概述的足够全面,steps()
函数还可以用两个预定义的关键字:step-start
和step-end
代替。前者相当于steps(1, start)
,而后者是相当于steps(1, end)
。
小技巧
使用动画实现轮播
使用animation-delay
属性可以实现简单的轮播效果。以下是一个四屏轮播的例子:
.slider__item {
animation: ani6sinfinite linear both;
@for $i from 1 to 4 {
&:nth-child(#{$i}) {
animation-delay: (-1+$i)*2s;
}
}
}
@keyframes ani {
0%, 33.33% {opacity:1;visibility: visible;}
33.34%, 100% {opacity:0;visibility: hidden;}
}
这样的一个问题在于,最终生成的代码比较多,而且不能在 HTML 中动态的增减轮播屏数。
See the Pen listAni by Yetty on CodePen.
为了能够在鼠标移动到轮播图片上时,暂停动画,可以使用animation-play-state: paused;
。也就是添加如下的设置:
.slider:hover.slider__item{
animation-play-state: paused;
}
有序动画
使用animation-delay
可以实现一个有序动画,元素依次进行动画效果。
比如京东2017海外招聘。效果如下:

调试动画
将animation-play-state
设置为paused
,animation-delay
设置为不同的负值,就可以查看动画在不同帧时的状态,便于进行动画调试。
注意
动画元素不要使用 display 来控制显示和隐藏
对于使用动画的元素,不能一开始设置为display: none;
,然后在动画开始的时候设置为display: block;
来展示元素,因为display
不能应用动画。
如果要实现元素一个个应用动画显现出来,则需要将元素设置透明opacity: 0;
,并设置animation-fill-mode: backwards;
,这样就能让元素在动画进行之前,保持延迟时的状态(透明),这样就不会出现意外了。
下面的两个图片,分别是设置了透明和设置了display
的效果,可以看到设置display
的时候(第二张图片)是先全部显示出来,然后才进行了动画效果的:


如果需要在动画结束后触发一些效果,可以绑定webkitTransitionEnd
事件来触发。比如,我们需要在当前页面的动画都走完了之后,才能继续向下滑动:
$slider.on("webkitTransitionEnd", 'li', function() {
isSlide = false; // slide 动画结束 防止暴力切换
})
.on('touchstart', function(e) {
var touch = e.touches[0];
startX = touch.clientX;
startY = touch.clientY;
if (isSlide) {
e.preventDefault();
}
})
.on('touchmove', function(e) {
e.preventDefault();
var touch = e.touches[0],
posY = touch.clientY,
posX = touch.clientX;
offsetY = posY - startY;
offsetX = posX - startX;
isMove = true;
})
.on("touchend", function(e) {
if (!offsetY || Math.abs(offsetY) < 30 || !isMove) {
return;
}
$this = $(e.target);
if ($this[0].tagName != 'LI') {
$this = $this.closest('li');
}
$this.siblings('li').removeClass('play'); // 防止出现重叠BUG
if (offsetY > 0) { //向下滑动
direction = "down";
$next = $this.prev();
} else { //向上滑动
direction = "up";
$next = $this.next();
}
var current = $this.index();
if (current == 0 && direction == 'down') {
return;
}
if (current == length - 1 && direction == 'up') {
return;
}
if (direction == 'up') {
$this.addClass('move-up');
} else {
$this.addClass('move-down');
}
isSlide = true;
offsetY = 0;
offsetX = 0;
setTimeout(function() {
$this.removeClass('play move-up move-down');
$next.addClass('play').siblings('li').removeClass('play');
}, 300);
});
在touchstart
和touchmove
都调用e.preventDefault
方法,意思是阻止默认行为:第一个调用是为了防止在手指快速的上下滑动的时候触发touchend
中的切换;第二个是 Android 4.0+ 的一个 BUG,就是有时候不会触发touchmove
事件,加了这个后就能触发。不过加了这个后,相应位置的滚动就无效了。
转摘:用CSS3动画
动画库
这个动画库有如下特点:
- 关键帧的选定,不仅有整数,还有小数,并且也不是说有规律的,几的倍数。
- 速度曲线的选定,使用的是
cubic-bezier
函数,自定义贝塞尔曲线。这里有个在线制作贝塞尔曲线的工具。 - 全程使用
transform
属性来实现动画效果,使用了大量的translate3d
、rotate3d
、scale3d
,这样能开启硬件加速。 - 使用
perspective
属性设置镜头到元素平面的距离。