Home  >  Article  >  Web Front-end  >  Some thoughts on animation-fill-mode

Some thoughts on animation-fill-mode

WBOY
WBOYOriginal
2016-08-10 08:49:431176browse

animation-fill-mode is a property of CSS3 animation, which can control the style of elements before the animation is executed and after the animation is completed. An animation with delay and executed in the normal direction (the normal direction refers to running from 0% to 100%), the execution process can be described as follows:

Some thoughts on animation-fill-mode

Divided according to the execution time of the animation, an animation process Elements can be divided into 3 states: animation waiting, animation progress and animation end state. By default, the style defined by the animation's keyframes will be applied only when the animation is in progress; while in the animation waiting and animation end states, it will not affect the style of the element. animation-fill-mode has four values, namely:

none: This is the default value. It is this value that causes the animation to not change the element style of animation waiting and animation completion;

backwards: If set to This value, then during the period when the animation is waiting, the style of the element will be set to the style of the first frame of the animation;

forwards: If set to this value, then after the animation ends, the style of the element will be set to the style of the animation The style of the last frame;

both: It is equivalent to configuring backwards and forwards at the same time, which means that in the animation waiting and animation end states, the element will apply the styles of the first and last frames of the animation respectively.

Through the demo below, you can feel the effects of the three non-none values ​​of animation-fill-mode.

Some thoughts on animation-fill-mode: http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Some thoughts on animation-fill-mode

The effect is as follows:

Some thoughts on animation-fill-mode

less source code:

<span style="color: #800000">#Some thoughts on animation-fill-mode </span>{<span style="color: #ff0000">
  .target.animate {
    animation-name</span>:<span style="color: #0000ff"> move_1</span>;<span style="color: #ff0000">
    animation-duration</span>:<span style="color: #0000ff"> 2s</span>;<span style="color: #ff0000">
    animation-delay</span>:<span style="color: #0000ff"> 1s</span>;<span style="color: #ff0000">

    &.target_1 {
      animation-fill-mode</span>:<span style="color: #0000ff"> backwards</span>;
    }<span style="color: #800000">
    &.target_2 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> forwards</span>;
    }<span style="color: #800000">
    &.target_3 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> both</span>;
    }<span style="color: #800000">
  }
}

@keyframes move_1 </span>{<span style="color: #ff0000">
  0% {
    transform</span>:<span style="color: #0000ff"> translate(-50px, 0)</span>;
  }<span style="color: #800000">

  50% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(0, 0)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(50px, 0)</span>;
  }<span style="color: #800000">
}</span>

在以上demo中,定义了一个move_1的动画,它包含三个关键帧,第一帧让元素往左偏移50px,最后一帧让元素往右偏移50px,这个偏移都是相对元素的初始状态而言的(就是没有添加动画的状态)。demo中从上到下有三个元素,分别应用了animation-fill-mode属性的三个值:backwards,forwards,both。结合前面对这三个属性值的说明,相信不难理解demo中三个元素的动画效果:

backwards和both使得第一个元素和第三个元素,在动画添加后都立即变为动画第一帧的状态。而第二个元素没有应用第一帧的状态。

forwards和both使得第二个元素和第三个元素,在动画结束后仍然保持动画最后一帧的状态。而第1个元素没有。

以上内容可能会让人觉得animation-fill-mode是一个比较简单的属性,因为它的作用非常的简单明了。尽管如此,我在最近做一些动画效果的时候却发现,这个属性在真正使用的时候要想完全融会贯通地去使用,还真不是那么容易,尤其是当我们需要同时应用多个动画,定义连续的复杂动画时,就可能会在写动画的过程中,碰到一些自己按理论不能理解清楚的点,虽然最后吧,我们总是能想办法搞定我们遇到的问题,那是因为这个属性毕竟只有那么几个值,多加调试当然能解决问题,但是做完了,心里面还是想解决那个为什么我之前那么写就不行的问题。所以本文从一些非常规的角度来研究animation-fill-mode在实际使用过程中可能会存在理解偏差的问题,我不敢保证在本文中,我提出的一些理解方式一定是正确的,只是以我现在的经验,只能得出这么些结论。希望本文可以抛砖引玉,发现一些更可靠更完美的思想。

