csssafaricss-animationscss-transformsmobile-webkit

Safari animation (keyframes and transform) set wrong positions


I have a weird issue only on Safari (strange? LOL). Doesn't matter if you are on iPhone, iPad or Desktop Mac; Safari makes a wrong calculation positioning a logo, using animation keyframes and transform.

The issue is that logo needs to move to his room, but on safari the logo goes too to the left, and when the keyframes reach 100% the logo fits on his room perfectly.

You can see the weird effect on: https://amonarraiz.com (visit on Safari is different than visit on another browser, the code is the same).

Here is my code:

.intro-wrapper {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}
.intro-logo {
  background: url(https://amonarraiz.com/css/img/slider/2.png) center center no-repeat;
  background-size: cover;
  width: 50rem;
  height: 41rem;
  position: absolute;
  left: 50%;
  top: 50%;
  -ms-transform: translate(-86%, -52%);
  -webkit-transform: translate(-86%, -52%);
  transform: translate(-86%, -52%);
  opacity: 0;
  cursor: pointer;
}

.intro-in {
  -moz-animation-duration: 3.75s;
  -webkit-animation-duration: 3.75s;
  animation-duration: 3.75s;
  -moz-animation-name: intro-in;
  -webkit-animation-name: intro-in;
  animation-name: intro-in;
  -moz-animation-iteration-count: 1;
  -webkit-animation-iteration-count: 1;
  animation-iteration-count: 1;
  -moz-animation-fill-mode: forwards;
  -webkit-animation-fill-mode: forwards;
  animation-fill-mode: forwards;
  -webkit-animation-timing-function: ease-in-out;
  -moz-animation-timing-function: ease-in-out;
  animation-timing-function: ease-in-out;
}
@-moz-keyframes intro-in {
  0% {
    opacity: 0.6;
    width: 50rem;
    height: 41rem;
    -ms-transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
  }
  30% {
    opacity: 1;
    width: 50rem;
    height: 41rem;
    -ms-transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
  }

  100% {
    opacity: 1;
    width: 25.6rem;
    height: 19.5rem;
    -ms-transform: translate(-106%, -46%);
    -webkit-transform: translate(-106%, -46%);
    transform: translate(-106%, -46%);
  }
}

@-webkit-keyframes intro-in {
  0% {
    opacity: 0.6;
    width: 50rem;
    height: 41rem;
    -ms-transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
  }
  30% {
    opacity: 1;
    width: 50rem;
    height: 41rem;
    -ms-transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
  }

  100% {
    opacity: 1;
    width: 25.6rem;
    height: 19.5rem;
    -ms-transform: translate(-106%, -46%);
    -webkit-transform: translate(-106%, -46%);
    transform: translate(-106%, -46%);
  }
}

@keyframes intro-in {
  0% {
    opacity: 0.6;
    width: 50rem;
    height: 41rem;
    -ms-transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
  }
  30% {
    opacity: 1;
    width: 50rem;
    height: 41rem;
    -ms-transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
  }

  100% {
    opacity: 1;
    width: 25.6rem;
    height: 19.5rem;
    -ms-transform: translate(-106%, -46%);
    -webkit-transform: translate(-106%, -46%);
    transform: translate(-106%, -46%);
  }
}
<div class="intro-wrapper">
  <div class="intro-logo intro-in"></div>
</div>

I don't know what is the problem here. All browsers render it perfectly (including Google Chrome's emulator), but Safari (iOS / Mac) is unable to render it in the right way while the animation is running (when animation ends, the logo sit on his room).

If you need more details, please, tell me and I add them as soon as possible.

Thank you.

Edit

I will add a bounty because this have no enough attention


