这两天一直在探究CSS Animation中animation-fill-mode
属性中的细节,那是有原因的,具体原因是什么就不多说了。虽然在《理解animation-fill-mode属性》一文让我稍加对该属性有一定的了解。但还有一些潜在的细节和因素还是不为人知。所以我决定花一定的时间彻底的来剖析animation-fill-mode
。如果你感兴趣,请继续往下阅读。
相关的概念
要深入的了解animation-fill-mode
,就很有必要对CSS Animation的一些概念进行了解。对于这些概念,这篇文章并不会深入的介绍,只是简单的说说这些概念,能更好的帮助大家更好的理解后续的内容。
状态
在任何一个动画当中,都会有两个状态:开始状态和结束状态。
上图显示的是一个动画的开始状态,一个蓝色的小圆在左屏幕的左边显示。而下面的另一张图,则表示动画的结束状态,即一个放大的蓝色圆在屏幕的右边显示:
在CSS Animation中,对于这两种状态,在不同情形下是有不同的解释。比如动画的@keyframes
有0%
(或者关键词from
)和100%
(或者关键词to
)的样式,那么开始状态是对应0%
还是100%
状态的样式,这得取决于animation-fill-mode
的值。如果你阅读过前面的文章,你可能会有所了解。当然,在@keyframes
中有时候并不会显式的通过0%
或100%
定义样式,这个时候的初始状态和结束状态,都是CSS给元素定义的样式。
这个示例中animation-fill-mode:both;
,从效果中明显的能看动画的开始状态和结束状态。
插值
前面说了,任何一个动画有两个状态:开始状态和结束状态。而且每个动画都有一个过度函数(timing-function
),能让动画执行过程有一个动画函数,比如一个平稳过渡,就是这个过渡创造了所有中间状态。这种创造中间状态被称为插值。这种插值发现在一段时间内,这段时间是通过animation-duration
来决定。其效果类似于下图:
持续时间和关键帧
了解CSS Animation的同学都知道,是通过animation-duration
的控制一个动画播放持续时间,而动画是通过@keyframes
来声明。而这两者结合在一起就产生了动画的另一个状态:动画进行。如下图所示:
延迟和抵消动画
在CSS Animation中通过animation-delay
属性来控制一个动画延迟播放。如下图所示:
animation-delay
除了可以延迟动画播放之外,还可以抵消动画。当animation-delay
取值为负值时,就可以抵消动画。如下图所示:
动画反转(交替动画)
动画播放默认顺序从0%
到100%
。但可以通过animation-direction
属性可以改变动画播放顺序。其有四个属性值:normal
、reverse
、alternate
或者alternate-reverse
。normal
和reverse
很容易让人理解,但更有意思的是alternate
和alternate-reverse
。
当animation-direction
取值为alternate-reverse
时,动画第一次播放按normal
,第二次开始就是reverse
。这样交替播放:
但animation-direction
设置为alternate
时,它的表现行为又略为不同:
探索animation-fill-mode
前面花了一些篇幅介绍了CSS Animation中的一些概念,只有了解了这些概念,才能更好的去探索animation-fill-mode
属性。通过《理解animation-fill-mode属性》一文的介绍,我们对animation-fill-mode
略有所知。简单的规纳起来:
none
:默认值,使得动画不会对动画等待和动画完成的元素样式产生改变backwards
:在动画等待的那段时间内,元素的样式将设置为动画第一帧的样式forwards
:在动画结束后,元素的样式设置为动画的最后一帧的样式both
:相当于同时配置了forwards
和backwards
。也就是说,动画等待时,元素样式将设置为动画第一帧的样式;而在动画线束状态,元素样式将设置为动画最后一帧样式。
为了能更好的理解上面这四点,咱们先来看一个简单的动画。
在Chrome开发者工具中,可以看到动画对应的Timeline描述:
示例也再次证明了animation-fill-mode
它能够控制元素在动画执行前(动画等待)和动画执行后(动画结束)的样式。前面也说过了,动画默认情况是从0%
到100%
执行,而且对于一个动画,按照时间的执行进行划分的话,一次动画过程可以将元素划分为三个状态:动画等待、动画进行和动画结束。而且这几个过程在动画的Timeline中可以很轻易的描述出来:
针对上面的动画,有几个样式提出来说,首选是元素的默认样式:
.ball {
width: 100px;
height: 100px;
border-radius: 100%;
background-color: #29B4F0;
margin: 5px;
position: relative;
}
通过@keyfarmes
创建了一个move1
的动画:
@keyframes move1 {
0% {
background: pink;
transform: translate3d(0,0,0);
}
100% {
transform: scale(1.5) translate3d(300%, 0, 0);
}
}
这个动画是一个具有两个帧的动画:
- 第一帧(
0%
):修改元素的background-color
为pink
颜色,并且设置了translate3d(0,0,0)
; - 第二帧(
100%
):设置了transform
的值为scale(1.5) translate3d(300%, 0 ,0)
。也就是把元素放大了1.5
倍,并且沿x
轴向右移动了300%
(在这个示例中,大约就是300px
)
从动画中可以了解到,第一帧的样式:
background: pink;
transform: translate3d(0,0,0);
最后一帧样式:
transform: scale(1.5) translate3d(300%, 0, 0);
有了这些,咱们就可以探索animation-fill-mode
的各个值对动画的影响,以及元素的样式表现形式了。
none
:这个效果很好理解,他不会对动画等待和动画完成的元素样式产生任何改变。也就是我们可以忽略对这个属性的探究,后面的示例中,我们也将不再聊none
下的效果。
backwards
:元素.ball
在等待时间内(animation-delay:1s;
),background
会立即变成pink
色,也就是动画0%
时样式(因为元素没有默认的transform
样式,这里看不出变化)。从动画Timeline图上(上图)可以看出,对应的就是带有虚线的那部分。动画结束后,元素回到了其默认样式。
forwards
:元素.ball
在等待时间内样式依旧是元素的默认样式,只有在动画结束后,保持动画最后一帧样式。
both
:元素.ball
在动画等待时间内使用了动画第一帧样式,而在动画结束后保持了动画最后一帧样式。
这是一个简单的效果。从这个简单的效果我们可以得出一个简单的结论:backwards
只会在具有animation-delay
属性设置才会生效;forwards
一定是只有动画完成之后生效。那么这样的结束是否正确呢?我们通过两个简单的示例来验证一下。首先看backwards
具有animation-delay
和没有animation-delay
的效果:
效果一下就能说明一切,这里不做过多阐述。那么再来看forwards
:
上面示例告诉我们,当animation-fill-mode
取值为forwards
时,如果动画是一个循环动画(就是无限次播放),那么意味着动画就没有最后帧这样的状态,从而forwards
就不生效。也就是说:forwards
只有在不是循环动画下才能生效,才能让元素在动画结束时,保留动画最后一帧样式。
这两个示例说的是backwards
和forwards
,那么对于both
呢?both
具有backwards
和forwards
两者特性。那么both
在没有animation-delay
和在循环动画下,又是什么样的情景呢?
老样子,还是写个示例,看效果,比文字描述更为精准:
animation-fill-mode:both
时,当animation-delay
没有设置值时,动画等待时元素不会具备第一帧样式;反之具备动画第一帧样式。这种现象是不循环动画状态下。如果是一个循环动画,并且设置了animation-delay
时,动画第一次播放时,元素具备动画第一帧样式,动画播放第二次的时候和不设置animation-delay
一样。
阅读到这里,发现forwards
、backwards
和both
都和动画的第一帧(0%
)或最后一帧(100%
)定义的样式有关系。那么接下来抛出另一个问题。如果第一帧和最后一帧里的样式与元素默认样式有冲突的时候,该取决于哪一方呢?
上面的示例,动画第一帧和最后一帧和元素默认样式中的transform
相冲突。forwards
值是,动画等待时间内,动画第一帧的transform
并没有覆盖元素默认的transform
样式,但在动画结束状态,动画最后一帧的transfrom
覆盖元素默认的transform
。backwards
时,动画等待时,动画第一帧的transform
将覆盖元素默认transform
样式,但在动画结束状态,动画最后一帧样式并不会覆盖元素默认transform
。对于both
,在动画等待和动画结束状态,第一帧和最后一帧的transform
都会覆盖元素默认的transform
。
简单的总结起来:如果animation-fill-mode
取forwards
,那么动画结束阶段会受到动画结束帧定义的样式的作用;如果该属性取backwards
,那么动画等待阶段,也会受到动画起始帧的作用;如果取both
,那么动画结束跟动画等待阶段都会影响。
前面的内容不断的提到,animation-fill-mode
中forwards
、backwards
和both
或多或少都和动画的第一帧和最后一帧有关系。那么是不是每个动画都有第一帧(0%
)和最后一帧(100%
)。言外之意,有些动画是不会在@keyframes
中设置0%
和100%
。如此一来,animation-fill-mode
取值又会有什么不同的影响呢?
在具体的聊后续内容之前,咱们先来看一个简单的动画,就是把前面的动画修改成不显式设置0%
和100%
的一个动画:
上面的效果大家也看到了,如果动画中没有显式的设置0%
和100%
,对于animation-fill-mode
取不同值时效果。具体介绍animation-fill-mode
值对元素样式影响之前,先来看Timeline的变化:
上图告诉我们,虽然我们在@keyframes
中只定义了一个50%
的帧,并没有显式的定义0%
和100%
,但事实上,动画中同样的具有第一帧和最后一帧。也就是说:
- 任何一个动画中,第一帧和最后一帧不是绝对的
- 第一帧不是永远在
0%
帧处,最后一帧也不是永远在100%
帧处 - 动画
@keyframes
中没有显式的设置0%
和100%
,但animation-fill-mode
的取值的效果是一样的 - 动画
@keyframes
中虽没显式的声明0%
和100%
,并不表示没有第一帧和最后一帧,从而也说明任何一个动画都有第一帧和最后一帧 - 结合前面的示例也能说明,任何一个动画,不管有没有显式的声明
0%
和100%
,动画都有第一帧和最后一帧,只不过这两帧的样式被元素的默认样式覆盖,当然显示的设置了0%
和100%
可以覆盖元素的默认样式
结合这些点,可以得出:animation-fill-mode
和动画第一帧和最后一帧并没有太大关系,其更认动画@keyframes
中的0%
和100%
,只不过在@keyframes
中没有显式的设置0%
和100%
时,其对应的样式被元素的默认样式给覆盖了。
如果你花了大量的时间阅读到这里的话,你应该对animation-fill-mode
有了更深入的了解。在文章开头的时候,动画播放会被animation-direction
属性影响到。假设,有一个动画,animation-direction
不是默认值,而是alternate
,并且播放次数(animation-iteration-count
)不是1
次也是不是无穷次(infinite
),而是2
次。动画的第一帧和最后帧会有何影响。为什么要聊这个话题呢?因为动画的第一帧和最后一帧直接决定animation-fill-mode
取值对元素的影响。
同样的,先来看一个简单的动画:
对应的Timeline如下:
就这个示例而言,第一帧和最后一帧就都是0%
。
上面的示例和图片阐述的是共中的一种情形。如果其中animation-dierction
和animation-iteration-count
取值不一样的时候,@keyframes
中的第0%
和100%
都将不一样。具体的如下表所示:
forwards
animation-direction | animation-iteration-count | 最后一帧(100%) |
---|---|---|
normal | even 或 odd | 100% 或 to |
reverse | even 或 odd | 0% 或 from |
alternate | even | 0% 或 from |
alternate | odd | 100% 或 to |
alternate-reverse | even | 100% 或 to |
alternate-reverse | odd | 0% 或 from |
backwards
animation-direction | 第一帧(0%) |
---|---|
normal 或 alternate | 0% 或 from |
reverse 或 alternate-reverse | 100% 或 to |
如此一来,animation-fill-mode
取值对应的效果就需要就具体的参数设置而言了。
上述阐述的相对而言都是简单的场景,为什么这么说呢?因为这些场景都是单一的动画。如果一个元素上使用多个动画的时候,animation-fill-mode
又将是什么样的场景或者说表现形式呢?我想是比较复杂,也是比较有意思的。在这里我就不把这个场景拿出来阐述了。如果你对这方面感兴趣,欢迎自己去尝试一下。不过,在这里我推荐大家仔细阅读@流云诸葛在《animation-fill-mode
的一些思考》一文中对多个动画中animation-fill-mode
的阐述。除此之外,文章中对于animation-fill-mode
的思考与阐述也是非常的详细。如果仔细阅读的话,将受益非浅。
总结
曾经一直以为自己对CSS Animation非常的了解或者说透彻,但这次踩animation-fill-mode
属性,才知道自己仅仅了解animationf-fill-mode
的一点皮毛。最近花时间整理了一下相关的细节,从此对animation-fill-mode
有了更深的了解。最后希望这篇文章对您有所帮助。如果文章有不对之处,或者说你有更深入的理解,欢迎在下面的评论中与我们一起分享。
如需转载,烦请注明出处:http://www.w3cplus.com/css3/css-animation-fill-mode-property.html