首先,我想对animation-fill-mode的理论知识再做一次补充说明:

1)在animation-fill-mode的基础知识中,有这么几个关键词:动画等待时间(也叫动画延迟时间),动画结束后,第一帧,最后一帧。这些关键词的更深的含义是:

a. backwards一定是在动画延迟时间内才会生效;

b. forwards一定在动画完成之后才会生效,对于一个循环的动画来说,它没有动画完成后的状态,所以forwards不会起作用;

c. 第一帧和最后一帧不是绝对的,就是说第一帧不一定永远跟0%这帧对应,最后一帧不一定永远跟100%这帧对应。具体到底0%是第一帧还是100%是第一帧,跟另外两个动画属性有关系:animation-direction和 animation-iteration-count。举个例子:当animation-direction是alternate,animation-iteration-count是2的时候,第一帧和最后一帧就都是0%。至于为啥是这样,自己简单画个图就好理解了:

Some thoughts on animation-fill-mode

详细的规则在mdn上有完整地说明,所以这里不会再赘述了。这个规则并不存在理解偏差的问题,但是对于animation-fill-mode的第一帧跟最后一帧该如何判别还是比较重要的,所以有必要记录一下。

为了不增加以下内容的复杂性,剩下的内容都将以animation-direction为normal,animation-iteration-count为1这个前提来说明。接下来就来看看animation-fill-mode这个属性,还有哪些问题值得花点心思研究研究的。

1. 动画没有定义0%或100%的时候

假如我们动画里没有定义0%或100%,只定义了中间百分比的关键帧,animation-fill-mode会有什么样的表现呢?

先来观察Some thoughts on animation-fill-mode:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Some thoughts on animation-fill-mode

Some thoughts on animation-fill-mode

less源码:

<span style="color: #800000">#Some thoughts on animation-fill-mode </span>{<span style="color: #ff0000">
  .target.animate {
    animation-name</span>:<span style="color: #0000ff"> move_2</span>;<span style="color: #ff0000">
    animation-duration</span>:<span style="color: #0000ff"> 2s</span>;<span style="color: #ff0000">
    animation-delay</span>:<span style="color: #0000ff"> 1s</span>;<span style="color: #ff0000">

    &.target_1 {
      animation-fill-mode</span>:<span style="color: #0000ff"> backwards</span>;
    }<span style="color: #800000">
    &.target_2 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> forwards</span>;
    }<span style="color: #800000">
    &.target_3 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> both</span>;
    }<span style="color: #800000">
  }
}

@keyframes move_2 </span>{<span style="color: #ff0000">
  50% {
    transform</span>:<span style="color: #0000ff"> scale(1.2, 1.2)</span>;
  }<span style="color: #800000">
}</span>

In this demo, you will see three elements with different animation-fill-mode applied, but the final effect is exactly the same. This is because 0% and 100% are not defined in the animation, causing animation-fill-mode to not be able to find the first and last frames it needs. Although in the demo animation above, 50% is in the animation definition, it is the only frame. According to our understanding of uniqueness, the 50% frame can be regarded as either one frame or the last frame. , but animation-fill-mode only recognizes 0% and 100% in the animation definition, not the first and last frames in the animation definition.

So does it mean that without 0% and 100%, animation-fill-mode must have no effect?

Actually not. When there are no 0% and 100% in the animation definition, it does not mean that the animation has no start frame and end frame. Any animation must have a start frame and an end frame. By default, the start frame and end frame The corresponding style is the style before the animation is added to the element. We can override the default start frame and end frame definitions through 0% or 100%. In other words, when there is no 0% or 100%, animation-fill-mode still works, but it uses the initial state of the element to work, so you can't tell.

The conclusion in the previous paragraph, I did not see it introduced in w3c, but I guessed it based on some of my own thinking and observations. Next, I will use Chrome's animation debugging tool to assist in explaining my judgment. When I introduce the practice of animation-fill-mode in multiple animations later, I will also combine an example and use these theories to explain.

