css transition only works within setInterval? why? - javascript

At a certain point in a script the following occurs
CSS-CODE
.tt{ opacity: 0; transition: all 1s;}
JS-CODE (THIS DOES NOT TRANSITION)
this.element.insertAdjacentHTML('beforeend',`<div class="tt">this is a message</div>`);
this.tooltip = this.element.querySelector('.tt');
this.tooltip.style.opacity = 1; => THIS DOES NOT TRANSITION
BUT WHEN I CHANGE MY CODE IN (THIS DOES TRANSITION)
this.element.insertAdjacentHTML('beforeend',`<div class="tt">${this.element.dataset.tooltip}</div>`);
this.tooltip = this.element.querySelector('.tt');
setTimeout(function(){
this.tooltip.style.opacity = 1 => THIS DOES TRANSITION
}.bind(this),0);
WHY? (even if the setTimeoutdelay is set to 0)

Transitions occur between one rendered state and another.
Your first code block changes the opacity property before the element has been rendered at opacity 0.
Adding timeout introduces a delay in which the element can be rendered at opacity 0.
even if the setTimeoutdelay is set to 0)
setTimeout has a minimum delay on it, and even if it didn't, the queue of jobs would probably have repaint above the next timed action.

Related

How to sync Javascript with CSS transitions to create a "onComplete" callback, when the transition is overriden by another?

I am trying to sync Javascript with CSS transitions, and I have done it right.
I basically created a callback that fires after X seconds, and everything works fine IF the transition completes normally. However, when the transition is interrupted BEFORE completion by another transition, like when you leave the mouse from a div when you're altering its width (for example, the div is 100px wide, mouseover -> 300px mouseout -> 100px. You mouse-leave the div before it reaches 300px, the transition DO NOT calculate the full-duration!), I don't know how to calculate the new duration.
I have tried the trasitionend event but is currently an instable solution to me.
CSS
div {
width: 100px;height: 100px;background: red;
transition: width 2s;
}
div:hover {
width: 300px;
}
HTML
<div id="mydiv"></div>
JS
let mydiv = document.getElementById('mydiv')
let i = 0;
var callback = function() {
i++;
mydiv.innerHTML = 'done ' + i;
}
mydiv.addEventListener('mouseover', function() {
setTimeout(callback, 2000+10);
});
mydiv.addEventListener('mouseout', function() {
setTimeout(callback, 2000+10);
});
As you can see, the callback is broken when you do not wait for the transition to fully complete, of course.
Is there a method to calculate the "cut" duration from the previous start point, in order to set a proper duration for the timeout, instead of using the "static" css duration?
Thank you in advance.

When does CSS transform actually get set?

I am making a simple slider using CSS transform.
It works like
Translate next slide to 100%
Add transitions to current and next
Translate next to 0, current slide to -100%
Remove transitions.
The problem is that next slide never gets translated. It seems to work fine in Chrome but not Firefox. My question is, how long it takes for browsers to really set the transform?
var curSlide = slides[index].style;
var nextSlide = slides[index + 1].style;
nextSlide['transform'] = 'translateX(100%)'; // never occurs
//Giv it some time ??? How long ???
setTimeout(function(){
nextSlide['transition'] = 'transform 0.2s';
curSlide['transition'] = 'transform 0.2s';
nextSlide['transform'] = 'translateX(0)';
curSlide['transform'] = 'translateX(-100%)';
},0);// if timeout is set to 100ms it works fine
Solution was to force a reflow before next translation.
console.log(elementTranslated.offsetHeight);
Thanks to this question Force browser to trigger reflow while changing CSS

Robust way to event handle after the *last* CSS3 transition?

Say I have a CSS class that transitions in several settings, with different timings to boot:
.hidden {
opacity:0;
height:0px;
transition:opacity 1s ease;
transition:height 2s ease;
}
I want to handle some logic after ALL the transitions are done. I know there's a transitionend event for that:
$('#content').on('transitionend', function(e) {
mandatoryLogic()
})
$('#content').addClass('hidden');
But, how do I ensure this event handle happens once and only once, at the end of the last transition (after the 2s height transition in my case)?
I've seen a few examples that involve checking for the type of transitionend, but this closely couples the JS to a particular CSS definition. So far I'm unable to come up with a JS solution that would survive say:
opacity changed to 3s, now the longest.
new width transition to 0px over 4s introduced
extreme case, all transitions removed (so the effects are instant)
I'm not entirely sure what you're asking, but if you want to make sure it only happens once, then use a variable set to false initially, and once the transition takes place it gets set to true. For example:
var transition = false ;
if( !transition ){
// do what you need to do
transition = true ;
}
If you want to make sure it happens once all transitions are complete, then check for the values of #content or .hidden. Whichever you prefer.
var height = $(element).height() ;
var opacity = $(element).css('opacity') ;
var transition = false ;
if( !transition && opacity = 'wanted value' && height = 'wanted value' ){
// do what you need to do
transition = true ;
}
This way, with var transition being set to true it won't happen again.

