Search code examples
htmlcsscss-animationscss-transitions

Flip animation using chrome's View Transition API not animating background color smoothly


I have a simple div that has a background colour and text. Upon a state change, I update this element in the DOM to have a different background colour and text (done via HTMX). I want to use Chrome's new View Transition API so that transition between these two divs has a vertical flip effect.

I have this almost working using the following code:

@keyframes flip-in {
  0% {
    transform: rotateX(-180deg);
  }
  100% {
    transform: rotateX(0deg);
  }
}

@keyframes flip-out {
  0% {
    transform: rotateX(0deg);
  }
  100% {
    transform: rotateX(180deg);
  }
}

::view-transition-old(flip-me) {
  animation: flip-out 0.3s;
}
::view-transition-new(flip-me) {
  animation: flip-in 0.3s;
}

.flip-container {
  position: relative;
  width: 300px;
  height: 3rem;
}

.flip-me {
  view-transition-name: flip-me;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  backface-visibility: hidden;
  transform-style: preserve-3d;
  transition: transform 1s cubic-bezier(0.4, 0, 0.2, 1);
}
<div class="flip-container">
  <!-- Starting Div -->
  <div class="flip-me old-color">
    Old Text
  </div>
  <!--This div replaces the one above in the transition --> 
  <div class="flip-me new-color">
    New Text
  </div>
</div>

The issue is that during the animation (for both the flip out and flip in) the background colour of the div goes really bright.

How can I maintain the background colour of the div whilst it's animating?


Solution

  • In the end this was a simple as including opacity into the animation:

    @keyframes flip-in {
      0%{
        opacity: 0;
        transform: rotateX(-180deg);  
      }
      100%{
        transform: rotateX(0deg);
        opacity: 1;
      }
    }
    
    @keyframes flip-out {
      0%{
        transform: rotateX(0deg);
        opacity: 1;
      }
      99%{
        transform: rotateX(180deg);
      }
      100% {
        transform: rotateX(180deg);
        opacity: 0;
      }
    }