htmlcsssasscss-transitionscss-transforms

CSS3 animation is different in Chrome and Safari browser


I am trying to create a 3D hover animation effect for a site and it works just fine in Chrome based browsers, since in the development phase it was written with the help of Chrome's inspect tool, but after trying to test its compatibility in Safari, it creates a hard but still visible after-image effect which I am not sure why it is caused.

.icon {
  width: 140px;
  aspect-ratio: 1/1;
  position: relative;
  display: flex;
  justify-content: center;
  flex-direction: row;
  transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
  transform: scale(1, 1);
  -webkit-transform: scale(1, 1);
  transition: all 0.2s ease-in-out 0s;
  -webkit-transition: all 0.2s ease-in-out 0s;
  top: 140px;
  .img-wrapper {
    width: 98px;
    aspect-ratio: 1/1;
    position: relative;
    top: -10px;
    &:after {
      content: '';
      display: flex;
      width: 15px;
      height: 115px;
      background-color: hsl(12, 77%, 35%);
      position: absolute;
      left: 80%;
      top: 0%;
      transform-style: preserve-3d;
      transform: skewY(-30deg) rotateZ(5deg) translateX(11px) translateY(-6px);
      -webkit-transform-style: preserve-3d;
      -webkit-transform: skewY(-30deg) rotateZ(5deg) translateX(11px) translateY(-6px);
      z-index: -1;
      transition: all ease-in-out 0.2s 0s;
      -webkit-transition: all 0.2s ease-in-out 0.01s;
      clip-path: polygon(0 10px, 100% 20px, 90% 95%, 3px 99%)
    }
    &:before {
      content: '';
      display: flex;
      width: 115px;
      height: 14px;
      background-color: hsl(12, 77%, 35%);
      transform: skewX(-20deg) rotateZ(10deg) translateY(-9px) translateX(-6px);
      transform-style: preserve-3d;
      -webkit-transform: skewX(-20deg) rotateZ(10deg) translateY(-9px) translateX(-6px);
      -webkit-transform-style: preserve-3d;
      clip-path: polygon(11px 0, 96% 2px, 100% 100%, 0 100%);
      -webkit-clip-path: polygon(11px 0, 96% 2px, 100% 100%, 0 100%);
      transition: all ease-in-out 0.2s 0s;
      -webkit-transition: all 0.2s ease-in-out 0s;
      position: absolute;
    }
    .logo-icon {
      width: 100%;
      height: 80%;
      background-color: orange;
      -webkit-transform-style: preserve-3d;
      transform-style: preserve-3d;
      transform: skewY(10deg);
      -webkit-transform: skewY(10deg);
      transition: all ease-in-out 0.2s 0s;
      -webkit-transition: all 0.2s ease-in-out 0s;
      clip-path: polygon(2px 0, calc(100% - 2px) 0px, 90% 89%, 50% 99%, 0 89%);
      position: relative;
    }
  }
  &:hover {
    transform: scale(1.2, 1.2);
    -webkit-transform: scale(1.2, 1.2);
    .img-wrapper {
      &:after {
        display: flex;
        width: 0px;
        height: 70%;
        left: 80%;
        top: 0%;
        transform: skewY(-5deg) rotateZ(5deg) translateX(30px) translateY(-20px);
        -webkit-transform: skewY(-5deg) rotateZ(5deg) translateX(30px) translateY(-20px);
        clip-path: polygon(0 8px, 99% 2px, 100% 98%, 0 99.5%);
      }
      &:before {
        width: 100%;
        height: 0px;
        transform: translateY(-20px) translateX(20px);
        -webkit-transform: translateY(-20px) translateX(20px);
        clip-path: polygon(0 0, 98% 1px, 98% 100%, 2px 100%);
        -webkit-clip-path: polygon(0 0, 98% 1px, 98% 100%, 2px 100%);
      }
      .logo-icon {
        transform: skewY(0) translateY(-20px) translateX(20px);
        -webkit-transform: skewY(0) translateY(-20px) translateX(20px);
      }
    }
  }
}