The new version of chrome provides the function of animation debugging, which can be opened as follows:

Some thoughts on animation-fill-mode

After the Animations tab appears, you will see a console similar to the one below, where we can debug animations by controlling the timeline:

Some thoughts on animation-fill-mode

When the Animations console is opened, it will monitor the animation effects in the page after the page is loaded. For example, when we click the add animation button of Some thoughts on animation-fill-mode, the console can see the animation happening in Some thoughts on animation-fill-mode:

Some thoughts on animation-fill-mode_2

This animation console can realize powerful animation management functions such as adjusting the animation timeline, animation pause, animation speed control, and frame-by-frame observation. However, this article will not introduce its use in depth. If you are interested, you can Use it a lot at work. Now I want the presentation of this animation console to illustrate the conclusion I made earlier. My previous conclusion is: Any animation, regardless of whether 0% and 100% are defined or not, must have a start frame and an end frame, but we Can be overridden with 0% and 100%.

Going back to Some thoughts on animation-fill-mode of this article, I refreshed the page, then clicked the add animation button in Some thoughts on animation-fill-mode, and then observed the animation console. The content it presented was:

Some thoughts on animation-fill-mode

Since the animation of Some thoughts on animation-fill-mode contains a total of three keyframe definitions, in the animation console, we can see that the animation timeline of each element contains three points, including the first point and the last point. They are all solid, which means they are the start and end frames of the animation; and the dots in the middle are hollow, which means they are key frames during the execution of the animation.

Look at Some thoughts on animation-fill-mode again, I added animation in the same way, and then look at the console:

Some thoughts on animation-fill-mode

对比Some thoughts on animation-fill-mode的截图,可以发现,尽管Some thoughts on animation-fill-mode中的动画只定义了1个50%的关键帧,但是在动画的时间轴上,依然出现了代表起始帧和结束帧的点,这也从一方面说明了,动画不管有没有0%和100%,起始帧和结束帧是一定存在的。

前面这个小结论,对于后面更复杂的一个实例的理解,比较关键,也是基于它,我才能得出后面更大的一个关于动画过程中属性冲突时优先级的猜想,所以这里花了不少的内容来介绍它。

接下来继续后面要探究的问题。

2. 动画作用过程中的样式与元素初始状态的样式冲突

在这个问题标题中,我用到了“动画作用过程”这个短语,而不是“动画过程”,是因为这两个的含义是不一样的。按照文首对动画阶段的划分,一个元素添加一个动画后,它就会经历三个阶段:动画等待,动画执行和动画结束。我们知道动画要做的事情,就是把动画定义里面的样式应用到元素上,而且我们可以确定的是动画执行阶段,动画定义的样式是一定会作用到元素之上的。那么在动画等待以及动画结束阶段呢,动画定义的样式是否也会作用到元素之上?这个就跟animation-fill-mode有关系了,如果该属性取forwards,那么动画结束阶段会受到动画结束帧定义的样式的作用;如果该属性取backwards,那么动画等待阶段,也会受到动画起始帧的作用;如果取both,那么动画结束跟动画等待阶段都会影响。换句话说:

如果animation-fill-mode取none,动画对一个的作用过程,简称之动画作用过程,就仅仅包括了动画执行阶段;

如果animation-fill-mode取backwards,动画作用过程就包含动画等待阶段跟动画执行阶段;

如果animation-fill-mode取forwards,动画作用过程就包含动画执行阶段跟动画结束阶段;

如果animation-fill-mode取both,动画作用过程就是整个添加动画之后的过程了。

以上提到的这个结论是对单个动画而言的,如果一个元素应有了多个动画,那么每个动画都会满足这个结论。

我们可以从动画控制台来直观感受下动画作用过程的不同类型。

这个结论,我也做了一个demo:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Some thoughts on animation-fill-mode

Some thoughts on animation-fill-mode

less源码:

