Johanovski
Johanovski

Reputation: 235

Restart CSS animation on the same element

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:

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

Answers (1)

Michal Brašna
Michal Brašna

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

Related Questions