I am trying to create a slideshow which will use CSS3 Transitions when available and classes to animate between. I am having trouble setting initial values from which to animate from however.
What I am trying to do is
take off transitions so move is immediate
set the class needed for the positioning of my element
turn transitions back on
changes classes so that animation takes place
The code I was trying to use is
item //set initial position
.css(vP + "transition", "")
.removeClass('left').removeClass("right").removeClass("center")
.addClass(toClass)
//move
.css(vP + "transition", css3Transition)
.removeClass(toClass)
.addClass('center');
However the initial class doesn't seem to be applied.
Example in action is here http://jsfiddle.net/EcvBP/31/
How would I get this class to be applied (so that items are repositioned before the transition)?
Following Gerben's pointer I was able to get it working, the working code is included in the link below, the solution was to delay the transition slightly.
item
//set inital move from position
.css(vP + "transition", "")
.removeClass("left right center")
.addClass(toClass)
.delay(10, "doMove").queue("doMove", function(){
//move
$(this).css(vP + "transition", css3Transition)
.removeClass(toClass)
.addClass("center");
}).dequeue("doMove");
http://jsfiddle.net/EcvBP/37/
I don't think jQuery can add css properties in the format you've written. You could just write a css class like
.transition {
-moz-transition: all 0.2s linear;
-webkit-....
transition...
}
and then use addClass('transition') and removeClass('transition') to add and remove transitions.
Alternatively, try just "transition" instead of with the browser prefix like you've used, although, again, not sure about it actually working.
EDIT: Just saw that you need tween speed. You might have to use a plugin like plugins.jquery.com/plugin-tags/css3-transitions
Related
Put simply, I have a class that I apply to an element when a certain event happens. It is a CSS keyframe animation, and I use classList.toggle to apply the animation at the right time. However, I need to be able to edit a property of this class (animation duration) before I even apply the class to the element.
Is there a way to edit a class which has not yet been applied to any element using only JavaScript (not jQuery)?
What I'm looking for:
function changeSpeed(n) {
// Get class and be able to change the properties
// Edit animation and change duration to "s" seconds
// Example: CLASSNAME.style.animation = `animation-name` + n + `s`;
}
One possible answer which seems to be working (for now):
I only add "animation-duration: 0.7s" to the Id of the element that the animation gets applied to. From there, I can use document.getElementById(elementId).style.animationDuration to set the animation to whatever I want.
CSS variables can help you here.
Set the class up initially as you normally would except make the animation-duration a var instead of a fixed amount.
.classname {
animation-name: your keyframes name;
animation-iteration-count: whatever you want;
etc for any animation properties you want to set
animation-duration: var(--speed);
}
Then your JS function can change it whenever you get a time you'd like to set without needing to have set any element with the class:
function changeSpeed(n) {
document.body.style.setProperty('--speed', n + 's');
}
I've used body here but any element containing any other element you want to animate in the future will do.
I am building non-jQuery responsive image slider based on CSS3 transitions.
The structure is simple: a viewport and inside relatively positioned UL with left floated LIs.
I am facing a problem in such situation:
User clicks "prev" arrow.
JS appends proper LI before currently displayed LI node.
For now UL has set CSS transition as none 0s linear to prevent animation changes. In this moment I decrease UL CSS left value by slider width (let's say: from 0px to -1200px) to make view the same as it was.
Now I am changing UL's transition property to all 0.2s ease-out.
Now I am changing UL's left property to trigger CSS3 animation. (let's say: from -1200px to 0px).
What is the problem? Browser simplifies changes and does not make any animations.
Stoyan Stefanov wrote about reflow problem at his blog here, but in this case trying to force a reflow on element doesn't work.
This is a piece of code doing this (I skipped browser prefixes for simplification):
ul.style.transition = 'none 0s linear 0s';
ul.style.left = '-600px';
ul.style.transition = 'all 0.2s ease-out';
ul.style.left = '0px';
Here is fiddle to see problem in action: http://jsfiddle.net/9WX5b/1/
Requesting the offsetHeight of an element does everything nicely. You can force a reflow using this function and passing it the element that styles have been changed on:
function reflow(elt){
console.log(elt.offsetHeight);
}
And call this where reflows are needed. See this example: http://jsfiddle.net/9WX5b/2/
EDIT: recently needed to do this, and wondered if there was a better way than to console.log it. You can't just write elt.offsetHeight as it's own statement, as the optimizer (Chrome's, at least) will not trigger a reflow because it is just accessing a property with no getter set, no need to even evaluate it. So, AFAIK the cheapest way to do this is void(elt.offsetHeight), as it does not know for sure if void has side effects or not. (could be overridden or something, idk).
function reflow( element ) {
if ( element === undefined ) {
element = document.documentElement;
}
void( element.offsetHeight );
}
It works OK with Chrome and FF, and seems to be the simplest and most portable way to do it ATM.
I'm trying to write a directive to move an element from one position on screen to another on click, using a CSS transition, where the position is determined by Javascript / attribute on the element, and not known ahead of time in the pre-written CSS. Also, I need a callback, to a function in the $scope, done at the end of the transition, which is specified in a custom attribute. So the element looks like
<button move-me="100" move-me-after="afterMove()">Move Me!</button>
In order to use $animate for this, in my custom directive moveMe, on click I dynamically add a style block to the page
<style> .move-me-1 {....}</style>
and then use
$animate.addClass(iElement, 'move-me-1', function() { ... });
to handle the animation and the callback once it's finished. An example plunkr is available at
http://plnkr.co/edit/XRMRO93vl248Ve02Jnpo?p=preview
This seems overly complicated: adding style tags to the page seems quite convoluted. I'm doing this so the transition itself can be specified in an external style sheet, in terms of the run time, and the timing function, and using $animate.addClass so Angular can then determine the correct time to fire the callback.
Is there a simpler/better way of achieving what I want?
This example is simplified to my actual use case. In my case the element animated is created in the directive, and removed at the end, and is purely a temporary visual aid. In addition to position, height + width are also dynamically determined for both the start and final style of the element, using a CSS transition between the states. Each of the styles can have a different transition time + timing function to achieve the effect I'm after. Multiple elements can be moved to / from different positions at the same time, so the JS/CSS must allow that.
sounds like you need more than just angular for complex animations, these use jquery to overwrite angular's $animate for a given class
http://thiswildorchid.com/custom-angularjs-animations-with-jquery-how-to
another example
EDIT:
You should be able to specify any non-dynamic rules and transition using pure css. e.g.
.animate-enter {
-webkit-transition: 1s linear all; /* Chrome */
transition: 1s linear all;
opacity: 0;
}
.animate-enter.animate-enter-active {
opacity: 1;
}
All,
I've got a situation in which I'm using CSS transforms/transitions to animate the horizontal position of a div element. Specifically, I'm using...
// in CSS
myDiv {
transition: transform 0.4s ease-in;
}
// in JavaScript, where "div" contains a reference to the div element
div.style.transform = translate3d(Npx, 0px, 0px);
...and it works well. That is, every time I call that line of JavaScript with a new value for N, the div smoothly animates from its current position to its new position.
However, there are times when I need position the div first WITHOUT a transition, then MOVE it WITH a transition. E.g.,
Have the div JUMP (instantly) to 100px, then transition (over 400ms) to 200px
Later, JUMP the div to 500px (without a transition), then transition it to 600px
In other words, I'd like to be able to move a div, and be able to control whether the new position is applied instantaneously, or with a transition.
Complicating matters, I have event listeners that fire when the transition is complete; these listeners should NOT fire if/when I move the div without a transition. I'm also supporting multiple browsers, so I have to deal with all the vendor prefixes.
In pseudo-code, I guess it would look something like this:
Remove the event listeners for the transitionEnd event
Set the transition property to none
Change the position of the div (e.g., [div].style.transform = translate3d([starting position]px, 0px, 0px))
Add the event listeners for the transitionEnd event
Set the transition property to have a transition (e.g., [div].style.transition:all 0.4s ease-in)
Change the position of the div (e.g., [div].style.transform = translate3d([ending position]px, 0px, 0px))
With all the vendor prefixes, that's too messy and complicated to be the best way to accomplish this. (I'm not even sure if it works...)
So, what's the best way to toggle transitions/transformations on and off?
[UPDATE]
Thanks to a suggestion from Chandranshu, I've tried toggling a class that includes the transitions.
So, my pseudocode looks like this:
Remove the transitions class
Apply the starting position
Restore the transitions class
Apply the ending position
However, it looks like, if I execute all four steps in a single JavaScript function - it seems to ignore steps 1-2, as though it's "netting" the results of all four steps.
Here's a jsfiddle that demonstrates this: http://jsfiddle.net/bUvX3/
Instead - if I execute steps 1 and 2, then execute steps 3 and 4 after a short delay (e.g., by using a setTimeout), it works: http://jsfiddle.net/2mhcv/
So, I guess that's a solution, except that I really don't like having to add an arbitrary delay, especially when so much emphasis is placed on fast, responsive UIs.
Thanks in advance!
I think you have over-complicated this :). Here's how I'd approach this problem:
Add a class to your divs, say movable.
Declare all your transition rules and transitionEnd callbacks for .movable.
Nothing to do if you want to move your div smoothly.
When you need to move your div w/o a transition, remove this class, move your div and add this class back: $('div').removeClass('movable').animate({transform: 'translate3d(...)' }).addClass('movable')
UPDATE:
Finally, I've got what you wanted: http://jsfiddle.net/2mhcv/1/. The only change here is that instead of a delay of 20ms, I'm using a delay of 0! setTimeout() causes a repaint to be triggered and that ensures that the first animation is executed before the next one begins.
UPDATE 2:
This version works without a setTimeout() call: http://jsfiddle.net/2mhcv/2/. Realizing that a repaint is all that is needed, I just added a line there to read a compute CSS property such as display. You could have read any other computed property to get the same effect.
I want to animate between "default" states/positions for a div. For example:
Div absolutely positioned with a class, to be on the left of the screen. Class is removed via JS (or replaced) and position is now relative. The default relative position is actually on the opposite side of the screen. I want to animate this.
Something like a dock, various divs as icons in display-inline, centered horizontally on the dock. If I "delete" one of the icons, the rest will shift a bit to recenter. I want to animate them shifting to fill the gap.
Transition: all does not work (I assume because there was no predefined values for the position) so is this even possible? Are there JS solutions to this?
It's possible exactly the way you described it. Here's a live example of how it's done.
http://jsfiddle.net/nDr4y/3/
You can also remove the transition from css and use jquery to animate the element with pure JS. The syntax looks like this:
// in the object are the css properties you want to animate,
// the second argument is how long you want it to take in ms
$('.el').animate({ left: 100 }, 1000);
You just need to figure out the destination coordinates and set it using jQuery, or whatever framework you use. Other than that, it's totally possible.
http://jsfiddle.net/Kd72u/