<span style="color: #800000">#Some thoughts on animation-fill-mode </span>{<span style="color: #ff0000">
  .target.animate {
    animation-name</span>:<span style="color: #0000ff"> move_3</span>;<span style="color: #ff0000">
    animation-duration</span>:<span style="color: #0000ff"> 2s</span>;<span style="color: #ff0000">
    animation-delay</span>:<span style="color: #0000ff"> 1s</span>;<span style="color: #ff0000">

    &.target_1 {
      animation-fill-mode</span>:<span style="color: #0000ff"> none</span>;
    }<span style="color: #800000">
    &.target_2 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> backwards</span>;
    }<span style="color: #800000">
    &.target_3 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> forwards</span>;
    }<span style="color: #800000">
    &.target_4 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> both</span>;
    }<span style="color: #800000">
  }
}

@keyframes move_3 </span>{<span style="color: #ff0000">
  50% {
    transform</span>:<span style="color: #0000ff"> scale(1.2, 1.2)</span>;
  }<span style="color: #800000">
}</span>

不过这一块的目的不是为了说明这个demo的动画效果,而是为了介绍如何从动画控制台去看动画作用过程的范围:

Some thoughts on animation-fill-mode

从源码中可以看到:

.target_1应用了animation-fill-mode:none

.target_2应用了animation-fill-mode:backwards

.target_3应用了animation-fill-mode:forwards

.target_4应用了animation-fill-mode:none。

结合这个可以看出,动画控制台中,时间轴实心的部分就是动画的作用过程

接下来回到本部分要研究问题主题,就是当元素在动画作用过程中的时候,动画定义的属性与元素初始的属性冲突时会有什么表现。

先看这个demo:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo4

Some thoughts on animation-fill-mode

(动画内容较多,所以没做gif,可以去上面的链接中查看)

less源码:

<span style="color: #800000">#demo4 </span>{<span style="color: #ff0000">
  .target {
    transform</span>:<span style="color: #0000ff"> scale(1.2, 1.2)</span>;
  }<span style="color: #800000">

  .target.animate </span>{<span style="color: #ff0000">
    animation-duration</span>:<span style="color: #0000ff"> 2s</span>;<span style="color: #ff0000">
    animation-delay</span>:<span style="color: #0000ff"> 1s</span>;<span style="color: #ff0000">

    &.target_1 {
      animation-fill-mode</span>:<span style="color: #0000ff"> none</span>;<span style="color: #ff0000">
      animation-name</span>:<span style="color: #0000ff"> move_4_01</span>;
    }<span style="color: #800000">
    &.target_2 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> backwards</span>;<span style="color: #ff0000">
      animation-name</span>:<span style="color: #0000ff"> move_4_01</span>;
    }<span style="color: #800000">
    &.target_3 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> forwards</span>;<span style="color: #ff0000">
      animation-name</span>:<span style="color: #0000ff"> move_4_01</span>;
    }<span style="color: #800000">

    &.target_1_02 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> none</span>;<span style="color: #ff0000">
      animation-name</span>:<span style="color: #0000ff"> move_4_02</span>;
    }<span style="color: #800000">
    &.target_2_02 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> backwards</span>;<span style="color: #ff0000">
      animation-name</span>:<span style="color: #0000ff"> move_4_02</span>;
    }<span style="color: #800000">
    &.target_3_02 </span>{<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> forwards</span>;<span style="color: #ff0000">
      animation-name</span>:<span style="color: #0000ff"> move_4_02</span>;
    }<span style="color: #800000">
  }
}

@keyframes move_4_01 </span>{<span style="color: #ff0000">
  0% {
    transform</span>:<span style="color: #0000ff"> translate(-50px, 0)</span>;
  }<span style="color: #800000">

  50% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(0, 0)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(50px, 0)</span>;
  }<span style="color: #800000">
}

@keyframes move_4_02 </span>{<span style="color: #ff0000">
  0% {
    transform</span>:<span style="color: #0000ff"> translate(-50px, 0) scale(1.2, 1.2)</span>;
  }<span style="color: #800000">

  50% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(0, 0) scale(1.2, 1.2)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(50px, 0) scale(1.2, 1.2)</span>;
  }<span style="color: #800000">
}</span>

在上面的截图中,我用箭头把元素跟动画控制台中的动画元素时间轴做了一个对应关系,方便理解。

