skip to Main Content

I have a simple flip card animation where I need to hide the backface layer when not shown.

Problem is, that hide() and show() can only be called at the beginning or ending (via transitionend) of the animation which of course does not look very smooth. Has anybody got an idea how to grab the halftime moment where a change in visibility would not be recognizable?

PS: I know, that in this example hiding would not be necessary because the use of backface-visibility: hidden;, but my original script has a couple of virtual backsides and frontsides. So I need to hide all sides that are currently not active.

$(document).on('click', '.trigger-down', function() {
  $(".card").addClass("flip-down-now");
  $(".front").hide();
  $(".back").show();
});
$(document).on('click', '.trigger-up', function() {
  $(".card").attr('class', 'card').addClass("flip-up-now");
  $(".front").show();
  $(".back").hide();
});
.card-wrapper {
  display: inline-block;
  perspective: 1200px;
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 90vw;
  height: 90vh;
}

.card {
  position: absolute;
  width: 100%;
  height: 100%;
  transition-duration: 0.6s;
  transition-timing-function: ease-in-out;
  transform-style: preserve-3d;
  border: 1px solid white;
  border-radius: 4vw;
}

.content {
  width: 100%;
  height: 100%;
  border-radius: 4vw;
  backface-visibility: hidden;
  position: absolute;
}

.front {
  background-color: red;
  transform: rotateY(0deg);
}

.back {
  background-color: blue;
  transform: rotateX(180deg);
  display: none;
}

.flip-down-now {
  transform: rotateX(180deg);
}

.flip-up-now {
  transform: rotateX(0deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="card-wrapper">
  <div class="card">
    <div class="content front">
      <button class="trigger-down">down</button>
    </div>
    <div class="content back">
      <button class="trigger-up">up</button>
    </div>
  </div>

2

Answers


  1. Chosen as BEST ANSWER

    I came up with a solution now, that is definitely not elegant (and I will therefore not mark it as correct answer) but it prevents me from rewriting the whole code. As I know the animation is timed at 0.6 Seconds I can use jquery delay() and fadeIn() to change at 50%.

    $(document).on('click', '.trigger-down', function() {
      $(".card").attr('class', 'card').addClass("flip-down-now");
      $(".front").delay( 300 ).fadeOut(0);
      $(".back").delay( 300 ).fadeIn(0);
    });
    $(document).on('click', '.trigger-up', function() {
      $(".card").attr('class', 'card').addClass("flip-up-now");
      $(".front").delay( 300 ).fadeIn(0);
      $(".back").delay( 300 ).fadeOut(0);
    });
    .card-wrapper {
      display: inline-block;
      perspective: 1200px;
      position: fixed;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      width: 90vw;
      height: 90vh;
    }
    
    .card {
      position: absolute;
      width: 100%;
      height: 100%;
      transition-duration: 0.6s;
      transition-timing-function: ease-in-out;
      transform-style: preserve-3d;
      border: 1px solid white;
      border-radius: 4vw;
    }
    
    .content {
      width: 100%;
      height: 100%;
      border-radius: 4vw;
      backface-visibility: hidden;
      position: absolute;
    }
    
    .front {
      background-color: red;
      transform: rotateY(0deg);
    }
    
    .back {
      background-color: blue;
      transform: rotateX(180deg);
      display: none;
    }
    
    .flip-down-now {
      transform: rotateX(180deg);
    }
    
    .flip-up-now {
      transform: rotateX(0deg);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <div class="card-wrapper">
      <div class="card">
        <div class="content front">
          <button class="trigger-down">down</button>
        </div>
        <div class="content back">
          <button class="trigger-up">up</button>
        </div>
      </div>


  2. Keyframes allow you to specify a sequence of animation steps, for example, a 90 degree rotation followed by a sudden scaling down to 0, followed by another 90 degree rotation. (The scale to 0 is the "replacement" for the hidden backface visibility.)

    The following snippet styles the front and back faces with animations based on such a keyframe. Whenever the card is flipped, the <div> elements "inserted before themselves" in order to restart their animation. (Perhaps someone knows a more elegant way to achieve this.)

    function flip() {
      document.querySelectorAll("div").forEach(function(div) {
        div.classList.toggle("back");
        div.parentNode.insertBefore(div, div);
      });
    }
    @keyframes flip {
      50% {
        transform: scale(1) rotateY(90deg);
      }
      51% {
        transform: scale(0) rotateY(90deg);
      }
      to {
        transform: scale(0) rotateY(180deg);
      }
    }
    
    body {
      position: relative;
    }
    
    div {
      position: absolute;
      top: 2em;
      transform-style: preserve-3d;
    }
    
    div:not(.back) {
      animation: flip 0.5s reverse forwards;
    }
    
    div.back {
      animation: flip 0.5s forwards;
    }
    <button onclick="flip()">Flip</button>
    <div>Front</div>
    <div class="back">Back</div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search