Solution 1 :

I fixed it. Belive it or not, the opacity in the keyframes was causing this issue.

Problem :

I’m trying to make a card flip effect with CSS keyframes but for some reason the transform: rotateY() doesn’t rotate correctly. When it’s rotated by the @keyframes, after it passes rotateY(90deg) the front side isn’t shown, instead it shows the flipped back side. When flipping the card “manually” (in the inspect element), it works fine.

The card by default is showing the front side. But the animation starts with the back side and then it flips. The animation is keeping its ending state.

As far as I could see, for some reason, the front side is always behind the back side. (If you opacity the back side, the front side can be seen.)

I’ve tried:

  • Adding perspective: 1000px; to the parent element
    (.cards).
  • Using positive rotateY() instead of negative.
  • Adding z-index to .front.
  • Adding transform: rotateY(0deg); to .front, so it knows that that’s the front side.
  • Adding backface-visibility: hidden; to both, .front and .back.
  • Adding positon: relative; on one (and both), .front and .back.

But none of these fixed it.

Here you can see a video of the issue:

When @keyframes does it:
https://gyazo.com/7cd4e75c85ed5eba6b1e717a37ce95c2

Manually (When I do it with the Inspect Element):
https://gyazo.com/42e63ff2e4fe0149b917e895a633dd88

Here’s the code:

HTML:

<div class="cards">
    <div class="card">
        <div class="front">
            <div class="card-number">5</div>
            <img src="https://bounty-assets.fra1.cdn.digitaloceanspaces.com/cards/clubs.png" alt="">
        </div>
        <div class="back">
            <img src="https://bounty-assets.fra1.cdn.digitaloceanspaces.com/cards/back.png" alt="">
        </div>
    </div>
</div>

CSS:

.cards {
    width: fit-content;
    display: flex;
    position: absolute;
    top: 25px;
    left: 0;
    right: 0;
    margin: 0 auto;
    perspective: 1000px;
}

.cards .card {
    min-width: auto;
    width: 208px;
    background: transparent;
    border: 0;
    border-radius: 0;
    display: flex;
    position: relative;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;
    margin-left: -30px;
    transform: rotateY(0deg);
    animation: flipcard 1s linear 0s 1 forwards;
}

.cards .card:first-child {
    margin-left: 0;
}

.cards .card .front {
    position: absolute;
    backface-visibility: hidden;
    transform: rotateY(0deg);
}

.cards .card .front .card-number {
    position: absolute;
    top: 30px;
    left: 35px;
    font-size: 32px;
    font-weight: 600;
}

.cards .card .back {
    position: absolute;
    transform: rotateY(180deg);
}

@keyframes flipcard {
    0% {
        opacity: 0;
        transform: translate(30vw, 30vh) rotateY(-180deg);
    }
    30% {
        opacity: 1;
        transform: translate(0, 0) rotateY(-180deg);
    }
    50% {
        opacity: 1;
        transform: translate(0, 0) rotateY(-180deg);
    }
    60% {
        transform: translate(-20px, 0) rotateY(-180deg);
    }
    80% {
        transform: translate(-30px, 0) rotateY(-90deg) scale(1.08);
    }
    90% {
        transform: translate(0, 0) rotateY(0deg) scale(1.08);
    }
    100% {
        transform: translate(0, 0) rotateY(0deg) scale(1);
    }
}

By