在这个demo里面,元素默认都有一个transform: scale(1.2,1.2)的设置,然后定义两个动画,move_4_01这个动画的样式定义里面同样包含了一个transform属性,而且没有保留元素默认的transform设置。move_4_02这个动画的样式定义里面也包含了一个transform的设置,跟move_4_01不同的是,这个动画还保留了元素默认的scale(1.2,1.2)的设置。

demo中用到了六个元素,它们按照animation-fill-mode分成了三组,以便对应不同的动画作用过程;每组里面的两个元素,分别应用move_4_01和move_4_02两个动画。

通过在时间轴上的动画等待阶段,动画执行阶段和动画结束阶段,任取三个时间点,观察元素的表现,可以帮助分析在动画作用过程中,当动画属性与初始属性冲突时存在的规律:

动画等待阶段:

Some thoughts on animation-fill-mode

动画执行阶段:

Some thoughts on animation-fill-mode

动画结束阶段:

Some thoughts on animation-fill-mode

考虑到篇幅的原因,这里就不再详细的分析以上各个截图的现象了。我最终得出的结论是:在动画属性与初始属性冲突的时候,只要一个元素处于动画作用过程中,就会启用动画定义的属性,覆盖元素初始化的属性。而前面的结论告诉我们,animation-fill-mode可以改变元素的动画作用过程,所以明白这点,对于做动画的状态分析会比较有帮助。

继续下一个问题。

3. 一个元素应用多个动画时,多个动画定义的属性冲突

当一个元素应用了多个动画时,假如动画定义的属性有冲突,也就是说多个动画都用到了同一个属性,这种冲突该怎么去分析呢?

先来看下一个Some thoughts on animation-fill-mode:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Some thoughts on animation-fill-mode

Some thoughts on animation-fill-mode

less源码:

<span style="color: #800000">#Some thoughts on animation-fill-mode </span>{<span style="color: #ff0000">
  .target.animate {
    animation-duration</span>:<span style="color: #0000ff"> 1s, 1s</span>;<span style="color: #ff0000">
    animation-delay</span>:<span style="color: #0000ff"> 1s, 2s</span>;<span style="color: #ff0000">
    animation-fill-mode</span>:<span style="color: #0000ff"> both</span>;<span style="color: #ff0000">

    &.target_1 {
      animation-name</span>:<span style="color: #0000ff"> move_5, bg_change_5</span>;
    }<span style="color: #800000">
    &.target_2 </span>{<span style="color: #ff0000">
      animation-name</span>:<span style="color: #0000ff"> bg_change_5, move_5</span>;
    }<span style="color: #800000">
  }
}

@keyframes move_5 </span>{<span style="color: #ff0000">
  0% {
    transform</span>:<span style="color: #0000ff"> translate(-50px, 0)</span>;
  }<span style="color: #800000">

  50% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(0, 0)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(50px, 0)</span>;
  }<span style="color: #800000">
}

@keyframes bg_change_5 </span>{<span style="color: #ff0000">
  0% {
    background-color</span>:<span style="color: #0000ff"> orange</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> scale(0.8)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    background-color</span>:<span style="color: #0000ff"> red</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> scale(1.2)</span>;
  }<span style="color: #800000">
}</span>

In this demo, two animations are defined, move_5 changes the offset of the element on the x-axis, and bg_change_5 changes the scale and background color of the element at the same time. Both elements have these two animations applied at the same time. Except for the order of application, other parameters such as delay, duration, and animation-fill-mode are exactly the same. Combined with the timeline displayed on the animation console, let's take a look at the rules of these two elements during the animation process.

Take the animation waiting stage as an example:

Some thoughts on animation-fill-mode

At this stage, both elements have an orange background. .target_1 has an orange background, and its size is significantly smaller than the default size; .target_2 has an orange background, but its size has not changed, but it has been shifted a little to the left. From the above source code, we can know that the animation that affects the background color and size must be bg_change_5, and the animation that affects the x-axis offset of the element must be move_5. Although both elements have two animations applied at the same time, and the delay, duration and animation-fill-mode are the same, the performance status is not exactly the same. The only difference between them is the order of applying animation, the animation order of .target_1 is: move_5,bg_change_5. The animation sequence of .target_2 is bg_change_5, move_5. So the final reasonable explanation for this phenomenon is:

