Can I run an animation forward and in reverse? [duplicate] - css

I've used two keyframe animations in CSS. One moves from left to right and the other one uses exact the same values - but reversed.
#keyframes moveLeft
{
from {transform: translate3d(50px, 0, 0);}
to {transform: translate3d(0px, 0, 0);}
}
#keyframes moveRight
{
from {transform: translate3d(0px, 0, 0);}
to {transform: translate3d(50px, 0, 0);}
}
However, I wonder whether it's possible to use one keyframe animation only. but as soon as I add animation-direction: reverse, the animation does only play once. It probably saves the information that it has been used once before.
So: can I reset this information somehow? Or is there any possibility to use one animation twice in different directions? (without using JS)
http://jsfiddle.net/vrhfd66x/

No, there is no way to restart the animation using CSS alone. You'd have to use JavaScript to remove the animation from the element and then re-apply it to the element (after a delay) for it to restart.
The below is what the W3C's CSS3 Animation Spec says (in a different context, but the point should hold good for this case also):
Note also that changing the value of ‘animation-name’ does not necessarily restart an animation (e.g., if a list of animations are applied and one is removed from the list, only that animation will stop; The other animations will continue). In order to restart an animation, it must be removed then reapplied.
emphasis is mine
This CSS Tricks Article by Chris Coiyer also indicates the same and provides some JS solutions for restarting an animation. (Note: The article has a reference to Oli's dabblet which claims that altering properties like duration, iteration count makes it restart on Webkit but it seems to be outdated as they no longer work on Chrome).
Summary:
While you have already touched upon the following, I am going to re-iterate for completeness sake:
Once an animation is applied on the element, it remains on the element until it is removed.
UA does keep track of the animation being on the element and whether it has completed or not.
When you apply the same animation on :checked (albeit with a different direction), the UA does nothing because the animation already exists on the element.
The switch of positions (instantaneous) while clicking the checkbox is because of the transform that is applied within the :checked selector. The animation's presence makes no difference.
Solutions:
As you can see from the below snippet, achieving this with a single animation is pretty complex even when using JavaScript.
var input = document.getElementsByClassName("my-checkbox")[0];
input.addEventListener('click', function() {
if (this.checked) {
this.classList.remove('my-checkbox');
window.setTimeout(function() {
input.classList.add('anim');
input.classList.add('checked');
}, 10);
} else {
this.classList.remove('anim');
window.setTimeout(function() {
input.classList.remove('checked');
input.classList.add('my-checkbox');
}, 10);
}
});
input {
transform: translate3d(50px, 0, 0);
}
.my-checkbox {
animation: moveLeft 1s;
animation-direction: reverse;
}
.checked {
transform: translate3d(0px, 0, 0);
}
.anim{
animation: moveLeft 1s;
}
#keyframes moveLeft {
from {
transform: translate3d(50px, 0, 0);
}
to {
transform: translate3d(0px, 0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<input type="checkbox" class="my-checkbox">
So, the best option (if you want to stick to CSS animations) is to use two different animations.
Alternately, you could also have a look at Marcelo's comment. If the actual use-case is exactly what is provided in the fiddle then transition would suffice and animation isn't required. Transitions can work both in forward and reverse directions by nature and hence would be a safer bet.

Related

Reuse CSS animation in reversed direction (by resetting the state?)

I've used two keyframe animations in CSS. One moves from left to right and the other one uses exact the same values - but reversed.
#keyframes moveLeft
{
from {transform: translate3d(50px, 0, 0);}
to {transform: translate3d(0px, 0, 0);}
}
#keyframes moveRight
{
from {transform: translate3d(0px, 0, 0);}
to {transform: translate3d(50px, 0, 0);}
}
However, I wonder whether it's possible to use one keyframe animation only. but as soon as I add animation-direction: reverse, the animation does only play once. It probably saves the information that it has been used once before.
So: can I reset this information somehow? Or is there any possibility to use one animation twice in different directions? (without using JS)
http://jsfiddle.net/vrhfd66x/
No, there is no way to restart the animation using CSS alone. You'd have to use JavaScript to remove the animation from the element and then re-apply it to the element (after a delay) for it to restart.
The below is what the W3C's CSS3 Animation Spec says (in a different context, but the point should hold good for this case also):
Note also that changing the value of ‘animation-name’ does not necessarily restart an animation (e.g., if a list of animations are applied and one is removed from the list, only that animation will stop; The other animations will continue). In order to restart an animation, it must be removed then reapplied.
emphasis is mine
This CSS Tricks Article by Chris Coiyer also indicates the same and provides some JS solutions for restarting an animation. (Note: The article has a reference to Oli's dabblet which claims that altering properties like duration, iteration count makes it restart on Webkit but it seems to be outdated as they no longer work on Chrome).
Summary:
While you have already touched upon the following, I am going to re-iterate for completeness sake:
Once an animation is applied on the element, it remains on the element until it is removed.
UA does keep track of the animation being on the element and whether it has completed or not.
When you apply the same animation on :checked (albeit with a different direction), the UA does nothing because the animation already exists on the element.
The switch of positions (instantaneous) while clicking the checkbox is because of the transform that is applied within the :checked selector. The animation's presence makes no difference.
Solutions:
As you can see from the below snippet, achieving this with a single animation is pretty complex even when using JavaScript.
var input = document.getElementsByClassName("my-checkbox")[0];
input.addEventListener('click', function() {
if (this.checked) {
this.classList.remove('my-checkbox');
window.setTimeout(function() {
input.classList.add('anim');
input.classList.add('checked');
}, 10);
} else {
this.classList.remove('anim');
window.setTimeout(function() {
input.classList.remove('checked');
input.classList.add('my-checkbox');
}, 10);
}
});
input {
transform: translate3d(50px, 0, 0);
}
.my-checkbox {
animation: moveLeft 1s;
animation-direction: reverse;
}
.checked {
transform: translate3d(0px, 0, 0);
}
.anim{
animation: moveLeft 1s;
}
#keyframes moveLeft {
from {
transform: translate3d(50px, 0, 0);
}
to {
transform: translate3d(0px, 0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<input type="checkbox" class="my-checkbox">
So, the best option (if you want to stick to CSS animations) is to use two different animations.
Alternately, you could also have a look at Marcelo's comment. If the actual use-case is exactly what is provided in the fiddle then transition would suffice and animation isn't required. Transitions can work both in forward and reverse directions by nature and hence would be a safer bet.

Page paint time stays high after css filter is removed

I use a div as a frame to add a css filter on whatever its content.
<div id="blurbox_wholescreen" class="blurbox">
...page content...
</div>
The filter is activated via css class.
.blurbox
{
transform: translate3d(0,0,0);
transition: all .5s ease;
}
.blurbox.blured
{
filter: blur(4px) brightness(80%) contrast(130%);
-webkit-filter: blur(4px) brightness(80%) contrast(130%);
}
When I toggle the class, the content of the blurbox gets blured.
function menu_toggle()
{
...
$("#blurbox_wholescreen").toggleClass("blured");
...
}
The 'Page paint time' displayed by the Chrome Inspector is low first (around 7ms) and as expected jumps up (to about 25ms) when the filter is applied. So far so good.
What bothers me is that it stays that high when I untoggle the ".blured" class again. I anticipate that the FPS should go back to default, as the performance heavy filter is removed. But it doesn't and I am puzzled.
Explanation somebody or tips how to tackle that?

Safari (mobile + desktop) grouping CSS Keyframe Animations

I'm having trouble with Safari creating an effect that mimics bubbles floating into the air, except with feathers. I've omitted some code to get to the gist of things. The url to the work-in-progress is here.
Here are the webkit styles for my animated objects.
#-webkit-keyframes f1 {
100% {
-webkit-transform: translateX(-25px) translateY(-350px);
}
}
.feather {
/* other styling omitted */
-webkit-animation-duration: 7s;
-webkit-animation-timing-function: linear;
}
And the javascript to create a bunch of objects.
animateFeathers = function() {
var $feather = $('<img>'),
$feather.addClass('feather animated');
$feather.attr('src','img/feather.png');
$feather.css('-webkit-animation-name','f1');
$featherContainer.append($feather);
setTimeout(function() {
$feather.remove();
}, 9000);
// random time to create next feather
var rTimeout = Math.random() * maxTime + minTime;
setTimeout(animateFeathers, rTimeout);
}
If you visit the link in Chrome or Firefox you'll see the intended effect. However in Safari (again, mobile or desktop) the feathers stack and only animate in a group every 7 seconds. I'd like for them to begin their animation as soon as they are inserted into the DOM. Any ideas on this?
Had to resort to using a canvas as I really couldn't get performance working on Safari. Took quite a few hours, but its working:
http://poetreatapp.com/

webkit animation not working, # before # in css

The site where I want my animation to work adds #user-space before any of my tags. So, my animation looks like this:
#user-space #-webkit-keyframes animation-name {
from {
style definition ["Before"-state]
}
to {
style definition ["After"-state]
}
And that #user-space declaration is breaking the css statement and animation is not working. Is there any way, to do that otherwise? For exaple put my keyframes insine -webkit-animation: animation-name 1.1s ease infinite; like
webkit-animation: from {
style definition ["Before"-state]
}
to {
style definition ["After"-state]
} 1.1s ease infinite; like
The solution I see is to get around your problem and do it with javascript.
Simply add a new style in your html file (in the header) and add the #-webkit-keyframes animation inside.
There is a thread which explains it well (see accepted solution): Set the webkit-keyframes from/to parameter with JavaScript

jQuery Mobile: How do you simulate the iOS slide-out navigation pattern on jQuery Mobile?

EDIT 2/13: The Panels widget in jQuery Mobile 1.3 now exists! Please use this instead.
I'm trying to write a custom CSS-based transition in jQuery Mobile to simulate the slide-out navigation design pattern.
What I'm trying to accomplish is to have the navigation slide into view and take up 75% of the viewport space. The remaining 25% is filled with the remainder of the previous page.
Here's my CSS:
.slidenav.in { /*New page coming in*/
-webkit-transform: translateX(-75%);
-webkit-animation-name: slidenav-in;
}
#-webkit-keyframes slidenav-in {
from { -webkit-transform: translateX(-75%); }
to { -webkit-transform: translateX(0); }
}
.slidenav.out { /*Old page going out*/
-webkit-transform: translateX(0);
-webkit-animation-name: slidenav-content-out;
}
#-webkit-keyframes slidenav-content-out {
from { -webkit-transform: translateX(0); }
to { -webkit-transform: translateX(75%); }
}
.slidenav.in.reverse { /*Old page coming in*/
-webkit-transform: translateX(75%);
-webkit-animation-name: slidenav-content-in;
}
#-webkit-keyframes slidenav-content-in {
from { -webkit-transform: translateX(75%); }
to { -webkit-transform: translateX(0); }
}
.slidenav.out.reverse { /*New page going out*/
-webkit-transform: translateX(0);
-webkit-animation-name: slidenav-out;
}
#-webkit-keyframes slidenav-out {
from { -webkit-transform: translateX(0); }
to { -webkit-transform: translateX(-75%); }
}
I can't seem to get it to do what I want, though. It removes the old page entirely instead of leaving the remaining 25% of the page in view.
You can see what's happening here (Webkit browsers): http://jsbin.com/ukajeb/7
What am I doing wrong?
EDIT 2/13: The Panels widget in jQuery Mobile 1.3 now exists! Please use this instead.
So I worked some more on this and, with the help of Firebug, discovered that after the keyframe animation was occurring, the original page was being reset to its original position and display set to none.
Knowing this, I started going through the jQuery Mobile docs a bit more thoroughly and found that there are Page Transition Events that you can bind to. More specifically, the pageshow and pagehide events.
Then I set the CSS of the original page manually:
$('[data-role=page]').live('pagehide',function(event, ui){
$(this).css({
"display": "block",
"-webkit-transform": "translateX(75%)"
});
});
$('[data-role=page]').live('pageshow',function(event, ui){
$(this).css({
"display": "",
"-webkit-transform": ""
});
});
Check it out here (Webkit browsers): http://jsbin.com/ukajeb/3
Hope someone else finds this useful as well!
Note: This demo uses jQuery Mobile 1.0.1, which only supports jQuery 1.6.4. This is why .live() was used rather than .on(). However, the upcoming jQuery Mobile 1.1.0 will support jQuery 1.7.1, so moving forward .on() should be used in place of the deprecated .live().
I don't know if this will fully help, but I took a look at this inside of firebug a bit. What I think is happening is when you complete the transition (even the partial one) the active page becomes the menu you are transitioning to. This means the last page is being hidden as it is no longer active. And in fact you can see when the transition completes the other page with "content" disappears.
You might try this on your link that invokes the menu - try using a dialog. You would still need to apply your custom transition there. I think what you are trying to accomplish you may also look into a plugin called "sub page" it may get you to the look you are trying to achieve. Also there is splitview (http://asyraf9.github.com/jquery-mobile/) Alternately you could try messing around with the 1.2 branch of JQM and see if POPUP men may get you there as well. Essentially, it is a div that can sit on top of the existing active page.
Open dialog
I originally was using a dialog with a slide up / down effect - but it became too troublesome in Android so we removed it.
I don't think JQM was really designed by default to keep two pages active and visible at once.

Resources