Smooth Keyframe Animation on Mobile? - css

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;
}

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>
Click here
</div>
<div class="page" id="page2">
<h1>PAGE 2</h1>
Click here
</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.

Related

CSS3 Animation: How do I create smooth movement of background image? Seems to be a Chrome only issue

Trying to smoothly animate a div's background image #bg2 over a short pixel distance (while a clip path animates over it). I'm not able to get the image to move smoothly, it jitters and judders. The clip path animation is fine.
I've tried different easing (linear / ease-in-out etc) suggested in another SO thread, and also extending the distance it needs to move, but it still seems to jump pixel by pixel (sort of), rather than move smoothly. (Although, extending the move distance isn't an option in the actual use case).
How can smooth movement of the cat background image #bg2 be accomplished? Thanks.
** Edit: It's totally smooth for me in Firefox, for me it's jittery in Chrome 91.0.4472.114 on Mojave 10.14.6, and less jittery in Safari. For other it seems to be smooth on Chrome also. Hmmm...
var clickTag = "#";
#main-container {
position: absolute;
width: 970px;
height: 250px;
left:-200px;
box-sizing: border-box;
background: #333;
overflow:hidden; perspective: 800px;
border:1px solid #ccc;
}
div, img {
position: absolute;
background-repeat:no-repeat;
width: 970px;
height: 250px;
z-index: 4;
background-size: 970px 250px;
}
#bg2{
width: 970px;
height: 250px;
z-index:2;
background-image:url('https://i.stack.imgur.com/6EcDu.jpg');
-webkit-clip-path: circle(9% at 682px 110px);
clip-path: circle(9% at 682px 110px);
transform: translateY(20px);
background-position: -5px -10px;
}
#bg2{animation: grow 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;-webkit-animation: groww 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;}
#-webkit-keyframes groww {
0% {opacity:1;transform: translateY(20px);clip-path: circle(9% at 682px 110px);-webkit-clip-path: circle(9% at 682px 110px);background-position: -5px -10px;}
100% {opacity:1;transform: translateY(-4px);clip-path: circle(15% at 682px 128px);-webkit-clip-path: circle(15% at 682px 128px);background-position: 0px 0px;}
}
#keyframes grow {
0% {opacity:1;transform: translateY(20px);clip-path: circle(9% at 682px 110px);background-position: -5px -10px;}
100% {opacity:1;transform: translateY(-4px);clip-path: circle(15% at 682px 128px);background-position: 0px 0px;}
}
<a href="javascript:window.open(window.clickTag)">
<div id="main-container" class="animate">
<div id="bg2"></div>
</div>
</a>
I'm a bit curious about why having a large banner while not displaying it all.
Anyways, I provide another way of animating, basically just changing the height. Hopefully that could give some ideas.
I removed the width to make it slightly more responsive.
The animation somewhat jittery in this solution, but I guess that it depends on your bezier curve. So perhaps that's the issue all along?
var clickTag = "#";
#main-container {
position: relative;
height: 250px;
box-sizing: border-box;
border: 1px solid #ccc;
background-color: #333;
}
#bg2 {
position: absolute;
left: 75%;
top: 50%;
transform: translate(-50%, -50%);
height: 40%;
aspect-ratio: 1;
border-radius: 50%;
background-image: url('https://i.stack.imgur.com/6EcDu.jpg');
background-position: right 25% center;
animation: grow 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;
}
#keyframes grow {
to { height: 80%; }
}
<a href="javascript:window.open(window.clickTag)">
<div id="main-container">
<div id="bg2"></div>
</div>
</a>

CSS - Improve opacity animation performance in conic gradient