.target_1 Because the bg_change_5 animation comes last, the transform: scale(0.8) of the first frame in bg_change_5 covers the transform: translate(-50px,0);

.target_2 because move_5 comes after, so transform: translate(-50px,0) in move_5 covers transform: scale(0.8)

That is to say, when the properties of multiple animations conflict, the priority of the animation applied later is higher than the priority of the animation applied first. But it should be noted that this conclusion is not rigorous. Why?

Because this conclusion is based on the moment of 250ms. For an element that may have multiple animations applied, the time points are different, which means that each animation may be in different animation stages, and some may still be in the animation stage. In the waiting stage, some may be in the execution stage, and some may already be in the completion stage, such as:

Some thoughts on animation-fill-mode

Some thoughts on animation-fill-mode

To prove whether the previous conclusion is true, we need to take more moments on the timeline to verify it. But in the end, for reasons of space, I couldn’t find more time points to take screenshots for analysis, so I just came to a conclusion, which is what I said beforeIn several of my tests, they are all objectively established conclusions.

It’s just that the previous conclusion description is not simple and clear enough. I will give a more straightforward explanation below. Let’s take a look at this picture first:

Some thoughts on animation-fill-mode

This picture describes an element. After applying multiple animations at the same time, you can see the timeline of each animation in the animation console. From the picture we can draw the following information:

The application order of animation is: animate_1, animate_2, animate_3

The delay time of animate_1 is t4 (1/5 position away from t4)-t1, and the animation end time is t8

The delay time of animate_2 is 0, and the animation end time is t5

The delay time of animate_3 is t3-t1, and the animation end time is t7

We assume that in this picture, the animation-fill-mode of all animations is set to both, which means that the solid parts of all timelines in the picture represent the action process of the animation. Then pick any moment on the timeline, If multiple animations have attribute conflicts at this moment, the priority of the attributes is completely determined by the order in which the animations are applied. The animation applied later has higher priority:

Some thoughts on animation-fill-mode

有了这个结论,将来在分析一些多动画效果的时候就会比较好下手了。我们只要先确定好单个动画的作用过程,然后找到我们需要分析的动画时间轴的点,最后再从上往下找到最后一个包含冲突属性的动画轴即可。

另外,从这部分的问题,我还想说明另外一个结论,这个结论比较好理解,也没太多要去分析的,就是应用多动画的时候,各个动画之间都是独立的,所以动画的那些属性,如animation-delay, animation-fill-mode不会受其它动画的影响。这个从动画控制台各个动画独立的时间轴也能看出来。为什么会有这个结论呢,是因为在我没有去研究到这些规律之前,我以为动画的animation-fill-mode可能会受多个动画的animation-delay的影响,就拿前面的demo来说,元素在应用动画时,第一个动画延迟1s,第二个动画延迟2s,我初以为第二个动画的animation-fill-mode会在第一个动画的延迟结束之后才会生效,不然这两个动画如果同时应用animation-fill-mode的话,属性冲突该怎么解决?最后有了前面两个重要的结论,我原来的那个认识也就很好解释了。

接下来看一个简单实际的多动画的例子,来看看多动画的效果如果碰到问题该怎么分析。

4. 实例分析

这个演示的效果实例是,元素默认是隐藏的,当添加动画后,元素以淡入的方式从x轴向左偏移-50px的位置,移动到原位置,显示1s之后,再从原位置以淡出的方式,移动到x轴往右偏移50px的位置。正确的效果如下:

Some thoughts on animation-fill-mode

一开始我的做法是这样的:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Some thoughts on animation-fill-mode

