Reputation: 9261
I'm having some major headache trying to apply CSS3 transitions to a slideshow trough JavaScript.
Basically the JavaScript gets all of the slides in the slideshow and applies CSS classes to the correct elements to give a nice animated effect, if there is no CSS3 transitions support it will just apply the styles without a transition.
Now, my 'little' problem. All works as expected, all slides get the correct styles, the code runs without bugs (so far). But the specified transitions do not work, even though the correct styles where applied. Also, styles and transitions work when I apply them myself trough the inspector.
Since I couldn't find a logical explanation myself I thought someone here could answer it, pretty please?
I've put together a little example of what the code is right now: http://g2f.nl/38rvma Or use JSfiddle (no images): http://jsfiddle.net/5RgGV/1/
Upvotes: 39
Views: 30832
Reputation: 1033
transistor09's answer is correct and should be the accepted. However, instead of relying on an obscure side effect of element.offsetHeight
, I prefer to use window.requestAnimationFrame
to make sure the initial state is fully applied before the target state is set:
// Set initial state
element.style.opacity = '0';
window.requestAnimationFrame(() => {
// Delay the setting of the target state to the next animation frame.
// The initial state has definitely been applied then.
element.style.opacity = '1';
});
JSFiddle sample code:
const one = document.getElementById('one');
const two = document.getElementById('two');
one.style.opacity = '0';
one.style.opacity = '1';
two.style.opacity = '0';
window.requestAnimationFrame(() => {
two.style.opacity = '1';
});
<div id="one" style="background-color: red; transition: all 3s">Transition doesn't work like that</div>
<div id="two" style="background-color: green; transition: all 3s">Works!</div>
https://jsfiddle.net/n6boapg8/
Upvotes: 0
Reputation: 65341
To make transition
work, three things have to happen.
opacity: 0;
transition: opacity 2s;
opacity: 1
If you are assigning 1 and 2 dynamically, like you are in your example, there needs to be a delay before 3 so the browser can process the request. The reason it works when you are debugging it is that you are creating this delay by stepping through it, giving the browser time to process. Give a delay to assigning .target-fadein
:
window.setTimeout(function() {
slides[targetIndex].className += " target-fadein";
}, 100);
Or put .target-fadein-begin
into your HTML directly so it's parsed on load and will be ready for the transition.
Adding transition
to an element is not what triggers the animation, changing the property does.
// Works
document.getElementById('fade1').className += ' fade-in'
// Doesn't work
document.getElementById('fade2').className = 'fadeable'
document.getElementById('fade2').className += ' fade-in'
// Works
document.getElementById('fade3').className = 'fadeable'
window.setTimeout(function() {
document.getElementById('fade3').className += ' fade-in'
}, 50)
.fadeable {
opacity: 0;
}
.fade-in {
opacity: 1;
transition: opacity 2s;
}
<div id="fade1" class="fadeable">fade 1 - works</div>
<div id="fade2">fade 2 - doesn't work</div>
<div id="fade3">fade 3 - works</div>
Upvotes: 65
Reputation: 5138
Trick the layout engine!
function finalizeAndCleanUp (event) {
if (event.propertyName == 'opacity') {
this.style.opacity = '0'
this.removeEventListener('transitionend', finalizeAndCleanUp)
}
}
element.style.transition = 'opacity 1s'
element.style.opacity = '0'
element.addEventListener('transitionend', finalizeAndCleanUp)
// next line's important but there's no need to store the value
element.offsetHeight
element.style.opacity = '1'
As already mentioned, transition
s work by interpolating from state A to state B. If your script makes changes in the same function, layout engine cannot separate where state A ends and B begins. Unless you give it a hint.
Since there is no official way to make the hint, you must rely on side effects of some functions. In this case .offsetHeight
getter which implicitly makes the layout engine to stop, evaluate and calculate all properties that are set, and return a value. Typically, this should be avoided for performance implications, but in our case this is exactly what's needed: state consolidation.
Cleanup code added for completeness.
Upvotes: 17
Reputation: 41
Some people have asked about why there is a delay. The standard wants to allow multiple transitions, known as a style change event, to happen at once (such as an element fading in at the same time it rotates into view). Unfortunately it does not define an explicit way to group which transitions you want to occur at the same time. Instead it lets the browsers arbitrarily choose which transitions occur at the same time by how far apart they are called. Most browsers seem to use their refresh rate to define this time.
Here is the standard if you want more details: http://dev.w3.org/csswg/css-transitions/#starting
Upvotes: 4