I have a CSS animation that has terrible performance if it's size is large, about 800px X 800px
or more, the animation can only be run in newest versions of Chrome or Edge.
See example code. If example is not slow enough add more circles or increase the example size.
The real animation is very similar to this one, this is just a simplified example.
I would like to know if there's a way to improve the performance of this animation.
The conic gradient maybe can be simplified but must look the same!
#property --opacity {
syntax: '<percentage>';
initial-value: 100%;
inherits: false;
}
.test {
display: inline-block;
position: absolute;
border-radius: 100%;
background-image: conic-gradient(
red var(--opacity),
red 10%,
rgba(255, 0, 0, var(--opacity)),
transparent,
transparent
);
will-change: transform, background-image;
width: 800px;
height: 800px;
mask:radial-gradient(circle, transparent 47%, white calc(47% + 1px));
-webkit-mask:radial-gradient(circle, transparent 47%, white calc(47% + 1px));
animation:
conic-gradient
4.5s
ease-out
0s
infinite
none
running;
}
.a {
position: absolute;
right: -10%;
top: 20%;
}
.b {
position: absolute;
right: -10%;
top: 40%;
}
#keyframes conic-gradient {
50% {
--opacity: 0%;
}
85% {
--opacity: 100%;
}
}
<div class="test"></div>
<div class="test a"></div>
<div class="test b"></div>
Is there a way to improve the performance?

CSS Animated wavy line not displaying properly in Chrome

