Search code examples
jqueryimageanimationhoverfade

jQuery opacity/fade animation only works once


I'm building a personal website. I researched and started doing it with CSS keyframes, but found a solution using jQuery + CSS keyframes myself.

My issue now (which I assume have a simple answer that I cannot see because I've been staring at my monitor too long) is that my hover animation only works once. That is, upon mouse:hover, my image 1 fades into images 2 (image1 disappears) and then image2 fades into images3 (image2 disappears), so its' like a cascade. However, this is only works once, if I hover again, it won't work.

So to clarify again, I want this animation to cascade-Fade from image1, to image2, to image3, and then reverse out (image3, to image2, to image1, i.e. like some morphing effect) EVERY-TIME the user mouse:hovers over the original image.

I'm assuming the answer might do with the class "animated" being added but not removed? I actually don't know jQuery but have been teaching myself impromptu and figured if someone else saw my code, they could spot the syntax/bug.

ALSO

Is this the best method to fade/transistion images to-one-another? I want a SMOOTH fade, like a "morphing" - is this best done the way I'm doing it? (jquery+keyframes), should I add more keyframes for a smoother effect?

Here is the jsfiddle: http://jsfiddle.net/1xrbxdnk/2/

And the source code: HTML:

<div class="box">
  <img src="http://alpizano.com/assets/images/venom1.png" width="50%" class="top">
  <img src="http://alpizano.com/assets/images/venom2.png" width="50%" class="middle">
  <img src="http://alpizano.com/assets/images/venom3.png" width="50%" class="bottom">
</div>

JavsScript/jQuery

$("img.top").hover(function() {
  $(this).addClass("animated");
  $("img.middle").addClass("animated2");
  $("img.bottom").addClass("animated3");
})

$("img.bottom").bind("webkitAnimationEnd mozAnimationEnd animationEnd", function() {
    $(this).addClass("animated6")
  $("img.middle").addClass("animated5")
  $("img.top").addClass("animated4")
})

CSS

.box {
  position: relative;
}

img {
  position: absolute;
}

.middle {
  display: none;
}

.bottom {
  display: none;
}

@keyframes anim1 {
  0% {
    opacity: 1;
  }
  70% {
    opacity: 0;
  }
}

@keyframes anim2 {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

@keyframes anim3 {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@keyframes anim6 {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}

@keyframes anim5 {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

@keyframes anim4 {
  0% {
    opacity: 0;
  }
  70% {
    opacity: 1;
  }
}

.top.animated {
  animation: anim1 3s ease-in-out;
  opacity: 0;
}

.middle.animated2 {
  animation: anim2 3s ease-in-out;
  display: block;
  opacity: 0;
}

.bottom.animated3 {
  animation: anim3 3s ease-in-out;
  display: block;
  opacity: 1;
}

.bottom.animated6 {
  animation: anim6 3s ease-in-out;

  opacity: 0;
}

.middle.animated5 {
  animation: anim5 3s ease-in-out;

  opacity: 0;
}

.top.animated4 {
  animation: anim4 3s ease-in-out;
  opacity: 1;
}

Solution

  • You need to remove the animation classes once the animation is done. You already have an event listener for animation end to add the reverse animations. You could do the following:

    $("img.bottom").bind("webkitAnimationEnd mozAnimationEnd animationEnd",         
    function() {
      if (!$(this).hasClass('animated6')) {
        $(this).addClass("animated6");
        $("img.middle").addClass("animated5");
        $("img.top").addClass("animated4");
      }
      else {
        $(this).removeClass("animated6 animated3");
        $("img.middle").removeClass("animated5 animated2");
        $("img.top").removeClass("animated4 animated");
      }
    });
    

    Here's your fiddle updated:

    http://jsfiddle.net/1xrbxdnk/3/

    Here's a snippet:

    $("img.top").hover(function() {
      $(this).addClass("animated");
      $("img.middle").addClass("animated2");
      $("img.bottom").addClass("animated3");
    })
    
    $("img.bottom").bind("webkitAnimationEnd mozAnimationEnd animationEnd", function() {
      if (!$(this).hasClass('animated6')) {
      	$(this).addClass("animated6");
        $("img.middle").addClass("animated5");
        $("img.top").addClass("animated4");
      }
      else {
        $(this).removeClass("animated6 animated3");
        $("img.middle").removeClass("animated5 animated2");
        $("img.top").removeClass("animated4 animated");
      }
    })
    .box {
      position: relative;
    }
    
    img {
      position: absolute;
    }
    
    .middle {
      display: none;
    }
    
    .bottom {
      display: none;
    }
    
    @keyframes anim1 {
      0% {
        opacity: 1;
      }
      70% {
        opacity: 0;
      }
    }
    
    @keyframes anim2 {
      0% {
        opacity: 0;
      }
      50% {
        opacity: 1;
      }
    }
    
    @keyframes anim3 {
      0% {
        opacity: 0;
      }
      50% {
        opacity: 0;
      }
      100% {
        opacity: 1;
      }
    }
    
    @keyframes anim6 {
      0% {
        opacity: 1;
      }
      50% {
        opacity: 0;
      }
      100% {
        opacity: 0;
      }
    }
    
    @keyframes anim5 {
      0% {
        opacity: 0;
      }
      50% {
        opacity: 1;
      }
    }
    
    @keyframes anim4 {
      0% {
        opacity: 0;
      }
      70% {
        opacity: 1;
      }
    }
    
    .top.animated {
      animation: anim1 3s ease-in-out;
      opacity: 0;
    }
    
    .middle.animated2 {
      animation: anim2 3s ease-in-out;
      display: block;
      opacity: 0;
    }
    
    .bottom.animated3 {
      animation: anim3 3s ease-in-out;
      display: block;
      opacity: 1;
    }
    
    .bottom.animated6 {
      animation: anim6 3s ease-in-out;
    
      opacity: 0;
    }
    
    .middle.animated5 {
      animation: anim5 3s ease-in-out;
    
      opacity: 0;
    }
    
    .top.animated4 {
      animation: anim4 3s ease-in-out;
      opacity: 1;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="box">
      <img src="http://alpizano.com/assets/images/venom1.png" width="50%" class="top">
      <img src="http://alpizano.com/assets/images/venom2.png" width="50%" class="middle">
      <img src="http://alpizano.com/assets/images/venom3.png" width="50%" class="bottom">
    </div>