For JavaScript or jQuery, how to make transitionend event not fire?

In the link:
https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions
it is said that:
Note: The transitionend event doesn't fire if the transition is aborted because the animating property's value is changed before the transition is completed.
So I went ahead and tried it on http://jsfiddle.net/HA8s2/32/ and http://jsfiddle.net/HA8s2/33/ using Chrome and Firefox.
example: (click on either the left or right box in jsfiddle)
$(".foo").click(function(evt) {
$(".foo").addClass("hide");
setTimeout(function() {
$(".foo").eq(0).removeClass("hide");
}, 3000);
});
$(".foo").on("transitionend", function(evt) {
console.log("wow! transitionend fired for", evt.target, "at time =", (new Date()).getTime() / 1000);
});
this is with a CSS transition duration for 6 seconds:
transition-duration: 6s;
But both kept the animation. The left box actually "animate to a new value in the middle of the original animation", so it took 9 seconds for the left to finish, while the right box took 6 seconds to finish.
In addition, Firefox only have the two events in http://jsfiddle.net/HA8s2/32/ separated by 2 seconds, instead of 3 seconds.
The question is: how do I make the transitionend stop as described in the docs in mozilla.org? (and not by any other brute force method).
(in other words, I want to find out all the situations that the transitionend will not fire and test it out).
Update: I was able to abort the animation if I add display: none to the box on the left, as on http://jsfiddle.net/HA8s2/34/ and won't be able to abort it if it is visibility: hidden as in http://jsfiddle.net/HA8s2/35/ but these do not really "change" the property's value as the docs says -- it is to add or change another property value.
Couldn't you give it a new class that overrides the transition property, removing it?
Your current code is like:
.myelem { transition: 0.5s all; }
You would add this code:
.alsothis { transition: none; }
When you apply the alsothis class to your element, the new transition property value will override the other one, removing the animation effect.

Animating a div disappearance, how to smooth that?

I've been trying to animate a Dashboard Widget's div disappearance, but it just brutally goes "poof" (as in, disappears as expected, only instantly).
function removeElement(elementId)
{
duration = 9000; // The length of the animation
interval = 13; // How often the animation should change
start = 1.0; // The starting value
finish = 0.0; // The finishing value
handler = function(animation, current, start, finish) {
// Called every interval; provides a current value between start and finish
document.getElementById(elementId).style.opacity = current;
};
new AppleAnimator(duration, interval, start, finish, handler).start();
interval = 1;
start= "visible";
finish = "hidden";
duration = 9001;
handler = function(animation, current, start, finish) {
document.getElementById(elementId).style.visibility="hidden";
};
new AppleAnimator(duration, interval, start, finish, handler).start();
}
I expected this to "disappear" the div a millisecond after its opacity reaches zero, but for a not so obvious reason (to me), it just disappears immediately. If I comment out the second animation code, the div fades out (but it's still active, which I don't want).
All solutions I've yet seen rely on using JQuery and wait for the event at the end of the animation, is there another way to do that, other than JQuery?
If you are looking for a pure javascript solution it probably needs a good understanding of how javascript event work and basically about javascript language. As reference you should check this question on CodeReview
But as I think the best solution for you and not to rely on jQuery is to checkout CSS3 animations. Even if they are not supported by all browsers you could use Modernizer to fill polyfills for animations.
My favorite CSS3 Animation library is Animate.css. It's pretty neat and gives you a variety of demos in the page.
You'll first have to choose an animation and add it to your css stylesheets. Then have another custom class that contain everything about the animation.
.disappear{
-webkit-animation-duration: 3s;
-webkit-animation-delay: 2s;
-webkit-animation-iteration-count: infinite;
}
Then you could use javascript events to toggle in classes to your Elements. Below is how you add a class to an element.
var animationObject = document.getElementById("poof");
animationObject.className = animationObject.className + " disappear";
If you need more help regarding javascript of how this should be done check out this answer.
Hope this helps...
I found it: AppleAnimator possesses animator.oncomplete: A handler called when the timer is complete.
In my case:
var anim = new AppleAnimator(duration, interval, start, finish, handler);
anim.oncomplete= function(){
document.getElementById(elementId).style.visibility="hidden";
};
anim.start();
The Apple documentation actually calls "Callback" the animation code itself, and "handler" the callback, which makes it a bit hard to realize at first.
Thanks frenchie though, the "YourCallbackFunction" made me realize I was missing something related to callbacks :D

Categories

Resources