<span style="color: #800000">#Some thoughts on animation-fill-mode </span>{<span style="color: #ff0000">
  .target</span>:<span style="color: #0000ff">not(.target_1) {
    visibility: hidden</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 0</span>;
  }<span style="color: #800000">

  .target.animate </span>{<span style="color: #ff0000">
    &.target_2 {
      animation-name</span>:<span style="color: #0000ff"> move_6_01, move_6_02</span>;<span style="color: #ff0000">
      animation-duration</span>:<span style="color: #0000ff"> 1s, 1s</span>;<span style="color: #ff0000">
      animation-delay</span>:<span style="color: #0000ff"> 0s, 2s</span>;<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> both</span>;
    }<span style="color: #800000">
  }
}

@keyframes move_6_01 </span>{<span style="color: #ff0000">
  0% {
    visibility</span>:<span style="color: #0000ff"> hidden</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 0</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(-50px, 0)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    visibility</span>:<span style="color: #0000ff"> visible</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 1</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(0, 0)</span>;
  }<span style="color: #800000">
}

@keyframes move_6_02 </span>{<span style="color: #ff0000">
  100% {
    visibility</span>:<span style="color: #0000ff"> hidden</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 0</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(50px, 0)</span>;
  }<span style="color: #800000">
}</span>

正如你所看到的,我定义了两个动画move_6_01,move_6_02,这两个动画按照01 02 的顺序应用到.target_2这个元素上,两个动画持续时间都是1s,第一个动画延迟时间为0,第二个动画延迟时间为2s,以便达到淡入淡出的时间都为1s,然后中间停留的时间也是1s的效果;两个动画同时应用了animation-fill-mode:both。然后还给.target_2这个元素设置了初始的属性:visibility: hidden,opactity: 0。.target_1只是一个对比的元素,没有添加动画效果。

当我运行这个代码的时候最后却发现,一点动画效果都没有,动画控制台已经监听到动画了,但是元素看不见动画效果:

Some thoughts on animation-fill-mode

我以为是animation-fill-mode的原因,所以我在上面的demo基础上,将animation-fill-mode稍加调整,改为both,forwards,也就是第二个动画不启用backwards的效果:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Some thoughts on animation-fill-mode

这个时候效果变成:

Some thoughts on animation-fill-mode

代码:

<span style="color: #800000">#Some thoughts on animation-fill-mode </span>{<span style="color: #ff0000">
  .target</span>:<span style="color: #0000ff">not(.target_1) {
    visibility: hidden</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 0</span>;
  }<span style="color: #800000">

  .target.animate </span>{<span style="color: #ff0000">
    &.target_2 {
      animation-name</span>:<span style="color: #0000ff"> move_6_01, move_6_02</span>;<span style="color: #ff0000">
      animation-duration</span>:<span style="color: #0000ff"> 1s, 1s</span>;<span style="color: #ff0000">
      animation-delay</span>:<span style="color: #0000ff"> 0s, 2s</span>;<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> both,forwards</span>;
    }<span style="color: #800000">
  }
}</span>

在这一步,淡入跟停留的效果出来了,可是淡出的效果没有出来。

虽然最后,我在不明白这其中的原理的前提下,将动画调试出来了,但是对于这个问题还是觉得很有必要去深入研究一下,这也是我写本文的初衷。有了之前的那些结论,接下来就看看如何分析前面两步的现象产生的原因。

先来看看Some thoughts on animation-fill-mode(就是本部分的第一个)的动画时间轴:

Some thoughts on animation-fill-mode

前面说过,动画是独立的,动画时间轴的实心部分表示动画作用过程,多动画的时候,在动画控制台中,可以根据从上往下的顺序判断属性的优先级。观察上面的截图发现:在动画添加后,两个动画的作用过程都是相同的,而由于move_6_02这个动画后应用,所以move_6_02这个动画,在有属性冲突的时候,优先级始终是高的那一个。

那么为什么在添加动画后,什么动画效果都看不到呢?这个原因在于move_6_02这个动画只定义了100%这一帧,没有定义0%,那就意味着move_6_02这个动画的起始帧会用元素默认的属性定义来代替。而元素的默认属性中有两个属性会导致元素在动画过程的0-2s都不会显示,就是visibility: hidden,opactity: 0这两个属性。