I have created a simple animated wavy line to use as a divider on one of my websites. Looks perfect in safari but it displays strange in Chrome.
Here's the safari screenshot:
Here's the chrome screenshot:
The safari one is perfect for me, but it seems chrome isn't liking it.
I have tried adding ALL vendor prefixes to the start of the selectors and various places but I cant seem to fix the issue.
Can anyone please tell me where I'm going wrong?
Here's a CODEPEN and here's a code snippet:
.wavy-line {
width: 150px;
height: 50px;
overflow: hidden;
margin: 0 auto 0 auto;
}
.wavy-line:before {
content: attr(data-text);
position: relative;
top: -35px;
color: rgba(0,0,0,0);
width: calc(100% + 27px);
font-size: 4em;
text-decoration-style: wavy;
text-decoration-color: #25173A;
text-decoration-line: underline;
animation: animate .9s linear infinite;
-webkit-animation: animate .9s linear infinite;
}
#keyframes animate {
0% { left: -0px; }
100% { left: -30px;}
}
#-webkit-keyframes animate {
0% { left: -0px; }
100% { left: -30px;}
}
.wavy-line-green:before { text-decoration-color: #56AE5F; }
.wavy-line-blue:before { text-decoration-color: #1FB5D1; }
.wavy-line-yellow:before { text-decoration-color: #F9B930; }
<div class="wavy-line wavy-line-green" data-text="xxxxxxxxxxxxxx"></div>
<div class="wavy-line wavy-line-blue" data-text="xxxxxxxxxxxxxx"></div>
<div class="wavy-line wavy-line-yellow" data-text="xxxxxxxxxxxxxx"></div>
I will consider a previous answer to draw the waves using CSS and then you can easily animate them. You simply need to adjust the CSS variable to control the shape:
.wave {
--c:red; /* Color */
--t:5px; /* Thickness */
--h:50px; /* Height */
--w:120px; /* Width */
--p:13px; /* adjust this to correct the position when changing the other values*/
margin:5px auto;
width:calc(var(--w)*4);
height:calc(var(--h) + 10px);
overflow:hidden;
position:relative;
}
.wave:before {
content:"";
position:absolute;
padding:5px 0;
top:0;
left:0;
width:200%;
bottom:0;
background:
radial-gradient(farthest-side at 50% calc(100% + var(--p)), transparent 47%, var(--c) 50% calc(50% + var(--t)),transparent calc(52% + var(--t))),
radial-gradient(farthest-side at 50% calc(0% - var(--p)), transparent 47%, var(--c) 50% calc(50% + var(--t)),transparent calc(52% + var(--t)));
background-size:var(--w) var(--h);
background-position:calc(var(--w)/2) calc(-1*(var(--h)/2)),0px calc(var(--h)/2);
background-repeat:repeat-x;
background-origin:content-box;
animation:move 3s infinite linear;
}
#keyframes move {
to {
transform:translateX(-50%);
}
}
<div class="wave"></div>
<div class="wave" style="--w:140px;--h:40px;--p:13px; --t:8px;--c:purple"></div>
<div class="wave" style="--w:100px;--h:30px;--p:14px;--t:10px;--c:green;"></div>
<div class="wave" style="--w: 64px;--h: 22px;--p: 11px;--t: 7px;--c: orange;"></div>

Generate gradient like the image

How can I generate a gradient like this image?
This is the closest I've got so far, but it is not yet the same:
.background {
position: relative;
background-image: radial-gradient(circle at top right, #ff9bb4, #ff507b, #ff7a2d, #f55a00 ) ;
width: 100%;
height: 300px;
-webkit-transform: skewY(-1.5deg);
-moz-transform: skewY(-1.5deg);
-ms-transform: skewY(-1.5deg);
-o-transform: skewY(-1.5deg);
transform: skewY(-1.5deg);
}
<div class="background"></div>
Maybe you could go at this by layering semi transparent gradients:
CSS
.grad {
width: 100%;
height: 100vh;
position: absolute;
top: 0;
}
.outer {
background: linear-gradient(45deg, rgba(255,83,21,0.21) 0%,rgba(254,55,112,0.87) 100%);
}
.inner {
background: linear-gradient(45deg, rgba(255,83,21,0.5) 0%,rgba(254,55,112,0.87) 100%);
}
HTML
<div class='outer grad'>
<div class='inner grad'></div>
</div>
If you need it, the rotation in the image above can be achieved with transform: rotate(10deg) rather than the skew.
To create the gradient, this could be helpful for you:
Gradient generator
If you would like to have the border as well, I would set the gradient as the background of a div and set the border of the div the way you want.
Created a pen: https://codepen.io/Raphael_Bucher/pen/wyQRYr
HTML
<div class="gradient-wrapper">
<div>
CSS
.gradient-wrapper {
height: 250px;
width: 500px;
margin-top: 50px;
background-image: linear-gradient(to right bottom, #fa9049, #ff8153,
#ff7260, #ff656e, #fe597e);
transform: skewY(-4deg);
-moz-transform: skewY(-4deg);
-webkit-transform: skewY(-4deg);
}

CSS animation image of leaf (as if blowing in the wind)

This was a personal challenge and I'm reasonably happy with the approach I have come up with below but I'd be keen to see if there are any alternative approaches.
I am working on a site where the logo contains a leaf image.
I thought it might be eye-catching to have the leaf appearing to be "wind-blown" to its final logo position.
I wanted to improve on the first (very basic) version of the CSS #keyframes animation I had written:
#keyframes leafanimation {
0% {transform:translate(900px,500px); color:rgba(255,0,0,0);}
80% {transform:translate(0,0); color:rgba(255,0,0,0);}
100% {transform:translate(0,0); color:rgba(255,0,0,1);}
}
.my-logo {
position:absolute;
top:0;
left:0;
height: 40px;
line-height: 40px;
font-size: 36px;
color: rgb(255,0,0);
animation: leafanimation 6s linear;
}
.my-logo div {
display: inline-block;
width: 20px;
height: 40px;
vertical-align: middle;
background-color: rgb(255,0,0);
border-radius: 20px;
}
<div class="my-logo">
My Logo
<div></div>
</div>
This was the solution I came up with (eventually) using a series of translate and rotate CSS transforms:
#keyframes leafanimation {
0% {transform:translate(900px,500px) rotate(0deg); color:rgba(255,0,0,0);}
20% {transform:translate(850px,450px) rotate(360deg); color:rgba(255,0,0,0);}
40% {transform:translate(450px,200px) rotate(720deg); color:rgba(255,0,0,0);}
60% {transform:translate(100px,100px) rotate(1080deg); color:rgba(255,0,0,0);}
80% {transform:translate(0,0) rotate(1440deg); color:rgba(255,0,0,0);}
100% {transform:translate(0,0) rotate(1440deg); color:rgba(255,0,0,1);}
}
.my-logo {
position:absolute;
top:0;
left:0;
height: 40px;
line-height: 40px;
font-size: 36px;
color: rgb(255,0,0);
animation: leafanimation 6s linear;
}
.my-logo div {
display: inline-block;
width: 20px;
height: 40px;
vertical-align: middle;
background-color: rgb(255,0,0);
border-radius: 20px;
}
<div class="my-logo">
My Logo
<div></div>
</div>

Resources