Solution

  • You use translate with percentage values, which calculates the element's position according to its width and height. But width and height also changes with the animation. In my opinion, this might be a Safari bug where it calculates the translate according to initial width and height.

    You have two workarounds to choose. Use scale while transforming or use a concrete unit for distance. If you want to use scale though, you have to change some numbers, I am not sure how exactly it works though.

    If you use rem instead of percentage in your animation, it works:

    .intro-wrapper {
      position: fixed;
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
    }
    .intro-logo {
      background: url(https://amonarraiz.com/css/img/slider/2.png) center center no-repeat;
      background-size: cover;
      width: 50rem;
      height: 41rem;
      position: absolute;
      left: 50%;
      top: 50%;
      opacity: 0;
      cursor: pointer;
    }
    .intro-in {
      -moz-animation-duration: 3.75s;
      -webkit-animation-duration: 3.75s;
      animation-duration: 3.75s;
      -moz-animation-name: intro-in;
      -webkit-animation-name: intro-in;
      animation-name: intro-in;
      -moz-animation-iteration-count: 1;
      -webkit-animation-iteration-count: 1;
      animation-iteration-count: 1;
      -moz-animation-fill-mode: forwards;
      -webkit-animation-fill-mode: forwards;
      animation-fill-mode: forwards;
      -webkit-animation-timing-function: ease-in-out;
      -moz-animation-timing-function: ease-in-out;
      animation-timing-function: ease-in-out;
    }
    @-moz-keyframes intro-in {
      0% {
        opacity: 0.6;
        width: 50rem;
        height: 41rem;
        -ms-transform: translate(-25rem, -21.5rem);
        -webkit-transform: translate(-25rem, -21.5rem);
        transform: translate(-25rem, -21.5rem);
      }
      30% {
        opacity: 1;
        width: 50rem;
        height: 41rem;
        -ms-transform: translate(-25rem, -21.5rem);
        -webkit-transform: translate(-25rem, -21.5rem);
        transform: translate(-25rem, -21.5rem);
      }
      100% {
        opacity: 1;
        width: 25.6rem;
        height: 19.5rem;
        -ms-transform: translate(-27.136rem, -8.97rem);
        -webkit-transform: translate(-27.136rem, -8.97rem);
        transform: translate(-27.136rem, -8.97rem);
      }
    }
    @-webkit-keyframes intro-in {
      0% {
        opacity: 0.6;
        width: 50rem;
        height: 41rem;
        -ms-transform: translate(-25rem, -21.5rem);
        -webkit-transform: translate(-25rem, -21.5rem);
        transform: translate(-25rem, -21.5rem);
      }
      30% {
        opacity: 1;
        width: 50rem;
        height: 41rem;
        -ms-transform: translate(-25rem, -21.5rem);
        -webkit-transform: translate(-25rem, -21.5rem);
        transform: translate(-25rem, -21.5rem);
      }
      100% {
        opacity: 1;
        width: 25.6rem;
        height: 19.5rem;
        -ms-transform: translate(-27.136rem, -8.97rem);
        -webkit-transform: translate(-27.136rem, -8.97rem);
        transform: translate(-27.136rem, -8.97rem);
      }
    }
    @keyframes intro-in {
      0% {
        opacity: 0.6;
        width: 50rem;
        height: 41rem;
        -ms-transform: translate(-25rem, -21.5rem);
        -webkit-transform: translate(-25rem, -21.5rem);
        transform: translate(-25rem, -21.5rem);
      }
      30% {
        opacity: 1;
        width: 50rem;
        height: 41rem;
        -ms-transform: translate(-25rem, -21.5rem);
        -webkit-transform: translate(-25rem, -21.5rem);
        transform: translate(-25rem, -21.5rem);
      }
      100% {
        opacity: 1;
        width: 25.6rem;
        height: 19.5rem;
        -ms-transform: translate(-27.136rem, -8.97rem);
        -webkit-transform: translate(-27.136rem, -8.97rem);
        transform: translate(-27.136rem, -8.97rem);
      }
    }
    <div class="intro-wrapper">
      <div class="intro-logo intro-in"></div>
    </div>