我一开始的理解是,move_6_01这个动画的100%这一帧,会让元素显示出来(visibility: visible,opactity: 1),所以move_6_02只用定义100%这一帧即可。但是动画是独立的,move_6_02这个动画的作用不会跟其它动画有关联,所以以上做法无法实现需要的效果。

再来看Some thoughts on animation-fill-mode:

Some thoughts on animation-fill-mode

在Some thoughts on animation-fill-mode里面,animation-fill-mode调整为both,forwards,改变了两个动画的作用过程,解决了move_6_02优先级高导致move_6_01的效果看不进的问题,但是为什么Some thoughts on animation-fill-mode在2s之后没有出现淡出的效果呢?

这个还是跟move_6_02这个动画没有定义0%这一帧有关系。当动画没有定义0%的时候,就会用默认的属性来作为起始帧。而元素的默认属性是

visibility: hidden,opactity: 0,move_6_02的100%里面定义的属性也是visibility: hidden,opactity: 0,也就是说这个动画实际上不会对元素的可见性做任何的改变,其实偏移还是有的,只是看不见而已。

所以最好解决这个问题,只要在Some thoughts on animation-fill-mode的基础上,给move_6_02加一个0%的定义即可:

http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#demo8

<span style="color: #800000">#demo8 </span>{<span style="color: #ff0000">
  .target</span>:<span style="color: #0000ff">not(.target_1) {
    visibility: hidden</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 0</span>;
  }<span style="color: #800000">

  .target.animate </span>{<span style="color: #ff0000">
    &.target_2 {
      animation-name</span>:<span style="color: #0000ff"> move_8_01, move_8_02</span>;<span style="color: #ff0000">
      animation-duration</span>:<span style="color: #0000ff"> 1s, 1s</span>;<span style="color: #ff0000">
      animation-delay</span>:<span style="color: #0000ff"> 0s, 2s</span>;<span style="color: #ff0000">
      animation-fill-mode</span>:<span style="color: #0000ff"> both,forwards</span>;
    }<span style="color: #800000">
  }
}

@keyframes move_8_01 </span>{<span style="color: #ff0000">
  0% {
    visibility</span>:<span style="color: #0000ff"> hidden</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 0</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(-50px, 0)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    visibility</span>:<span style="color: #0000ff"> visible</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 1</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(0, 0)</span>;
  }<span style="color: #800000">
}

@keyframes move_8_02 </span>{<span style="color: #ff0000">
  0% {
    visibility</span>:<span style="color: #0000ff"> visible</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 1</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(0, 0)</span>;
  }<span style="color: #800000">

  100% </span>{<span style="color: #ff0000">
    visibility</span>:<span style="color: #0000ff"> hidden</span>;<span style="color: #ff0000">
    opacity</span>:<span style="color: #0000ff"> 0</span>;<span style="color: #ff0000">
    transform</span>:<span style="color: #0000ff"> translate(50px, 0)</span>;
  }<span style="color: #800000">
}</span>

Through this example, I hope that everyone can understand the practical methods of some of the theories summarized in this article.

Summary

I won’t say much else. Let’s slightly refine some of the conclusions proposed in this article. I hope these things will be helpful to everyone in making complex animation effects in the future:

1. Animations are independent, each has its own timeline and does not affect each other.

2. animation-fill-mode only recognizes 0% and 100% in the animation definition, not the first and last frames in the animation definition.

3. When there is no 0% and 100% in the animation definition, it does not mean that the animation does not have a start frame and an end frame. Any animation must have a start frame and an end frame. By default, the start frame and The style corresponding to the end frame is the style of the element before animation is added. We can override the default start frame and end frame definitions by 0% or 100%. What animation-fill-mode actually applies is the starting frame and ending frame of the animation.

4. In the animation console, the solid part of the timeline is the animation process. When animation properties conflict with initial properties, as long as an element is in the process of animation, the priority of the properties defined in the animation will always be higher than the initial properties of the element.

5. In multi-animation effects, to determine which animation has a higher priority at any moment, just find the line corresponding to that moment in the animation console, and the intersection of the line with the solid parts of all animations (animation action process), according to In order from top to bottom, the points further down have higher priority.

Thank you for reading.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn