Reputation: 235
I'm just getting started with CSS animations controlled via Javascript, and I'm stuck with a problem that I'm sure it's quite simple...
What am I trying to achieve?
I want to have a kind of image zone where some images are displayed with an increasing opacity effect: I want each new image to appear upon the other when the user clicks on the image.
How am I trying to achieve it?
I have a "div" which contains two "img" tags, and I'm simply trying to just animate the upper "img" and then swap the image "src" when the new image has to be shown. Let me explain it:
"img1" is the image at the bottom, which is showing "My first photo".
"img2" is the image at the top, which starts with an opacity of 0.
When the user clicks the image, "My second photo" is associated with the "img2", and "img2" starts and animation to fade in.
When the user touches again, "img1" changes its "src" to show "My second photo", "img2" changes its alpha to 0, changes its source to "My third photo" and starts the fade in animation again.
And so on, making the effect that the new image is always appearing upon the current one.
The bizarre part: the code
As I'm still quite green on CSS animations and Javascript, I'm trying to do it as follows:
index.html:
<div style="position:absolute; top:50%; left:50%; margin-left:-114px; margin-top:-203px;" onClick="canviaImatge();">
<img id="img_1" class="pantalla" src="" style="position:absolute;" />
<img id="img_2" class="pantalla" src="" style="position:relative; left:50px" />
</div>
<script>
document.getElementById("img_1").src = arrImatges[0];
document.getElementById("img_2").src = arrImatges[1];
document.getElementById("img_2").style.opacity = 0;
</script>
index.html (Javascript)
function canviaImatge()
{
document.getElementById("img_2").style.opacity = 0;
document.getElementById("img_2").classList.remove('horizTranslateApareix');
if(currentPantalla == 1)
{
document.getElementById("img_1").src = arrImatges[0];
document.getElementById("img_2").src = arrImatges[1];
}else{
document.getElementById("img_1").src = arrImatges[1];
document.getElementById("img_2").src = arrImatges[0];
}
document.getElementById("img_2").classList.add('horizTranslateApareix');
}
style.css
.pantalla.horizTranslateApareix {
-webkit-transition: 1s;
-moz-transition: 1s;
-ms-transition: 1s;
-o-transition: 1s;
transition: 1s;
opacity: 1 !important;
}
I know I'm doing it the dirty way, but it's like I'm just there and it seems that I'm just missing a line, a tag or something... Any clue about it?
Thanks in advance for your time and effort! :)
Upvotes: 1
Views: 3776
Reputation: 2323
When you bind event handler on div as well as on images inside the div, it will be called twice as there is no e.preventBubble()
in event handler. You can avoid this by using it only on the div.
Second issue is that after first click inside the div, the transition is in final state and you don't move it to initial state. I would achieve required behavior by using 2 classes. One for transition and one for initial state, final state is implicit here, opacity:1
is default value.
.pantalla.invisible {
opacity: 0;
}
.pantalla.horizTranslateApareix {
-webkit-transition: 1s;
-moz-transition: 1s;
-ms-transition: 1s;
-o-transition: 1s;
transition: 1s;
}
Main part is in JS. We start by removing the transition, otherwise it would took 1s to hide the image as well. Then we hide the image and return the transition, do image swapping and finally show the image again, starting the transition.
function canviaImatge()
{
img2.classList.remove('horizTranslateApareix');
img2.classList.add('invisible');
img2.offsetHeight; // <-- force repaint, otherwise browser optimize and nothing changes
img2.classList.add('horizTranslateApareix');
// image swapping
img2.classList.remove('invisible');
}
This would be the ideal case, but browsers optimize, so we can't use it as simply as that. Browsers do as much as possible without repainting the page, so they merge several opearions to one and we loose our functionality. That's where magic comes in place. We enforce repaint asking for img2.offsetHeight
, which has to recalculate positions and repaint the relevant part of page (possibly whole page). Other ways to achieve it, is to move code to setTimeout
function, which can't be optimized either.
setTimeout(function() {
img2.classList.add('horizTranslateApareix');
img2.classList.remove('invisible');
}, 1)
Demo at http://jsfiddle.net/Gobie/e4m3R/2/
Upvotes: 3