I am trying to build a simple animation of a beaker tipping over. Everything is working great on desktop, but both iOS Safari and chrome, when the animation starts it jumps immediately to the last key frame (100%). So this tells me the animation is firing, but for some reason it just doesn't want to well... animate.
Here is my scss code. I have an auto-prefixer, I've checked and double checked, it doesn't seem to be anything to do with -webkit. Any help would be awesome!!
/** Our Process Area Edits **/
&.our-process-title {
#our-process-svg {
width: rem-calc(150);
height: rem-calc(150);
margin: 50px auto;
transform: translateZ(0);
animation-name: beakerShake;
animation-duration: 4s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-play-state: paused;
&.running {
animation-play-state: running;
}
#-webkit-keyframes beakerShake {
0% { -webkit-transform: rotateZ(0deg);}
5% { -webkit-transform: rotateZ(20deg); }
15% { -webkit-transform: rotateZ(-25deg); }
20% { -webkit-transform: rotateZ(0deg);}
40% { -webkit-transform: rotateZ(0deg);}
50% { -webkit-transform: rotateZ(5deg); }
55% { -webkit-transform: rotateZ(-10deg); }
58% { -webkit-transform: rotateZ(15deg); }
60% { -webkit-transform: rotateZ(0deg);}
65% { -webkit-transform: rotateZ(0deg);}
72% { -webkit-transform: rotateZ(30deg); }
78% { -webkit-transform: rotateZ(-35deg); }
85% { -webkit-transform: rotateZ(0deg);}
95% { -webkit-transform: rotateZ(0deg);}
100% { -webkit-transform: rotateZ(105deg);}
}
#keyframes beakerShake {
0% { transform: rotateZ(0deg);}
5% { transform: rotateZ(20deg); }
15% { transform: rotateZ(-25deg); }
20% { transform: rotateZ(0deg);}
40% { transform: rotateZ(0deg);}
50% { transform: rotateZ(5deg); }
55% { transform: rotateZ(-10deg); }
58% { transform: rotateZ(15deg); }
60% { transform: rotateZ(0deg);}
65% { transform: rotateZ(0deg);}
72% { transform: rotateZ(30deg); }
78% { transform: rotateZ(-35deg); }
85% { transform: rotateZ(0deg);}
95% { transform: rotateZ(0deg);}
100% { transform: rotateZ(105deg);}
}
EDIT:
After trying one last thing, of course I found the culprit. I am drawing this particular svg's path, and then when it's done drawing, changing the animation play state to running. Here is my js :
setTimeout(function(){
svg.style.animationPlayState = svg.style.WebkitAnimationPlayState = 'running';
}, 4500);
Once i removed that functionality it all worked fine. I really need this the animation to fire after the svg is drawn (for obvious reasons). Any help would be awesome.
Turns out this is an issue with how iOS and the mobile broswers handle the animation play state... Essentially they don't.
The solution was to add the class
.no-animation {
animation: none !important;
}
to the element, and remove that class with js when the time is right. Feels kind of like a hack, but its the only thing I could find to work on both mobile and desktop. If anyone has better suggestions, I'd love to hear them!
Related
I have a rather simple fiddle here: http://jsfiddle.net/7aotzqmL/2/ that is supposed to shake a div with CSS animation upon clicking a link. It works, but only every other time (every second time). I'm stumped - can anybody help?
Other answers I've looked at mentioned how when using onmouseover you also need to attach onmouseout... but this is just a click so I'm not sure that's relevant. I just want the div to shake on every click rather than every other.
jsFiddle: https://jsfiddle.net/7aotzqmL/2/
CSS code:
$(function() {
$('a').click(function(ev) {
$('div').toggleClass('shaker');
ev.preventDefault();
});
});
div.shaker {
animation: shake 0.3s;
/* When the animation is finished, start again */
animation-iteration-count: 1; //single shake
}
#keyframes shake {
0% {
transform: translate(1px, 1px) rotate(0deg);
}
10% {
transform: translate(-1px, -2px) rotate(-1deg);
}
20% {
transform: translate(-3px, 0px) rotate(1deg);
}
30% {
transform: translate(3px, 2px) rotate(0deg);
}
40% {
transform: translate(1px, -1px) rotate(1deg);
}
50% {
transform: translate(-1px, 2px) rotate(-1deg);
}
60% {
transform: translate(-3px, 1px) rotate(0deg);
}
70% {
transform: translate(3px, 1px) rotate(-1deg);
}
80% {
transform: translate(-1px, -1px) rotate(1deg);
}
90% {
transform: translate(1px, 2px) rotate(0deg);
}
100% {
transform: translate(1px, -2px) rotate(-1deg);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
asd
<div>shake</div>
Try this will work
$(function(){
$('a').click(function(ev){
$('div').addClass('shaker');
setTimeout(function(){
$('div').removeClass('shaker');
},300);
ev.preventDefault();
});
});
Below code is removing class on even time click, and you animation working on adding class
$('div').toggleClass('shaker');
in above solution, div class will be removed after 0.3secs animation, it will add 'shaker' class every time you click and animation will happen
You are toggling the class so the first click adds it and the second removes it. Instead you could add the class on click and set a single use event listener to listen for the animation end and then remove the class.
$(function() {
const div = $('.container')
$('a').click(function(ev) {
div.addClass('shaker')
div.one('animationend', () => {
div.removeClass('shaker')
})
ev.preventDefault();
});
});
.container {
opacity: 1;
width: 100px;
height: 100px;
background: red;
}
.container.shaker {
/* Start the shake animation and make the animation last for 0.5 seconds */
animation: shake 0.3s;
/* When the animation is finished, start again */
animation-iteration-count: 1; //single shake
}
#keyframes shake {
0% {
transform: translate(1px, 1px) rotate(0deg);
}
10% {
transform: translate(-1px, -2px) rotate(-1deg);
}
20% {
transform: translate(-3px, 0px) rotate(1deg);
}
30% {
transform: translate(3px, 2px) rotate(0deg);
}
40% {
transform: translate(1px, -1px) rotate(1deg);
}
50% {
transform: translate(-1px, 2px) rotate(-1deg);
}
60% {
transform: translate(-3px, 1px) rotate(0deg);
}
70% {
transform: translate(3px, 1px) rotate(-1deg);
}
80% {
transform: translate(-1px, -1px) rotate(1deg);
}
90% {
transform: translate(1px, 2px) rotate(0deg);
}
100% {
transform: translate(1px, -2px) rotate(-1deg);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
asd
<div class="container"></div>
Well, for one, you're TOGGLING the class. so one click means "add" the next one means "remove". Also, "preventdefault" should appear first in order to prevent the default behavior of the anchor tag before you try to add or remove classes.
$(function(){
$('a').click(function(ev){
ev.preventDefault();
$('div').addClass('shaker');
setTimeout(()=> {
$('div').removeClass('shaker');
},300)
});
});
$(function(){
$('a').click(function(ev){
$('div').addClass('shaker');
setTimeout(()=>{
$('div').removeClass('shaker');
},300)
ev.preventDefault();
});
});
Use the above code. You were removing the shaker class alternatively.
How can I trigger CSS class to start my logo animation when scrolling/changing slide with fullpage.js?
I have this (it works alright) for animating my SVG wheel logo:
.logo-img:hover #wheel {
-webkit-animation: in 1s;
transform-origin: 49% 50%;
}
#wheel {
-webkit-animation: out 1s;
transform-origin: 49% 50%;
}
#-webkit-keyframes in {
from { -webkit-transform: rotate(0deg); }
to { -webkit-transform: rotate(360deg);}
}
#-webkit-keyframes out {
0% { -webkit-transform: rotate(360deg); }
100% { -webkit-transform: rotate(0deg); }
}
It's a simple animation of spinning wheel 360deg., now I want it to spin when scrolling and use "in/out" keyframes depending on sliding page up or down.
I'm using fullpage.js and jquery v2.2.4
I hope It makes sense.
Thanks
Use the fullpage.js state classes.
So you can do:
.fp-viewing-section1-slide1 .myItem{
/*Whatever */
}
See my video tutorial here:
https://www.youtube.com/watch?v=qiCVPpI9l3M&t=5s
I'm looking for a way to animate a plane flying from off-page onto the page. At the moment, I'm using the code below, which is very clunky and not smooth. Do you know a better way to do this using CSS and HTML? If not, using another method?
.plane-animation{
animation: animationFrames linear 3s;
animation-iteration-count: 1;
transform-origin: 50% 50%;
-webkit-animation: animationFrames linear 3s;
-webkit-animation-iteration-count: 1;
-webkit-transform-origin: 50% 50%;
-moz-animation: animationFrames linear 3s;
-moz-animation-iteration-count: 1;
-moz-transform-origin: 50% 50%;
-o-animation: animationFrames linear 3s;
-o-animation-iteration-count: 1;
-o-transform-origin: 50% 50%;
-ms-animation: animationFrames linear 2s;
-ms-animation-iteration-count: 1;
-ms-transform-origin: 50% 50%;
}
#keyframes animationFrames{
0% {
transform: translate(100%,-20px) rotate(0deg) ;
}
10% {
transform: translate(90%,-30px) rotate(5deg) ;
}
20% {
transform: translate(80%,-40px) rotate(15deg) ;
}
30% {
transform: translate(70%,-50px) rotate(10deg) ;
}
40% {
transform: translate(60%,-60px) rotate(5deg) ;
}
50% {
transform: translate(50%,-70px) rotate(0deg) ;
}
60% {
transform: translate(40%,-60px) rotate(-5deg) ;
}
70% {
transform: translate(30%,-50px) rotate(-10deg) ;
}
80% {
transform: translate(20%,-40px) rotate(-15deg) ;
}
90% {
transform: translate(10%,-30px) rotate(-10deg) ;
}
100% {
transform: translate(0%,0px) rotate(0deg) ;
}
}
<img class="plane-animation" src="http://www.jetcharterrewards.com/images/Plane%20Icons/plane-icon-4.png" alt="Paper Airplane" />
It seems like you're on the right track, and CSS animations should be perfect for the task you're solving. A few quick pointers:
You've made prefixed animation calls like -webkit-, -moz-, -o- and -ms-. However, you've not made any prefixed keyframes. This makes the first part wasted. If you want full browser compatibility you also need prefixed keyframes and prefixed transforms.
Like this:
#keyframes animationFrames{
0% {
transform: translate(100%,-20px) rotate(0deg) ;
}
100% {
transform: translate(100%,-20px) rotate(0deg) ;
}
}
#-webkit-keyframes animationFrames{
0% {
-webkit-transform: translate(100%,-20px) rotate(0deg) ;
}
100% {
-webkit-transform: translate(100%,-20px) rotate(0deg) ;
}
}
....
and so on.
The other part is more esthetic, but I suggest trying to work on one property at a time. Try drawing your animation in lines on a piece of paper first, figure out the axis and vectors that it's moving on and code one at a time. I'm afraid no-one on here can give you a finished piece of code, but with enough practice, I'm sure you will get the hang of animating.
<style>
#keyframes shake {
0% {
-moz-transform:scale(0);opacity:0;
}
25% {
-moz-transform:scale(1.3);opacity:1;
}
50% {
-moz-transform:scale(0.7);opacity:1;
}
75% {
-moz-transform:scale(2);opacity:1;
}
100% {
-moz-transform:scale(1);opacity:1;-moz-transform:rotate(45deg);
}
}
</style>
<div style="-moz-animation-duration:2s;" onclick='this.style.mozAnimationName="shake";'>TEST</div>
It works fine in Google Chrome with its respective -webkit prefix, but with Firefox (-moz), it doesn't function properly.
Is there a solution for this, or is this simply a dumb mistake on my part? Furthermore, I do not want to utilize jQuery for my solution.
It doesn't work because Firefox no longer requires the vendor prefixes in more recent versions (starting from Firefox 16), so just drop those:
http://jsfiddle.net/nsca73oo/2/
<style>
#keyframes shake {
0% {
transform: scale(0);
opacity:0;
}
25% {
transform: scale(1.3);
opacity: 1;
}
50% {
transform: scale(0.7);
opacity: 1;
}
75% {
transform: scale(2);
opacity: 1;
}
100% {
transform: scale(1);
opacity: 1;
transform: rotate(45deg);
}
}
</style>
<div style="animation-duration: 2s;" onclick='this.style.animationName = "shake";'>TEST</div>
I'm going mad trying to get a spinner to appear. I've bound my heavy processing function to a button thus:
$(document).delegate("#clearread", "tap", onClearRead);
So on tap it calls this:
var onClearRead = function() {
setTimeout($.mobile.showPageLoadingMsg, 5);
// Civilised cleaning of saved status
var jStorIndex = $.jStorage.index();
for (var i = 0; i < jStorIndex.length; i++) {
if( jStorIndex[i] != "version" ) {
$.jStorage.deleteKey(jStorIndex[i]);
}
}
// Load articles afresh
loadArticles();
$.mobile.changePage("#choosearticle");
} //onClearRead
I find that the spinner does not appear during the clearing/loading of articles (about 10 secs) but only for a brief period while the #choosearticle page loads (0.5 secs).
What am I doing wrong?
I have the spinner working elsewhere in the app.
Thanks
Try this:
$(document).delegate("#clearread", "tap", onClearRead);
var onClearRead = function() {
$.mobile.showPageLoadingMsg();
setTimeout(function(){
//Your heavy processing
$.mobile.changePage("#choosearticle");
}, 5);
} //onClearRead
jQuery.show( [duration ] [, complete ] )
Putting the heavy processing in the "complete" function slot, ensures the object (with show called on it) is visible before the show happens.
Related SO Answers
https://stackoverflow.com/a/25207120/999943
jQuery whole HTML page load with spinner
Example using a CSS based spinner
CSS
#-moz-keyframes spin {
0% {
-moz-transform: rotate(0deg); }
100% {
-moz-transform: rotate(359deg); } }
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg); }
100% {
-webkit-transform: rotate(359deg); } }
#-o-keyframes spin {
0% {
-o-transform: rotate(0deg); }
100% {
-o-transform: rotate(359deg); } }
#-ms-keyframes spin {
0% {
-ms-transform: rotate(0deg); }
100% {
-ms-transform: rotate(359deg); } }
#keyframes spin {
0% {
transform: rotate(0deg); }
100% {
transform: rotate(359deg); } }
.icon-spin {
display: inline-block;
-moz-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
-webkit-animation: spin 2s infinite linear;
animation: spin 2s infinite linear; }
Html using font awesome
<div id="spinner" data-bind="visible: isSpinning" style="padding: 10px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: #cccccc; z-index: 1; filter: alpha(opacity=30);">
<i class="fa fa-spinner fa-spin fa-5x"></i>
</div>
Javascript
$('#spinner').show(100, function() {
// Once the spinner is visible then run the heavy function.
heavyProcessingFunction();
});