animation-fill-mode는 CSS3 애니메이션의 속성으로 애니메이션 실행 전과 애니메이션 완료 후 요소의 스타일을 제어할 수 있습니다. 지연이 있고 정방향(정방향은 0%에서 100%까지 실행됨을 의미)으로 실행되는 애니메이션, 한 번 실행되는 과정은 다음과 같이 설명할 수 있습니다.
애니메이션 실행 시간에 따라 애니메이션 프로세스는 요소를 애니메이션 대기, 애니메이션 진행 및 애니메이션 종료 상태의 세 가지 상태로 나눌 수 있습니다. 기본적으로 애니메이션의 키프레임에 의해 정의된 스타일은 애니메이션이 진행 중일 때만 적용됩니다. 애니메이션 대기 및 애니메이션 종료 상태에서는 요소의 스타일에 영향을 주지 않습니다. animation-fill-mode에는 다음과 같은 네 가지 값이 있습니다.
none: 애니메이션이 기다리고 있는 요소의 스타일을 변경하지 못하게 하는 기본값입니다. Completed;
backwards: 이 값으로 설정하면 애니메이션이 기다리는 동안 요소의 스타일이 애니메이션의 첫 번째 프레임 스타일로 설정됩니다. >forwards: 이 값으로 설정하면 애니메이션이 끝난 후 요소의 스타일이 애니메이션의 마지막 프레임 스타일로 설정됩니다.
둘 다: 뒤로 및 앞으로 구성하는 것과 동일합니다. 동시에, 이는 애니메이션 대기 및 애니메이션 종료 상태 동안 요소가 각각 애니메이션화됨을 의미합니다. 첫 번째 프레임과 마지막 프레임의 스타일입니다.
아래 데모를 보면 animation-fill-mode의 세 가지 non-none 값의 효과를 느낄 수 있습니다.
애니메이션 채우기 모드에 대한 몇 가지 생각: http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#애니메이션 채우기 모드에 대한 몇 가지 생각효과는 다음과 같습니다. 다음과 같습니다:
소스 코드 간략히:
在以上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%。至于为啥是这样,自己简单画个图就好理解了:
详细的规则在mdn上有完整地说明,所以这里不会再赘述了。这个规则并不存在理解偏差的问题,但是对于animation-fill-mode的第一帧跟最后一帧该如何判别还是比较重要的,所以有必要记录一下。
为了不增加以下内容的复杂性,剩下的内容都将以animation-direction为normal,animation-iteration-count为1这个前提来说明。接下来就来看看animation-fill-mode这个属性,还有哪些问题值得花点心思研究研究的。
1. 动画没有定义0%或100%的时候
假如我们动画里没有定义0%或100%,只定义了中间百分比的关键帧,animation-fill-mode会有什么样的表现呢?
先来观察애니메이션 채우기 모드에 대한 몇 가지 생각:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#애니메이션 채우기 모드에 대한 몇 가지 생각
less源码:
<span style="color: #800000">#애니메이션 채우기 모드에 대한 몇 가지 생각 </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>
이 데모에서는 서로 다른 애니메이션 채우기 모드가 적용된 세 가지 요소를 볼 수 있지만 최종 효과는 완전히 동일합니다. 이는 애니메이션에 0%와 100%가 정의되지 않아 애니메이션 채우기 모드가 필요한 첫 번째 프레임과 마지막 프레임을 찾을 수 없기 때문입니다. 위의 데모 애니메이션에서는 50%가 애니메이션 정의에 포함되어 있지만 우리의 고유성에 대한 이해에 따르면 50% 프레임은 하나의 프레임 또는 마지막 프레임으로 간주될 수 있지만 애니메이션입니다. -fill-mode는 애니메이션 정의의 첫 번째 프레임과 마지막 프레임이 아닌 애니메이션 정의의 0%와 100%만 인식합니다.
그럼 0%와 100%가 없으면 애니메이션 채우기 모드가 효과가 없다는 뜻인가요?
사실 그렇지 않습니다. 애니메이션 정의에 0%와 100%가 없다고 해서 애니메이션에 시작 프레임과 끝 프레임이 없다는 의미는 아닙니다. 기본적으로 모든 애니메이션에는 시작 프레임과 끝 프레임이 있어야 합니다. 시작 프레임과 끝 프레임에 해당하는 스타일은 애니메이션이 요소에 추가되기 전의 스타일입니다. 기본 시작 프레임과 끝 프레임 정의를 0% 또는 100%로 재정의할 수 있습니다. 즉, 0%나 100%가 없을 때 animation-fill-mode는 여전히 작동하지만 요소의 초기 상태를 사용하여 작동하므로 알 수 없습니다.
앞 문단의 결론은 w3c에서 소개된 것을 보지는 못했지만 나름의 생각과 관찰을 바탕으로 추측한 것입니다. 다음에는 Chrome의 애니메이션 디버깅 도구를 사용하여 내 판단을 설명하는 데 도움을 드리겠습니다. 나중에 여러 애니메이션에서 애니메이션 채우기 모드의 실습을 소개할 때 예제도 결합하여 이러한 이론을 사용하여 설명하겠습니다.
새 버전의 Chrome에서는 다음과 같이 열 수 있는 애니메이션 디버깅 기능을 제공합니다.
애니메이션 탭이 나타나면 타임라인을 제어하여 애니메이션을 디버깅할 수 있는 아래와 유사한 콘솔이 표시됩니다.
애니메이션 콘솔이 열리면 페이지가 로드된 후 페이지의 애니메이션 효과를 모니터링합니다. 예를 들어 데모2의 애니메이션 추가 버튼을 클릭하면 콘솔은 데모2에서 발생하는 애니메이션을 볼 수 있습니다.
이 애니메이션 콘솔은 애니메이션 타임라인 조정, 애니메이션 일시 정지, 애니메이션 속도 제어, 프레임별 관찰과 같은 강력한 애니메이션 관리 기능을 실현할 수 있습니다. 하지만 관심이 있는 경우 이 기사에서는 그 사용법을 자세히 소개하지 않습니다. , 업무에 사용할 수 있습니다. 이제 이 애니메이션 콘솔을 통해 이전에 내린 결론은 다음과 같습니다. 0%와 100%가 정의되었는지 여부에 관계없이 모든 애니메이션에는 시작 프레임과 끝 프레임이 있어야 합니다. , only 하지만 0%와 100%로 재정의할 수 있습니다.
이 기사의 데모 1로 돌아가서 페이지를 새로 고친 다음 데모 1에서 애니메이션 추가 버튼을 클릭하고 애니메이션 콘솔에 표시되는 내용을 관찰했습니다.
애니메이션 채우기 모드에 대한 몇 가지 생각의 애니메이션에는 총 3개의 키프레임 정의가 포함되어 있으므로 애니메이션 콘솔에서 각 요소의 애니메이션 타임라인에 3개의 지점이 포함되어 있음을 확인할 수 있으며, 그 중 첫 번째 지점과 마지막 지점이 솔리드입니다. 이는 애니메이션의 시작 및 끝 프레임임을 의미하며 중간 지점은 비어 있습니다. 이는 애니메이션 실행 중 핵심 프레임임을 의미합니다.
애니메이션 채우기 모드에 대한 몇 가지 생각를 다시 보면 같은 방식으로 애니메이션을 추가한 후 콘솔을 보면
对比애니메이션 채우기 모드에 대한 몇 가지 생각的截图,可以发现,尽管애니메이션 채우기 모드에 대한 몇 가지 생각中的动画只定义了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#애니메이션 채우기 모드에 대한 몇 가지 생각
less源码:
<span style="color: #800000">#애니메이션 채우기 모드에 대한 몇 가지 생각 </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的动画效果,而是为了介绍如何从动画控制台去看动画作用过程的范围:
从源码中可以看到:
.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
(动画内容较多,所以没做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两个动画。
通过在时间轴上的动画等待阶段,动画执行阶段和动画结束阶段,任取三个时间点,观察元素的表现,可以帮助分析在动画作用过程中,当动画属性与初始属性冲突时存在的规律:
动画等待阶段:
动画执行阶段:
动画结束阶段:
考虑到篇幅的原因,这里就不再详细的分析以上各个截图的现象了。我最终得出的结论是:在动画属性与初始属性冲突的时候,只要一个元素处于动画作用过程中,就会启用动画定义的属性,覆盖元素初始化的属性。而前面的结论告诉我们,animation-fill-mode可以改变元素的动画作用过程,所以明白这点,对于做动画的状态分析会比较有帮助。
继续下一个问题。
3. 一个元素应用多个动画时,多个动画定义的属性冲突
当一个元素应用了多个动画时,假如动画定义的属性有冲突,也就是说多个动画都用到了同一个属性,这种冲突该怎么去分析呢?
先来看下一个애니메이션 채우기 모드에 대한 몇 가지 생각:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#애니메이션 채우기 모드에 대한 몇 가지 생각
less源码:
<span style="color: #800000">#애니메이션 채우기 모드에 대한 몇 가지 생각 </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>
이 데모에서는 두 개의 애니메이션이 정의되어 있습니다. move_5는 x축에서 요소의 오프셋을 변경하고, bg_change_5는 요소의 크기와 배경색을 동시에 변경합니다. 두 요소 모두 이 두 애니메이션이 동시에 적용됩니다. 적용 순서를 제외하고 지연, 지속 시간, 애니메이션 채우기 모드와 같은 다른 매개변수는 완전히 동일합니다. 애니메이션 콘솔에 표시되는 타임라인과 결합하여 애니메이션 프로세스 중 이 두 요소의 규칙을 살펴보겠습니다.
애니메이션 대기 단계를 예로 들어보겠습니다.
이 단계에서는 두 요소 모두 주황색 배경을 가지고 있습니다. .target_1은 주황색 배경을 가지며 크기는 기본 크기보다 훨씬 작습니다. 그러나 크기는 변경되지 않았습니다. 조금 왼쪽으로 이동했습니다. 위 소스코드를 보면 배경색과 크기에 영향을 주는 애니메이션은 bg_change_5, 요소의 x축 오프셋에 영향을 주는 애니메이션은 move_5 이어야 함을 알 수 있습니다. 두 요소 모두 두 개의 애니메이션이 동시에 적용되고 지연, 지속 시간 및 애니메이션 채우기 모드가 동일하더라도 성능 상태가 완전히 동일하지는 않습니다. 유일한 차이점은 애니메이션이 적용되는 순서입니다.target_1의 애니메이션 순서는 move_5,bg_change_5입니다. .target_2의 애니메이션 시퀀스는 bg_change_5, move_5입니다. 따라서 이 현상에 대한 최종 합리적인 설명은 다음과 같습니다.
.target_1 bg_change_5 애니메이션이 마지막에 나오므로 bg_change_5의 첫 번째 프레임의 변환: scale(0.8)은 변환: 변환(-50px,0);
을 포함합니다..target_2 move_5가 뒤에 오기 때문에 move_5의 변환: 변환(-50px,0)이 변환: 스케일(0.8)을 포함합니다
즉, 여러 애니메이션의 속성이 충돌하는 경우 나중에 적용되는 애니메이션의 우선순위가 먼저 적용되는 애니메이션의 우선순위보다 높습니다. 그러나 이 결론은 엄밀하지 않다는 점에 유의해야 합니다. 왜일까요?
이 결론은 250ms의 순간을 기준으로 하기 때문에 여러 애니메이션이 적용될 수 있는 요소의 경우 시점이 다르며, 이는 각 애니메이션이 다른 애니메이션 단계에 있을 수 있고 일부는 여전히 대기 중일 수 있음을 의미합니다. 단계 중 일부는 실행 단계에 있을 수 있고 일부는 이미 완료 단계에 있을 수 있습니다.
이전 결론이 사실인지 증명하려면 타임라인에서 더 많은 시간을 들여 이를 검증해야 합니다. 하지만 결국 스페이스 문제로 분석용 스크린샷을 찍을 시점을 더 찾을 수 없어서 직접적으로 결론을 내리자면 앞서 말씀드렸던 부분입니다 몇번의 테스트를 거쳐 모두 객관적으로 나온 결과입니다. 결론을 내렸다.
이전의 결론 설명이 간단하고 명확하지 않을 뿐입니다. 아래에서 좀 더 간단하게 설명하겠습니다. 먼저 이 사진을 살펴보겠습니다.
이 그림은 여러 애니메이션을 동시에 적용한 후 애니메이션 콘솔에서 각 애니메이션의 타임라인을 볼 수 있는 요소를 설명합니다. 그림에서 다음 정보를 그릴 수 있습니다.
애니메이션 적용 순서는 animate_1, animate_2, animate_3
animate_1의 지연 시간은 t4(t4에서 1/5 위치만큼 떨어져 있음)-t1이고, 애니메이션 종료 시간은 t8입니다
animate_2의 지연시간은 0이고, 애니메이션 종료시간은 t5입니다
animate_3의 지연 시간은 t3-t1이고, 애니메이션 종료 시간은 t7입니다
이 사진에서는 모든 애니메이션의 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的位置。正确的效果如下:
一开始我的做法是这样的:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#애니메이션 채우기 모드에 대한 몇 가지 생각
<span style="color: #800000">#애니메이션 채우기 모드에 대한 몇 가지 생각 </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只是一个对比的元素,没有添加动画效果。
当我运行这个代码的时候最后却发现,一点动画效果都没有,动画控制台已经监听到动画了,但是元素看不见动画效果:
我以为是animation-fill-mode的原因,所以我在上面的demo基础上,将animation-fill-mode稍加调整,改为both,forwards,也就是第二个动画不启用backwards的效果:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#애니메이션 채우기 모드에 대한 몇 가지 생각
这个时候效果变成:
代码:
<span style="color: #800000">#애니메이션 채우기 모드에 대한 몇 가지 생각 </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>
在这一步,淡入跟停留的效果出来了,可是淡出的效果没有出来。
虽然最后,我在不明白这其中的原理的前提下,将动画调试出来了,但是对于这个问题还是觉得很有必要去深入研究一下,这也是我写本文的初衷。有了之前的那些结论,接下来就看看如何分析前面两步的现象产生的原因。
先来看看애니메이션 채우기 모드에 대한 몇 가지 생각(就是本部分的第一个)的动画时间轴:
前面说过,动画是独立的,动画时间轴的实心部分表示动画作用过程,多动画的时候,在动画控制台中,可以根据从上往下的顺序判断属性的优先级。观察上面的截图发现:在动画添加后,两个动画的作用过程都是相同的,而由于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这个动画的作用不会跟其它动画有关联,所以以上做法无法实现需要的效果。
再来看애니메이션 채우기 모드에 대한 몇 가지 생각:
在애니메이션 채우기 모드에 대한 몇 가지 생각里面,animation-fill-mode调整为both,forwards,改变了两个动画的作用过程,解决了move_6_02优先级高导致move_6_01的效果看不进的问题,但是为什么애니메이션 채우기 모드에 대한 몇 가지 생각在2s之后没有出现淡出的效果呢?
这个还是跟move_6_02这个动画没有定义0%这一帧有关系。当动画没有定义0%的时候,就会用默认的属性来作为起始帧。而元素的默认属性是
visibility: hidden,opactity: 0,move_6_02的100%里面定义的属性也是visibility: hidden,opactity: 0,也就是说这个动画实际上不会对元素的可见性做任何的改变,其实偏移还是有的,只是看不见而已。
所以最好解决这个问题,只要在애니메이션 채우기 모드에 대한 몇 가지 생각的基础上,给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>
이 예를 통해 이 기사에 요약된 일부 이론의 실제적인 방법을 이해할 수 있기를 바랍니다.
이 기사에서 제안한 결론 중 일부를 약간 수정해 보겠습니다. 이러한 내용이 앞으로 복잡한 애니메이션 효과를 만들 때 모든 사람에게 도움이 되기를 바랍니다.
1. 애니메이션은 독립적이며 각각 고유한 타임라인을 가지며 서로 영향을 미치지 않습니다.
2. animation-fill-mode는 애니메이션 정의의 첫 번째와 마지막 프레임이 아닌 애니메이션 정의에서 0%와 100%만 인식합니다.
3. 애니메이션 정의에 0%와 100%가 없다고 해서 애니메이션에 시작 프레임과 끝 프레임이 있어야 한다는 의미는 아닙니다. 기본, 시작 프레임 프레임과 끝 프레임에 해당하는 스타일은 애니메이션이 추가되기 전 요소의 스타일입니다. 기본 시작 프레임과 끝 프레임 정의를 0% 또는 100%로 재정의할 수 있습니다. animation-fill-mode가 실제로 적용되는 것은 애니메이션의 시작 프레임과 끝 프레임입니다.
4. 애니메이션 콘솔에서 타임라인의 확실한 부분은 애니메이션 프로세스입니다. 애니메이션 속성이 초기 속성과 충돌하는 경우 요소가 애니메이션 프로세스에 있는 한 애니메이션에 정의된 속성의 우선 순위는 항상 요소의 초기 속성보다 높습니다.
5. 다중 애니메이션 효과에서 어떤 순간에 어떤 애니메이션의 우선순위가 더 높은지 결정하려면 애니메이션 콘솔에서 해당 순간에 해당하는 선을 찾고 모든 애니메이션의 단색 부분과 선의 교차점( 애니메이션 액션 과정) 위에서 아래로 순서대로 포인트가 낮을수록 우선순위가 높습니다.
읽어주셔서 감사합니다.