animation-fill-mode ist eine Eigenschaft der CSS3-Animation, die den Stil von Elementen steuern kann, bevor die Animation ausgeführt wird und nachdem die Animation abgeschlossen ist. Eine Animation mit Verzögerung, die in normaler Richtung ausgeführt wird (normale Richtung bezieht sich auf die Ausführung von 0 % auf 100 %). Der Vorgang der einmaligen Ausführung kann wie folgt beschrieben werden:
Folgen: Je nach Ausführungszeit der Animation kann ein Animationsprozess das Element in drei Zustände unterteilen: Animationswartezustand, Animationsfortschritt und Animationsendzustand. Standardmäßig wird der durch die Keyframes der Animation definierte Stil nur angewendet, wenn die Animation ausgeführt wird. Im Warte- und Endzustand der Animation hat dies keinen Einfluss auf den Stil des Elements. Der Animationsfüllmodus hat vier Werte:
none: Dies ist der Standardwert. Dieser Wert verhindert, dass die Animation den Stil der Elemente ändert, auf die die Animation wartet und die sich auf der Animation befindet abgeschlossen;
rückwärts: Wenn dieser Wert festgelegt ist, wird der Stil des Elements während des Zeitraums, in dem die Animation wartet, auf den Stil des ersten Frames der Animation eingestellt >forwards: Wenn dieser Wert festgelegt ist, wird der Stil des Elements nach dem Ende der Animation auf den Stil des letzten Frames der Animation eingestellt Dies bedeutet, dass das Element während der Animationswarte- und Animationsendzustände animiert wird. Der Stil des ersten und letzten Frames.
Anhand der folgenden Demo können Sie die Wirkung der drei Nicht-Keine-Werte des Animationsfüllmodus spüren.
Einige Gedanken zum Animationsfüllmodus: http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Einige Gedanken zum AnimationsfüllmodusDer Effekt ist wie folgt:
weniger Quellcode:
在以上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会有什么样的表现呢?
先来观察Einige Gedanken zum Animationsfüllmodus:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Einige Gedanken zum Animationsfüllmodus
less源码:
<span style="color: #800000">#Einige Gedanken zum Animationsfüllmodus </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 dieser Demo sehen Sie drei Elemente mit unterschiedlichen Animationsfüllmodi, aber der Endeffekt ist genau der gleiche. Dies liegt daran, dass 0 % und 100 % in der Animation nicht definiert sind, was dazu führt, dass der Animationsfüllmodus nicht in der Lage ist, das erste und letzte benötigte Bild zu finden. Obwohl in der obigen Demo-Animation 50 % in der Animationsdefinition enthalten sind, handelt es sich um den einzigen Frame. Nach unserem Verständnis von Eindeutigkeit kann der 50 %-Frame entweder als ein Frame oder als letzter Frame betrachtet werden, aber Animation -fill-mode erkennt nur 0 % und 100 % in der Animationsdefinition, nicht den ersten und letzten Frame in der Animationsdefinition.
Bedeutet das also, dass der Animationsfüllmodus keine Wirkung haben darf, wenn es keine 0 % und 100 % gibt?
Eigentlich nicht. Wenn die Animationsdefinition keine 0 % und 100 % enthält, bedeutet das nicht, dass die Animation kein Startbild und kein Endbild hat. Standardmäßig muss jede Animation ein Startbild und ein Endbild haben. Der dem Start-Frame und dem End-Frame entsprechende Stil ist der Stil, bevor die Animation dem Element hinzugefügt wird. Wir können die Standard-Start-Frame- und End-Frame-Definitionen um 0 % oder 100 % überschreiben. Mit anderen Worten, wenn es keine 0 % oder 100 % gibt, funktioniert der Animationsfüllmodus immer noch, aber er verwendet den Anfangszustand des Elements, um zu funktionieren, sodass Sie es nicht erkennen können.
Die Schlussfolgerung im vorherigen Absatz: Ich habe nicht gesehen, dass sie in w3c eingeführt wurde, aber ich habe sie aufgrund einiger meiner eigenen Überlegungen und Beobachtungen erraten. Als nächstes werde ich das Animations-Debugging-Tool von Chrome verwenden, um mein Urteil zu erläutern. Wenn ich später die Praxis des Animationsfüllmodus in mehreren Animationen vorstelle, werde ich auch ein Beispiel kombinieren und diese Theorien zur Erklärung verwenden.
Die neue Version von Chrome bietet die Funktion zum Debuggen von Animationen, die wie folgt geöffnet werden kann:
Nachdem die Registerkarte „Animationen“ angezeigt wird, sehen Sie eine Konsole ähnlich der folgenden, in der wir Animationen debuggen können, indem wir die Zeitleiste steuern:
Wenn die Animationskonsole geöffnet wird, werden die Animationseffekte auf der Seite überwacht, nachdem die Seite geladen wurde. Wenn wir beispielsweise auf die Schaltfläche „Animation hinzufügen“ von Demo2 klicken, kann die Konsole die Animation in Demo2 sehen:
Diese Animationskonsole kann leistungsstarke Animationsverwaltungsfunktionen wie das Anpassen der Animationszeitleiste, die Animationspause, die Steuerung der Animationsgeschwindigkeit und die Einzelbildbeobachtung realisieren. Wenn Sie interessiert sind, wird in diesem Artikel jedoch nicht ausführlich auf die Verwendung eingegangen , Sie können es in Ihrer Arbeit verwenden. Jetzt möchte ich die Präsentation dieser Animationskonsole veranschaulichen, die ich zuvor gezogen habe: Jede Animation, unabhängig davon, ob 0 % und 100 % definiert sind oder nicht, muss einen Startrahmen und einen Endrahmen haben . Aber wir können es mit 0 % und 100 % überschreiben.
Als ich zu Demo1 dieses Artikels zurückkehrte, habe ich die Seite aktualisiert, dann in Demo1 auf die Schaltfläche „Animation hinzufügen“ geklickt und dann die Animationskonsole beobachtet. Der angezeigte Inhalt war:
Da die Animation von Demo1 insgesamt drei Keyframe-Definitionen enthält, können wir in der Animationskonsole sehen, dass die Animationszeitleiste jedes Elements drei Punkte enthält, darunter den ersten Punkt und den letzten Punkt. Jeder Punkt ist fest, was bedeutet, dass es sich um das Start- und Endbild der Animation handelt und der Mittelpunkt hohl ist, was bedeutet, dass es sich um ein Schlüsselbild während der Ausführung der Animation handelt.
Schauen Sie sich Demo2 noch einmal an, ich habe auf die gleiche Weise Animationen hinzugefügt, und schauen Sie sich dann die Konsole an:
对比Einige Gedanken zum Animationsfüllmodus的截图,可以发现,尽管Einige Gedanken zum Animationsfüllmodus中的动画只定义了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#Einige Gedanken zum Animationsfüllmodus
less源码:
<span style="color: #800000">#Einige Gedanken zum Animationsfüllmodus </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. 一个元素应用多个动画时,多个动画定义的属性冲突
当一个元素应用了多个动画时,假如动画定义的属性有冲突,也就是说多个动画都用到了同一个属性,这种冲突该怎么去分析呢?
先来看下一个Einige Gedanken zum Animationsfüllmodus:http://liuyunzhuge.github.io/blog/animation/dist/html/animation-fill-mode.html#Einige Gedanken zum Animationsfüllmodus
less源码:
<span style="color: #800000">#Einige Gedanken zum Animationsfüllmodus </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 dieser Demo sind zwei Animationen definiert: move_5 ändert den Versatz des Elements auf der x-Achse und bg_change_5 ändert gleichzeitig die Skalierung und Hintergrundfarbe des Elements. Bei beiden Elementen werden diese beiden Animationen gleichzeitig angewendet. Abgesehen von der Reihenfolge der Anwendung sind andere Parameter wie Verzögerung, Dauer und Animationsfüllmodus genau gleich. Lassen Sie uns in Kombination mit der auf der Animationskonsole angezeigten Zeitleiste einen Blick auf die Regeln dieser beiden Elemente während des Animationsprozesses werfen.
Nehmen Sie als Beispiel die Wartephase der Animation:
Zu diesem Zeitpunkt haben beide Elemente einen orangefarbenen Hintergrund. .target_1 hat einen orangefarbenen Hintergrund und seine Größe ist deutlich kleiner als die Standardgröße. .target_2 hat einen orangefarbenen Hintergrund, aber seine Größe hat sich nicht geändert etwas nach links verschoben. Aus dem obigen Quellcode können wir erkennen, dass die Animation, die sich auf die Hintergrundfarbe und -größe auswirkt, bg_change_5 sein muss und die Animation, die sich auf den X-Achsen-Versatz des Elements auswirkt, move_5 sein muss. Obwohl auf beide Elemente gleichzeitig zwei Animationen angewendet werden und Verzögerung, Dauer und Animationsfüllmodus gleich sind, ist der Leistungsstatus nicht genau derselbe. Der einzige Unterschied zwischen ihnen ist die Reihenfolge, in der die Animation angewendet wird Die Animationsreihenfolge von .target_1 ist: move_5,bg_change_5. Die Animationssequenz von .target_2 ist bg_change_5, move_5. Die letzte vernünftige Erklärung für dieses Phänomen lautet also:
.target_1 Da die bg_change_5-Animation an letzter Stelle steht, deckt die Transformation: scale(0.8) des ersten Frames in bg_change_5 die Transformation ab: translator(-50px,0);
.target_2 Da move_5 danach kommt, deckt die Transformation: Translate(-50px,0) in Move_5 die Transformation: Scale(0.8) ab
Das heißt, wenn die Eigenschaften mehrerer Animationen in Konflikt geraten, ist die Priorität der später angewendeten Animation höher als die Priorität der zuerst angewendeten Animation. Es sollte jedoch beachtet werden, dass diese Schlussfolgerung nicht streng ist. Warum?
Da diese Schlussfolgerung auf dem Moment von 250 ms basiert, sind die Zeitpunkte für ein Element, auf das möglicherweise mehrere Animationen angewendet werden, unterschiedlich, was bedeutet, dass sich jede Animation möglicherweise in einer anderen Animationsphase befindet und einige möglicherweise noch warten Einige befinden sich möglicherweise in der Ausführungsphase und einige befinden sich bereits in der Abschlussphase, z. B.:
Um zu beweisen, ob die vorherige Schlussfolgerung wahr ist, müssen wir uns mehr Momente auf der Zeitachse nehmen, um sie zu überprüfen. Aber am Ende konnte ich aus Platzgründen keine weiteren Zeitpunkte finden, um Screenshots zur Analyse zu machen. Wie bereits erwähnt handelt es sich bei mehreren meiner Tests um objektiv fundierte Schlussfolgerungen. .
Es ist nur so, dass die vorherige Beschreibung der Schlussfolgerung nicht einfach und klar genug ist. Ich werde unten eine einfachere Erklärung geben. Schauen wir uns zunächst dieses Bild an:
Dieses Bild beschreibt ein Element. Nachdem Sie mehrere Animationen gleichzeitig angewendet haben, können Sie die Zeitleiste jeder Animation in der Animationskonsole sehen. Aus dem Bild können wir folgende Informationen ableiten:
Die Anwendungsreihenfolge der Animation ist: animate_1, animate_2, animate_3
Die Verzögerungszeit von animate_1 beträgt t4 (1/5 Position von t4 entfernt)-t1, und die Endzeit der Animation beträgt t8
Die Verzögerungszeit von animate_2 ist 0 und die Endzeit der Animation ist t5
Die Verzögerungszeit von animate_3 beträgt t3-t1 und die Endzeit der Animation beträgt t7
Wir gehen davon aus, dass in diesem Bild der Animationsfüllmodus aller Animationen auf „Beide“ eingestellt ist, was bedeutet, dass die durchgezogenen Teile aller Zeitleisten im Bild den Animationsprozess darstellen, dann jederzeit auf dem Zeitleiste Nehmen Sie sich einen Moment Zeit. Wenn mehrere Animationen zu diesem Zeitpunkt Attributkonflikte aufweisen, wird die Priorität der Attribute vollständig durch die Reihenfolge bestimmt, in der die Animation angewendet wird:
有了这个结论,将来在分析一些多动画效果的时候就会比较好下手了。我们只要先确定好单个动画的作用过程,然后找到我们需要分析的动画时间轴的点,最后再从上往下找到最后一个包含冲突属性的动画轴即可。
另外,从这部分的问题,我还想说明另外一个结论,这个结论比较好理解,也没太多要去分析的,就是应用多动画的时候,各个动画之间都是独立的,所以动画的那些属性,如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#Einige Gedanken zum Animationsfüllmodus
<span style="color: #800000">#Einige Gedanken zum Animationsfüllmodus </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#Einige Gedanken zum Animationsfüllmodus
这个时候效果变成:
代码:
<span style="color: #800000">#Einige Gedanken zum Animationsfüllmodus </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>
在这一步,淡入跟停留的效果出来了,可是淡出的效果没有出来。
虽然最后,我在不明白这其中的原理的前提下,将动画调试出来了,但是对于这个问题还是觉得很有必要去深入研究一下,这也是我写本文的初衷。有了之前的那些结论,接下来就看看如何分析前面两步的现象产生的原因。
先来看看Einige Gedanken zum Animationsfüllmodus(就是本部分的第一个)的动画时间轴:
前面说过,动画是独立的,动画时间轴的实心部分表示动画作用过程,多动画的时候,在动画控制台中,可以根据从上往下的顺序判断属性的优先级。观察上面的截图发现:在动画添加后,两个动画的作用过程都是相同的,而由于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这个动画的作用不会跟其它动画有关联,所以以上做法无法实现需要的效果。
再来看Einige Gedanken zum Animationsfüllmodus:
在Einige Gedanken zum Animationsfüllmodus里面,animation-fill-mode调整为both,forwards,改变了两个动画的作用过程,解决了move_6_02优先级高导致move_6_01的效果看不进的问题,但是为什么Einige Gedanken zum Animationsfüllmodus在2s之后没有出现淡出的效果呢?
这个还是跟move_6_02这个动画没有定义0%这一帧有关系。当动画没有定义0%的时候,就会用默认的属性来作为起始帧。而元素的默认属性是
visibility: hidden,opactity: 0,move_6_02的100%里面定义的属性也是visibility: hidden,opactity: 0,也就是说这个动画实际上不会对元素的可见性做任何的改变,其实偏移还是有的,只是看不见而已。
所以最好解决这个问题,只要在Einige Gedanken zum Animationsfüllmodus的基础上,给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>
Ich hoffe, dass Sie anhand dieses Beispiels die praktischen Methoden einiger der in diesem Artikel zusammengefassten Theorien verstehen können.
Ich werde nicht viel mehr sagen. Lassen Sie uns einige der in diesem Artikel vorgeschlagenen Schlussfolgerungen etwas verfeinern. Ich hoffe, dass diese Dinge in Zukunft für alle hilfreich sein werden, wenn es darum geht, komplexe Animationseffekte zu erstellen:
1. Die Animationen sind unabhängig, jede hat ihre eigene Zeitleiste und beeinflusst sich nicht gegenseitig.
2. Der Animationsfüllmodus erkennt nur 0 % und 100 % in der Animationsdefinition, nicht den ersten und letzten Frame in der Animationsdefinition.
3. Wenn es in der Animationsdefinition keine 0 % und 100 % gibt, bedeutet das nicht, dass die Animation kein Startbild und kein Endbild hat Standardmäßig ist der dem Frame und Endframe entsprechende Stil der Stil des Elements vor dem Hinzufügen der Animation. Wir können die Standarddefinitionen für Startframe und Endframe um 0 % oder 100 % überschreiben. Was der Animationsfüllmodus tatsächlich anwendet, ist der Startrahmen und der Endrahmen der Animation.
4. In der Animationskonsole ist der Animationsprozess der feste Teil der Zeitleiste. Wenn Animationseigenschaften mit Anfangseigenschaften in Konflikt stehen, ist die Priorität der in der Animation definierten Eigenschaften immer höher als die Anfangseigenschaften des Elements, solange sich ein Element im Animationsprozess befindet.
5. Um bei Multi-Animationseffekten zu bestimmen, welche Animation zu einem bestimmten Zeitpunkt die höhere Priorität hat, suchen Sie einfach die Linie, die diesem Moment entspricht, in der Animationskonsole und den Schnittpunkt der Linie mit den durchgezogenen Teilen aller Animationen (Animation). Aktionsprozess), in der Reihenfolge von oben nach unten: Je niedriger der Punkt, desto höher die Priorität.
Vielen Dank fürs Lesen.