AndrewLeonardi
AndrewLeonardi

Reputation: 3512

Smooth Keyframe Animation on Mobile?

I'm working on improving a Keyframe Animation's smoothness. It seems to work perfectly on desktop but is very laggy and not smooth on mobile. How would I need to change my code to make it smooth?

See JSBin: https://jsbin.com/hecifu/6/edit?html,css,js,output

@keyframes overlayAnimation {
  0% {
    width:  100vw;
    height: 100vh;
    transform: translate3d(0px, 0px, 0);
    background: transparent;
  }
  25%{
    width:  10px;
    height: 200px;
    transform: translate3d(calc(50vw - 5px), calc(50vh - 100px), 0);
  }
  50%{
    width:  10px;
    height: 200px;
    transform: translate3d(calc(50vw - 5px), calc(50vh - 100px), 0) rotate(90deg);
  }
  50.1%{
    width:  200px;
    height: 10px;
    transform: translate3d(calc(50vw - 100px), calc(50vh - 5px), 0) rotate(0deg);
  }
  75%{
    width:  200px;
    height: 100vh;
    transform: translate3d(calc(50vw - 100px), 0px, 0) rotate(0deg);
  }
  100%{
    width:  100vw;
    height: 100vh;
    transform: translate3d(0px, 0px, 0) rotate(0deg);
    visibility:hidden;
  }

Upvotes: 0

Views: 713

Answers (1)

Oliver
Oliver

Reputation: 3138

There are a few issues that could be causing the slow-down. The main suspect though: remove the box-shadow.

To elaborate

CSS can utilise hardware acceleration for animations... but only for transform and opacity animations - all other animations are run on the CPU, which is less optimised: https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/

Your animation changes the width and height attributes of an element - what you may want to consider is changing it so that the size is altered via a transform: scale(x, y) change instead: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale

But possibly the biggest drain in your animation is actually the box-shadow - you have a box-shadow set that is 2000px in all directions - that is going to be quite a draw on the smartphone, which has to thus calculate (even if it doesn't have to render all of) a box that is at least 4000px larger than the width and height of the device. Box-shadows can be costly to render at the best of times. These documented cases are for scrolling performance, but I should imagine that animating a box-shadow has a similar performance impact.

What might be better here is to try and use a clip-path to clip the content, rather than cover it with a box-shadow. That would work something like this (based on your JSBin):

var $pages = $(".page");
var $overlay = $("#overlay");

$('.page a').on("click", function(){
  if($overlay.hasClass("overlayAnimation")) return;
  $pages.fadeToggle(4000);
  $overlay.addClass("overlayAnimation").on("animationend", function(){
    $(this).removeClass("overlayAnimation");
  });
});
*{margin:0; box-sizing:border-box;}
html, body{height:100%;}


h1{   
  font: 60px/2 Helvetica;
  color: #fff;
  font-weight: normal;
  text-align: center;
}
.page{
  position: absolute;
  overflow: hidden;
  width:  90vw;
  height: 90vh;
  top:  5vh;
  left: 5vw;
  color: white;
}
#page1{
  background: #008562;
}
#page2{
  display: none;
  background: #ff8600;
}
.page a{
  font-family: Helvetica;
  color: #fff;
  border: 2px solid #fff;
  padding: 10px 15px;
  display: block;
  text-align: center;
  margin: 0 auto;
  width: 20%;
  text-decoration: none;
}

#overlay{
  position: fixed;
  z-index:999;
  width:  100vw;
  height: 100vh;
}

#overlay.overlayAnimation{
  animation: overlayAnimation 4s forwards;
}

@keyframes overlayAnimation {
  0% {
    clip-path: inset(0 0);
    background: transparent;
  }
  25%{
    clip-path: inset(calc(50% - 100px) calc(50% - 5px));
    transform: rotate(0deg);
  }
  50%{
    clip-path: inset(calc(50% - 100px) calc(50% - 5px));
    transform: rotate(90deg);
  }
  50.1%{
    clip-path: inset(calc(50% - 5px) calc(50% - 100px));
    transform: rotate(0deg);
  }
  75%{
    clip-path: inset(0 calc(50% - 100px));
  }
  100%{
    clip-path: inset(0 0);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="overlay">
    <div class="page" id="page1">
        <h1>PAGE 1</h1>
        <a href="#">Click here</a>
    </div>
      
    <div class="page" id="page2">
        <h1>PAGE 2</h1>
        <a href="#">Click here</a>
    </div>
</div>

https://jsbin.com/pojewujoko/edit?html,css,js,output

Maybe give that a go, see if it is any more performant? It's certainly more elegant IMO, and makes more sense to someone viewing the code directly.

Upvotes: 1

Related Questions