I'm trying to make a complex animation, so I made the next simple example to ilustrate my problem.
The next code tries to make an object rotate, change its color at 50% of animation and keep it until 100%,
the problem I got is that when it changes from 50% to 100% it doesn't keep the previous keyframe (50%), it becomes transpatent again at 100%.
I've worked with some animation software like blender or animate cc and the default behavior is to keep values of the
properties set in the last keyframe unless you actively change it to something else.
I know that I can set the background property again to red at 100%. but for a real complex animation that would mean repeating A LOT of values,
I'm also aware of the "animation-fill-mode" property which keeps the final state of animation if it is set to "forward",
so I though that if I did that in each step it would behave as I wish but it didn't work :(
Is there a good workaround for this problem without having to repeat each property on every frame?
Can I change the default behaviour?
Note: I thought that if a property is not set on each frame it would default to the initial value (0% frame),
however I didn't set any "transform:rotate" property at 50% and it's not defaulted to 0%'s value, since it interpolates the value between 0% and 100%,
so I have no idea how this really works :/ , some clarification on why does this happen would be really appreceated
.test{
all: unset;
animation-name: rotate_and_change_color;
animation-duration: 3s;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-direction: normal;
}
#keyframes rotate_and_change_color{
0%{transform: rotate(0deg);
animation-fill-mode: forwards;
}
50%{
background: red;
animation-fill-mode: forwards;
}
100%{transform: rotate(360deg);
animation-fill-mode: forwards;
}
}
One way is to consider multiple animations where you can easily control each property:
.test {
animation-name: rotate, change_color;
animation-duration: 3s;
animation-fill-mode: forwards;
animation-timing-function: linear;
animation-direction: normal;
width:200px;
height:200px;
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#keyframes change_color {
50%,
100% {
background: red;
}
}
<div class="test">
</div>
Concerning your note this apply to only the last and first state where if you don't specify any value the computed value will be considered (the initial one or the one defined in the style of the element)
If a 0% or from keyframe is not specified, then the user agent constructs a 0% keyframe using the computed values of the properties being animated. If a 100% or to keyframe is not specified, then the user agent constructs a 100% keyframe using the computed values of the properties being animated.ref
For the other states, you have in fact an interpolation considering the value you have defined and the one automatically done (in case you didn't define the 0% and 100%)
Related
This sample shows an animation that transitions from a scale of 100% to a scale of 70%:
.shrink {
animation-name: title-min;
animation-duration: 1s;
animation-iteration-count:infinite;
animation-timing-function: linear;
animation-fill-mode: forwards;
transform-origin: 0% 100% 0;
}
#keyframes title-min
{
from { transform: scale(1); }
to { transform: scale(.7); }
}
<body>
<h1 class="shrink">
Hello
</h1>
</body>
Now, transform is just a CSS property, wrapped in a block to define various targets in an animation sequence. Is it possible to specify that block external to the #keyframes block as some named CSS Ruleset or At-rule and reference it in the #keyfreames block?
Unfortunately, that is not possible outside of a preprocessor. In CSS, property declarations to change in an animation must appear within specific keyframe rules within the #keyframes at-rule.
The closest you can get is by abstracting the values in each keyframe to custom properties outside the #keyframes at-rule, then referencing them within it using var(), but the properties themselves (such as transform) still need to be specified inside the keyframe.
I'm trying to use two consecutive animations for an element using keyframes, but the second animation doesn't start in Chrome if I've set an animation-delay property until I make some interaction, like clicking somewhere. The code works as expected in Firefox.
Is this a bug or is there something that I'm doing wrong?
#-webkit-keyframes to-up {
from {
-webkit-transform: rotate(45deg);
}
to {
-webkit-transform: rotate(0);
}
}
#-webkit-keyframes move {
from {
-webkit-transform: rotate(0);
}
to {
-webkit-transform: translateY(-1000px);
}
}
.animate {
-webkit-animation-name: to-up, move;
-webkit-animation-duration: .5s, 1s;
-webkit-animation-delay: 0, 1.4s;
-webkit-animation-timing-function: ease-in, cubic-bezier(0.6, -0.28, 0.735, 0.045);
-webkit-animation-fill-mode: forwards;
}
Code on Codepen: http://codepen.io/kcmr/pen/Ibrnx
The animation-delay property is commented.
It turns out this is a bug reported nearly a year ago, which astounds me that it has not been fixed.
To fix it they said to change the second's animation-delay to the same length as the duration of the first. For you that would be
animation-delay: 0s, .5s;
They also discuss the possibility of running a second animation during that time (on a different element) which allows the second animation to run. I tested it and confirmed that it also fixes the issue, thus allowing you to have an animation-delay greater that .5s. Following is the animation (that does nothing) that I applied to the container, .wrapper
#keyframes empty {from{display:block;}to{display:block;}}
Good catch on the bug!
I have images that I want to swap in and out (no slide effect). The first cycle, the images appear stacked on top of each other (since they have holes). All subsequent cycles, it works correctly (only one visible at a time).
Html
<div class="small xfade">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
css
#keyframes xfade {
0% { opacity:1; }
17% { opacity:1; }
25% { opacity:0; }
92% { opacity:0; }
100% { opacity:1; }
}
.xfade span {
animation-name: xfade;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
animation-duration: 8s;
height: 100%;
left: 0;
/* opacity: 0; */
position: absolute;
top: 0;
width: 100%;
}
All visible at once during first loop
Only one visible during first loop, but flash
An usual scene when doing animations is where you have the same animation for several elements, but you want them to be delayed, making a sort of full cycle.
Then you set a animation-duration of say 8 seconds, and if you have 4 elements, you set a delay of 0 for the first, a delay of 2s for the second, and 4s and 6s for the others.
The problem with this is that the second element only starts animating after 2 seconds. In the meantime, it has the initial properties, that can match, or not, (usually not) the properties of the animation.
The best way to solve that is to realize that, if the animation-duration is 8s, then setting the delay to 2s is the same than setting it to -6s. because if you count 8s starting in -6s, you will end at 2s. But, then the animation is running from the first moment, with the properties that should have.
So, the delays in your case should be 0s, -6s, -4s, -2s. Just subtract the transition-duration from the transition delay.
Whenever you set an animation, and discover than the first animation is wrong, but after that they are ok, the likely problem (and solution) is this.
If you want to make everything go faster, but everything else being the same, then you have to reduce both the animation duration and all the animation delays
Example setting
.xfade span {
animation-duration: 4s;
}
.xfade span:nth-of-type(1) {
animation-delay: -1s;
}
.xfade span:nth-of-type(2) {
animation-delay: -2s;
}
.xfade span:nth-of-type(3) {
animation-delay: -3s;
}
fiddle
Also, let's analyze how the tween time is computed. First of all, you are setting the animation for an element that shares the full time with another 3 elements. That means that every element has 1/4 of the time, that is 25%.
This time has to be divided between time of full display and time of tween. Inthe original example, tween time is 8%. If you want that reduced, let's say that tween time will be 6%. Then, full display time will be 25 - 6 = 19.
That gives us the first part of the keyframes:
#keyframes xfade {
0% { opacity:1; }
19% { opacity:1; }
25% { opacity:0; }
Now, for the final keyframes, we have to remember that the tween time is 6, and set that at the end. The keyframe mus be at 100 - 6 = 94. Remainig keyframes:
94% { opacity:0; }
100% { opacity:1; }
}
I have an element that has css3 animation with keyframes applied to it but still I want to scale this element. But it seems that because transform translate is already applied in the animation transform scale is not working
e.g.: let say I have 4 clouds (div elements) moving from right to left, I want those clouds to be different scales
.x1 {
-webkit-animation-name: moveclouds;
-moz-animation-name: moveclouds;
animation-name: moveclouds;
-webkit-animation-duration: 170s;
-moz-animation-duration: 170s;
animation-duration: 170s;
-webkit-animation-timing-function: linear;
-moz-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-iteration-count: infinite;
-moz-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-transform: scale(0.79);
-moz-transform: scale(0.79);
-ms-transform: scale(0.79);
-o-transform: scale(0.79);
transform: scale(0.79);
}
.x2{ ...}
.x3{...}
.x4{...}
#keyframes moveclouds {
from {
transform: translateX(2400px);
/* note: I'm using vendor prefixes, I just want to simplified it here */
}
to {
transform: translateX(-200px);
}
}
animation works well, scale not
question: anyone got an ide how to enforce the scale ?
I'm using this example http://thecodeplayer.com/walkthrough/pure-css3-animated-clouds-background but tweeking it a bit (see the keyframe difference)
When setting a CSS property, you must set the complete value for the property. So in your example you are wanting to set the TRANSFORM property with multiple types of transforms (translateX and scale). You must set ALL transforms on a single property. Remove the current SCALE styles, and do the following (with vendor prefixes). Yes... you will have duplication. This is a shortcoming of complex CSS3 property values.
#keyframes moveclouds {
from {
transform: translateX(2400px) scale(0.79);
/* note: I'm using vendor prefixes, I just want to simplified it here */
}
to {
transform: translateX(-200px) scale(0.79);
}
}
To expand on this more, if you had an element with multiple background images:
.some-div {
background-image: url("img1.png"), url("img2.png");
}
and you wanted to change img2.png to img3.png on hover, you would have to:
.some-div:hover {
background-image: url("img1.png"), url("img3.png");
}
i am using keyframes to scale an element on my webpage. The problem is that the animation is running perfectly in chrome but its not running in safari. I am providing values at 0% , 80% and 100% in keyframes and everytime the animation ends it goes back to the properties defined at 80% and not 100%. i also used fill-mode to stop animation at last frame but still got no solution.
#-webkit-keyframes leftpageanim {
0%{ -webkit-transform:scale(1);
bottom:-26px;
}
80%{
-webkit-transform:scale(1.8) ; bottom:140px;
}
100%
{
-webkit-transform:scale(1.7); bottom:120px; }
}
after the animation ends its again reverting back to properties of 80%
I did some changes in the code. Look at this jsfiddle. The animation now stops at 100%. That's what you wanted, right?
from:
.animator {
-webkit-animation-name: leftpageanim;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: linear;
-webkit-animation-duration: 5s;
to:
.animator {
-webkit-animation: leftpageanim 5.0s ease-in-out forwards;
-webkit-animation-iteration-count: 1;