I have a website on which I'm showing a loading animation during page load using SVG and CSS3 animations. It works fine on Chrome and Firefox, but behaves incorrectly during page load on Safari 12.1.2
Until the page is fully loaded and the animation is over, the CSS animation won't have the correct duration, but instead will skip from one keyframe to the other without any transition. Once the page is loaded, the animations will start transitioning correctly between keyframes.
Here is a screencast of the issue: https://streamable.com/shca4
This is the CSS code I'm using for the animations. I use autoprefixer for browser support, but the issue is happening with safari 12.1.2 which should not be using a vendor prefix anyway.
#rightHand{
animation: rightHand 1s infinite 0s ease-in-out;
}
#leftHand{
animation: leftHand 1s infinite 0s ease-in-out;
}
#keyframes rightHand {
0%{
transform: translateX(0%) translateY(0%);
}
50%{
transform: translateX(5%) translateY(5%);
}
100%{
transform: translateX(0%) translateY(0%);
}
}
#keyframes leftHand {
0%{
transform: translateX(0%) translateY(0%);
}
50%{
transform: translateX(-5%) translateY(-5%);
}
100%{
transform: translateX(0%) translateY(0%);
}
}
Not sure if relevant, but I'm using the following code to add some body classes once the page is loaded to hide the animation:
$(window).on('load', function(){
$('body').removeClass('is-loading');
$('body').addClass('dom-loaded');
});
There are no errors in the console. Any idea why this is happening?
Related
As others have pointed out, CSS animations might get stuck or pause inadvertently because of performance issues, for example a busy JavaScript main thread, like CSS Animation, State change finish animation.
In the context of a webpage using existing third-party libraries or frameworks, we might have no control over the whole web app, so we cannot guarantee that the JavaScript behaves properly.
As there seems to be no way to increase an animation's priority over other browser tasks, and there seems to be no way to decrease the priority of browser tasks initiated by JavaScript so that CSS-initiated tasks are preferred either, and that may have unintended consequences as well, I want to focus on controlling the animation itself.
So, my questions are:
Is there a way to tell the browser, preferably using only CSS, that the animation should rather drop some frames to guarantee to reach the final state in time even if there are performance problems?
If so, can we use CSS animation syntax only, or do we need to use other techniques such as requestAnimationFrame() or complex libraries like GSAP?
Perhaps, there is something like a combination of animation-fill-mode and text-rendering: optimizeSpeed; but to control what to optimize when rendering animations, but I have searched and have not found anything helpful.
What I have tried so far:
.drawer {
position: fixed;
left: 100%;
transition: transform 3s;
background: blue;
}
.drawer.open {
transform: translateX(-400px);
animation-name: slidein;
animation-duration: 3s;
animation-fill-mode: forwards;
}
#keyframes slidein {
0% { transform: none; }
25% { transform: translateX(-100px); }
50% { transform: translateX(-200px); }
75% { transform: translateX(-300px); }
100%{ transform: translateX(-400px); }
}
<div class="drawer" id="drawer">drawer</div>
show drawer
Although, this is supposed to be a minimal reproducible example, the bug is hard to reproduce when taken out of context. Please try to use CPU throttling in developer tools to see what I mean.
.drawer {
position: fixed;
left: 100%;
transition: transform 3s;
background: blue;
}
.drawer.open {
transform: translateX(-400px);
animation-name: slidein;
animation-duration: 3s;
}
#keyframes slidein {
0% { transform: none; }
25% { transform: translateX(-100px); }
50% { transform: translateX(-200px); }
75% { transform: translateX(-300px); }
100% { transform: translateX(-400px); }
}
<div>
<div class="drawer open" id="drawer">drawer</div>
show drawer
</div>
I want to rotate an image for a specific time (for example 2 seconds) and with a specific speed and then the rotation gets slower until it stops.
I am not an expert, I just know how to rotate and image with css, but not with a given speed and and ending.
Give this a try. Using keyframes is a good way to build an animation. The animation will run for 2 seconds. The ease out property makes the animation end smoothly.
The forwards property keeps the image from reverting back to its original orientation.
<img src="" class="rotation-class" />
.rotation-class {
width: 200px;
animation: rotate-animation 2s ease-out forwards;
}
#keyframes rotate-animation {
from {transform: rotate(0deg);}
to {transform: rotate(90deg);}
}
To make the animation faster shorten the length of the animation. You can also use percentages in your keyframes animation to further customize your animation.
#keyframes rotate-animation {
10% {
transform: rotate(0deg);
}
20% {
transform: rotate(90deg);
}
100% {
transform: rotate(90deg);
}
}
I already widely searched on Google and Stackoverflow, but couldn't find a solution.
I made a simple mobile menu with some cool animations.
Here is the codepen: Codepen link
The problem should be in these lines, but I don't understand what's wrong.
.menu a:hover:before {
right: 100%;
visibility: visible;
-webkit-transform: scaleY(1) rotate(360deg);
transform: scaleY(1) rotate(360deg);
}
When you hover the menu, the bars rotate (and it works even on chrome and opera) and change color. If you click it, they rotate again to form a X (and it works even on chrome and opera).
When the menu appears, if you hover the links there's a bar that (should) rotate and go from right to left. If you do it in Firefox it works fine, the bars on the links appears smoothly and rotate from right to left, if you do it on Chrome or Opera, they just appear in the middle and go straight to the left.
Check the codepen, I already inserted browser keywords (i.e. -webkit-) and tried some options but no way to make it working.
Thanks in advance!
.menu a:before {
-webkit-transform: scaleY(0) rotate(0deg);
transform: scaleY(0) rotate(0deg);
-webkit-transition: all 1s ease-in-out 0s;
transition: all 1s ease-in-out 0s;
}
.menu a:hover:before {
right: 100%;
visibility: visible;
-webkit-transform: scaleY(1) rotate(360deg);
transform: scaleY(1) rotate(360deg);
}
works for me if i add rotate(0deg) to the "default" state of the before pseudo element
What I am trying to do is depending on a variable I get, change the 100% rotate value in the keyframe to the new calculated value. I have no problem with using Javascript to do this, but I want it to be done in the External CSS, not inline, once changed I need to restart the animation for that time. Is this possible? If so, how? (NOTE ALL DONE CURRENTLY THROUGH BUTTON CLICK) this is not to be saved, only done to update the graphic with a new position.
.arrow {
-webkit-animation: rotate 3s linear 0 1;
animation: rotate 3s linear 0 1;
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
-webkit-animation-play-state: paused;
animation-play-state: paused;
visibility: visible !important;
}
#-webkit-keyframes rotate {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Any help will be much appreciated! I have been trying to find something that would work for about a week now.
It is possible to change keyframes on loaded stylesheets. Here you have a stack overflow answer from 2011. And here's a link to a recent blog post about it.
So, as adeneo mentioned, it is not possible to make javascript change an external style sheet.
The thing you can do is make 2 css classes and use javascript to change the class. This way you are not using inline styles.
Also, because you are changing the class, the animation will begin from the start - as you want it.
I have CSS keyframe animations that are triggered by scroll behavior. If the user is scrolling too fast, I'd like to be able to send some of the animations to their 'finished/final' state using JavaScript given that the animations build off of each other.
Say I have a 3000ms animation that I decide I want to finish after 1500ms has passed -- Is it possible to force this CSS keyframe animation to finish early using JS?
** PS -- I'm not talking about persisting the final frame's properties using the forwards fill-mode.
Thanks!
How about using class to control status like this:
.play{
animation: animationFrames ease 5s;
-webkit-animation: animationFrames ease 5s;
-moz-animation: animationFrames ease 5s;
-o-animation: animationFrames ease 5s;
-ms-animation: animationFrames ease 5s;
}
.end{
transform: translateX(100px);
-moz-transform: translateX(100px);
-webkit-transform: translateX(100px);
-o-transform: translateX(100px);
-ms-transform: translateX(100px);
}
JavaScript
$('#end').click(function(){
$('#box').removeClass('play').addClass('end');
});
http://jsfiddle.net/a2Gsh/
Yes, simply change the animation duration to conclude the animation faster,
elementWithAnimation.style.animationDuration="1500ms";
You will need browser prefixes, for example for webkit:
elementWithAnimation.style.webkitAnimationDuration="1500ms";