```
<div class="icon">
  <div class="img-wrapper">
    <div class="logo-icon"></div>
  </div>
</div>

The codepen for the animation is https://codepen.io/Giannis-Nikolaou/pen/PogwLNa

I have tried adding the -webkit prefix on some properties I hypothesized were the cause of the issue but the problem isn't fixed. I also thought it might be a weird delay issue that Safari has with the :before and :after pseudo-elements, so I've added my own transition-delay, but that doesn't fix it since it causes a clear to see delay.
I have also tried adding the -webkit prefix on the clip-path property but this also does not fix it. I've ran out of ideas to test and see what the problem is.


Solution

  • For anybody who comes across in the future searching for a solution, there is no real solution besides adding a delay equal to the time it takes to render a single frame (in my situation, it was 60 fps, so I added a 17ms delay). It seems that safari has this beharior where either

    1. it prioritizes the element highest on the z-index, and on the next rendered frame, starts to animate the elements on the lower z-index, or
    2. it prioritizes the main element over the pseudo :after and :before element's animations

    A viable solution I found was instead of trying to simulate a 3D object with some smart skew and rotate magic, try and make a true 3D object. To do this, you need to also use the translateZ() and rotateZ() properties, and figure out how to make a 3D object.

    Some useful links which can help speed up and understand what is going on:

    Learn what properties to use, how and when

    A useful site to make quick, but very limited shapes. The site includes a full 3D GUI to make it very easy to make these shapes

    When making these objects, MAKE SURE that the surface that will be exposed to the user will NOT be flat on itself. Safari DOES NOT behave well with that behavior. Check out the codepen to understand better what I mean (force hover on #tridiv)

    The only way around this is to either make the 3D object in such a way that the plane drawn on is not flat to the user, or add a 1deg in one direction to force Safari to paint it

    <div class="container">
      <div id="tridiv">
        <div class="scene">
          <div class="shape cylinder-1 cyl-1">
            <div class="face bm"></div>
            <div class="face tp"></div>
            <div class="face side s0"></div>
            <div class="face side s1"></div>
            <div class="face side s2"></div>
            <div class="face side s3"></div>
            <div class="face side s4"></div>
            <div class="face side s5"></div>
            <div class="face side s6"></div>
            <div class="face side s7"></div>
            <div class="face side s8"></div>
            <div class="face side s9"></div>
            <div class="face side s10"></div>
            <div class="face side s11"></div>
            <div class="face side s12"></div>
            <div class="face side s13"></div>
            <div class="face side s14"></div>
            <div class="face side s15"></div>
            <div class="face side s16"></div>
            <div class="face side s17"></div>
            <div class="face side s18"></div>
          </div>
        </div>
      </div>
    </div>
    
    .container {
      width: 500px;
      height: 500px;
      overflow: visible;
      position: relative;
      top: 100px;
      left: 100px;
    }
    
    #tridiv {
      perspective: 800px;
      width: 100%;
      height: 100%;
      background: transparent;
      font-size: 125%;
    
      &:hover {
        .cyl-1 {
          transform: translate3D(150px, 150px, 0) rotateX(90deg) rotateY(0deg) rotateZ(0deg) scale3D(1.3, 1.3, 1.3);
          -webkit-transform: translate3D(150px, 150px, 0) rotateX(90deg) rotateY(0deg) rotateZ(0deg) scale3D(1.3, 1.3, 1.3);
        }
      }
    }
    
    .scene,
    .shape,
    .face,
    .face-wrapper,
    .cr {
      position: absolute;
      transform-style: preserve-3d;
    }
    
    .scene {
      width: 100%;
      height: 100%;
    }
    
    .shape {
      width: 0;
      height: 0;
      transform-origin: 50%;
    }
    
    .face,
    .face-wrapper {
      transform-origin: 0 0;
      backface-visibility: hidden;
    }
    
    .face {
      background-size: 100% 100% !important;
      background-position: center;
    }
    
    .face-wrapper .face {
      left: 100%;
      width: 100%;
      height: 100%
    }
    
    .photon-shader {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%
    }
    
    .side {
      left: 50%;
    }
    
    .cr,
    .cr .side {
      height: 100%;
    }
    
    [class*="cylinder"] .tp {
      transform: rotateX(90deg) translateY(-50%);
    }
    
    [class*="cylinder"] .bm {
      transform: rotateX(-90deg) translateY(-50%);
    }
    
    [class*="cylinder"] .tp,
    [class*="cylinder"] .bm,
    [class*="cylinder"] .tp .photon-shader,
    [class*="cylinder"] .bm .photon-shader {
      border-radius: 50%;
    }
    
    [class*="cylinder"] .bm {
      top: 100%;
    }
    
    /* .cyl-1 styles */
    .cyl-1 {
      transition: all 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95) 0s;
      -webkit-transition: all 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95) 0s;
      top: 45px;
      transform: translate3D(0, 0, 0) rotateX(60deg) rotateY(0deg) rotateZ(30deg) scale3D(1, 1, 1);
      -webkit-transform: translate3D(0, 0, 0) rotateX(60deg) rotateY(0deg) rotateZ(30deg) scale3D(1, 1, 1);
      opacity: 1;
      width: 6em;
      height: 1.5em;
    }
    
    .cyl-1 .tp,
    .cyl-1 .bm {
      width: 6em;
      height: 6em;
    }
    
    .cyl-1 .side {
      width: 1.0262229172794184em;
      height: 1.5em;
    }
    
    .cyl-1 .s0 {
      transform: rotateY(9.473684210526315deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s1 {
      transform: rotateY(28.421052631578945deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s2 {
      transform: rotateY(47.368421052631575deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s3 {
      transform: rotateY(66.3157894736842deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s4 {
      transform: rotateY(85.26315789473684deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s5 {
      transform: rotateY(104.21052631578947deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s6 {
      transform: rotateY(123.1578947368421deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s7 {
      transform: rotateY(142.10526315789474deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s8 {
      transform: rotateY(161.05263157894734deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s9 {
      transform: rotateY(180deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s10 {
      transform: rotateY(198.9473684210526deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s11 {
      transform: rotateY(217.89473684210526deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s12 {
      transform: rotateY(236.84210526315786deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s13 {
      transform: rotateY(255.78947368421052deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s14 {
      transform: rotateY(274.7368421052631deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s15 {
      transform: rotateY(293.6842105263158deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s16 {
      transform: rotateY(312.6315789473684deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s17 {
      transform: rotateY(331.578947368421deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .s18 {
      transform: rotateY(350.52631578947364deg) translate3D(-50%, 0, 2.975em);
    }
    
    .cyl-1 .face,
    .cyl-1 .side {
      background-color: #FFFFFF;
    }
    
    .cyl-1 .tp {
      background-color: #ffffff;
    }
    
    .cyl-1 .bm {
      background: url(https://john-nik.com/icons/sass.svg) #ffffff;
    }
    
    .cyl-1 .side {
      background-color: #c63980;
      border-radius: 3px 3px 0px 0px;
    }