This trivial CSS animation code snippet doesn't get 60 fps in Chrome 58 on a MacBook Pro (15-inch, 2016), according to the Performance tab in Dev Tools. It's mostly smooth, but the square occasionally visibly skips a frame or two during animation. Why? How do I fix this?
EDIT: It still reproduces in Chrome 79 on a 16-inch 2019 MacBook Pro.
div {
background-color: red;
height: 10vh;
width: 10vh;
margin: 10vh;
animation-name: slide;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
#keyframes slide {
0% { transform: translateX(0); }
50% { transform: translateX(1000%); }
100% { transform: translateX(0); }
}
<div></div>
I managed to get a Chromium engineer to look into this on Twitter.
https://mobile.twitter.com/flackrw/status/1225116562010656769
Sadly the animation isn't composited because the percentage transform keyframe is dependent on a layout size. This isn't fundamental and it's on our short list of things to fix! https://crbug.com/389359 It's a good example of why compositing effects helps a lot.
But switching from translateX(1000%) to 400px didn't help. https://css-stutter.glitch.me/ So another bug was filed:
https://mobile.twitter.com/flackrw/status/1225144162858799104
Thanks for trying - I'm able to see the same! I filed https://crbug.com/1049248 and recorded a trace where I saw that the call to SwapBuffers is taking a long time once in a while. Feel free to add any details I may have missed.
So hopefully we'll have an answer there soon-ish. I also see the same issue on Safari 13 for macOS 10.15, so I've filed a WebKit bug as well.
https://bugs.webkit.org/show_bug.cgi?id=207282
There appears to be no way to work around this issue at this time.
I'd don't see a lot of issues in Chrome on a 2017 MBP 13" using your code. However, replacing the vh/wv units with px to avoid any browser overhead from checking dynamic sizes and adding will-change: transform; cleaned it up the minimal issues I was seeing.
There's some pretty good information in this article Smooth as Butter: Achieving 60 FPS Animations with CSS3 that might give you additional ideas.
However, at this point, I might attribute any jankiness to other elements on the page that aren't in your example.
div {
background-color: red;
height: 20px;
width: 20px;
margin: 20px;
animation-name: slide;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
will-change: transform;
}
#keyframes slide {
0% { transform: translateX(0); }
50% { transform: translateX(1000%); }
100% { transform: translateX(0); }
}
<div></div>
Related
I have a 4 part CSS3 animation playing on click - but the last part of the animation is meant to take it off the screen.
However, it always goes back to its original state once it has played. Anyone know how I can stop it on its last css frame (100%), or else how to get rid of the whole div it is in once it has played.
#keyframes colorchange {
0% { transform: scale(1.0) rotate(0deg); }
50% { transform: rotate(340deg) translate(-300px,0px) }
100% { transform: scale(0.5) rotate(5deg) translate(1140px,-137px); }
}
You're looking for:
animation-fill-mode: forwards;
More info on MDN and browser support list on canIuse.
If you want to add this behaviour to a shorthand animation property definition, the order of sub-properties is as follows
animation-name - default none
animation-duration - default 0s
animation-timing-function - default ease
animation-delay - default 0s
animation-iteration-count - default 1
animation-direction - default normal
animation-fill-mode - you need to set this to forwards
animation-play-state - default running
Therefore in the most common case, the result will be something like this
animation: colorchange 1s ease 0s 1 normal forwards;
See the MDN documentation here
-webkit-animation-fill-mode: forwards; /* Safari 4.0 - 8.0 */
animation-fill-mode: forwards;
Browser Support
Chrome 43.0 (4.0 -webkit-)
IE 10.0
Mozilla 16.0 ( 5.0 -moz-)
Shafari 4.0 -webkit-
Opera 15.0 -webkit- (12.112.0 -o-)
Usage:-
.fadeIn {
animation-name: fadeIn;
-webkit-animation-name: fadeIn;
animation-duration: 1.5s;
-webkit-animation-duration: 1.5s;
animation-timing-function: ease;
-webkit-animation-timing-function: ease;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
The best way seems to put the final state at the main part of css. Like here, i put width to 220px, so that it finally becomes 220px. But starting to 0px;
div.menu-item1 {
font-size: 20px;
border: 2px solid #fff;
width: 220px;
animation: slide 1s;
-webkit-animation: slide 1s; /* Safari and Chrome */
}
#-webkit-keyframes slide { /* Safari and Chrome */
from {width:0px;}
to {width:220px;}
}
Isn't your issue that you're setting the webkitAnimationName back to nothing so that's resetting the CSS for your object back to it's default state. Won't it stay where it ended up if you just remove the setTimeout function that's resetting the state?
I just posted a similar answer, and you probably want to have a look at:
http://www.w3.org/TR/css3-animations/#animation-events-
You can find out aspects of an animation, such as start and stop, and then, once say the 'stop' event has fired you can do whatever you want to the dom. I tried this out some time ago, and it can work, but I'd guess you're going to be restricted to webkit for the time being (but you've probably accepted that already). Btw, since I've posted the same link for 2 answers, I'd offer this general advice: check out the W3C - they pretty much write the rules and describe the standards. Also, the webkit development pages are pretty key.
Nobody actualy brought it so, the way it was made to work is animation-play-state set to paused.
I learned today that there is a limit you want to use for the fill-mode. This is from an Apple dev. Rumor is * around * six, but not certain.
Alternatively, you can set the initial state of your class to how you want the animation to end, then * initialize * it at from / 0% .
I am having an issue with Chrome (v. 67) at OSX and movement animations. I've prepared JS fiddle with it:
https://jsfiddle.net/5m173ghv/31/
If you open it at safari it is working very good. But, when you will use chrome it has little lags when moving.
I cannot describe it a bit more... You need to open it and try yourself on the big screen... Please look carefully at white box. You will see that this box has sometimes something like lags or small jumps(?)...
This is very weird. I've tried almost every answer from the internet (trust me ;) ).
I also tried:
Change transforms at animation into position (left)
Change animations into transitions
adding additional parameters (backface-visibility, perspective, will-change...)
Changing sequences of animation to have more steps (per 10%)
Debugging on chrome dev tools (~30-40fps)
Adding transforms like translateZ(0)
You think that this is chrome bug or maybe my fault? Do you have any solution for that?
Here you have code:
HTML
<span class="spark"></div>
SCSS
body {
background-color: black;
}
#keyframes left-to-right {
0% {
transform: translate3d(0,0,0);
}
100% {
transform: translate3d(50vw,0,0);
}
}
.spark {
position: absolute;
top: 30px;
width: 322px;
height: 500px;
background-color: white;
transform: translate3d(0,0,0);
backface-visibility: hidden;
perspective: 1000px;
animation: left-to-right 5s infinite linear;
will-change: transform;
pointer-events: none;
user-select: none;
}
I have a question/problem, regarding the animations in CSS3. No matter what I try, I can't achieve a smooth animation when my screen is set to 120hz. There's a laggy effect from time to time. If I set the screen to 60hz, it's fine. I was able to reproduce the issue on all the major browsers. Here's a link with a simple animation to illustrate the problem : https://jsfiddle.net/na1dx182/
<div id="container">
<div id="track"></div>
</div>
#container {
width: 600px;
height: 400px;
background: #ddd;
}
#track {
position: absolute;
width: 8px;
height: 400px;
background: #242424;
-webkit-animation: bounce 1s linear infinite alternate;
-moz-animation: bounce 1s linear infinite alternate;
animation: bounce 1s linear infinite alternate;
}
#keyframes bounce {
from {
transform: translateX(0);
}
to {
transform: translateX(600px);
}
}
My first question is, is it related to my screen only, or anyone else with a 120hz screen is experiencing this issue too ? When I look at the animation, it's like some frames are skipped sometimes, there's a laggy effect from time to time. I have the feeling the moving bar is doing some micro jumps.
If this issue is also found by others, is there a way to fix this ? I tried many different things, including the use of transitions, of requestAnimationframe, of setInterval, but the problem is always the same. I also tried other tricks or CSS properties, like translateZ(0), backface-visibility, will-change, but no luck.
Edit : It seems like unplugging and reconnect my screens has almost fixed the issue.
I have a 4 part CSS3 animation playing on click - but the last part of the animation is meant to take it off the screen.
However, it always goes back to its original state once it has played. Anyone know how I can stop it on its last css frame (100%), or else how to get rid of the whole div it is in once it has played.
#keyframes colorchange {
0% { transform: scale(1.0) rotate(0deg); }
50% { transform: rotate(340deg) translate(-300px,0px) }
100% { transform: scale(0.5) rotate(5deg) translate(1140px,-137px); }
}
You're looking for:
animation-fill-mode: forwards;
More info on MDN and browser support list on canIuse.
If you want to add this behaviour to a shorthand animation property definition, the order of sub-properties is as follows
animation-name - default none
animation-duration - default 0s
animation-timing-function - default ease
animation-delay - default 0s
animation-iteration-count - default 1
animation-direction - default normal
animation-fill-mode - you need to set this to forwards
animation-play-state - default running
Therefore in the most common case, the result will be something like this
animation: colorchange 1s ease 0s 1 normal forwards;
See the MDN documentation here
-webkit-animation-fill-mode: forwards; /* Safari 4.0 - 8.0 */
animation-fill-mode: forwards;
Browser Support
Chrome 43.0 (4.0 -webkit-)
IE 10.0
Mozilla 16.0 ( 5.0 -moz-)
Shafari 4.0 -webkit-
Opera 15.0 -webkit- (12.112.0 -o-)
Usage:-
.fadeIn {
animation-name: fadeIn;
-webkit-animation-name: fadeIn;
animation-duration: 1.5s;
-webkit-animation-duration: 1.5s;
animation-timing-function: ease;
-webkit-animation-timing-function: ease;
animation-fill-mode: forwards;
-webkit-animation-fill-mode: forwards;
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
The best way seems to put the final state at the main part of css. Like here, i put width to 220px, so that it finally becomes 220px. But starting to 0px;
div.menu-item1 {
font-size: 20px;
border: 2px solid #fff;
width: 220px;
animation: slide 1s;
-webkit-animation: slide 1s; /* Safari and Chrome */
}
#-webkit-keyframes slide { /* Safari and Chrome */
from {width:0px;}
to {width:220px;}
}
Isn't your issue that you're setting the webkitAnimationName back to nothing so that's resetting the CSS for your object back to it's default state. Won't it stay where it ended up if you just remove the setTimeout function that's resetting the state?
I just posted a similar answer, and you probably want to have a look at:
http://www.w3.org/TR/css3-animations/#animation-events-
You can find out aspects of an animation, such as start and stop, and then, once say the 'stop' event has fired you can do whatever you want to the dom. I tried this out some time ago, and it can work, but I'd guess you're going to be restricted to webkit for the time being (but you've probably accepted that already). Btw, since I've posted the same link for 2 answers, I'd offer this general advice: check out the W3C - they pretty much write the rules and describe the standards. Also, the webkit development pages are pretty key.
Nobody actualy brought it so, the way it was made to work is animation-play-state set to paused.
I learned today that there is a limit you want to use for the fill-mode. This is from an Apple dev. Rumor is * around * six, but not certain.
Alternatively, you can set the initial state of your class to how you want the animation to end, then * initialize * it at from / 0% .
First of all, sorry if the title is wrong because I don't know if these are actually called rotating loaders or not. This is what I am talking about: JSFiddle
I have 2 problems with these loaders,
in .chrome-loader, if I set height: 50px; width: 50px;, and and in .ring-maker set top: 2.5px; left: 2.5px it doesn't work very well. Does px unit support values upto 2 decimal places? I guess they don't. So what can I do to fix it? I basically want to make it of same size as the ones above. Perhaps, some other unit?
For .win8-loader I set this CSS animation for first dot.
#-webkit-keyframe win8dot1 {
0% {left: -10px;}
33% {left: 500px;}
66% {left: 780px;}
100% {left: 1280px;}
}
But it doesn't work. The first dot doesn't even move.
PS: are names like abc1-de2 allowed for keyframes?
You have to correct 2 problems
Your CSS
.win8-loader .dot1 { -webkit-animation: win8-dot1 2.5s infinite linear; }
#-webkit-keyframe win8dot1 {
corrected:
.win8-loader .dot1 { -webkit-animation: win8dot1 2.5s infinite linear; }
#-webkit-keyframes win8dot1 {