Safari infinite translateX animation flickers on loop - css

I have this code
.wave {
position: absolute;
height: 90vh;
width: 1920px * 2;
background-image: url(...);
background-size: 1920px 100%;
background-repeat: repeat-x;
animation: wave 3s linear infinite;
#keyframes wave {
0% {
transform: translateX(0);
// left: 0;
}
100% {
transform: translateX(-1920px);
// left: -1920px;
}
}
}
which should loop seamlessly creating a continuous wave motion. Unfortunately, in safari, it flickers on every loop. I have tried all the -webkit stuff and -webkit-backface-visibility: hidden, but no luck
If I remove transform: translateX(...) and animate left instead, the flickering disappears, but I want to use transform for perfomance reasons
I have created this simple example here
You can see the flicker on every loop (3s) in safari. Works fine in chrome

Adding -webkit-transform: translateZ(0); to img or picture element will do the trick

Related

animated linear gradient devouring CPU usage

I have an animation for alternating the body and change its background color. Everything works just fine, however when the animation runs I can see that my CPU is at 100%. At first I thought it might be due to #keyframes, however when I changed the code from alternating the colors, I saw a very critic CPU overload decrease, of an overwhelming constantly 40%. So I understood it might be due to animation.
Here's my CSS code:
body {
background: linear-gradient(45deg, #F17C58, #E94584, #24AADB, #27DBB1, #FFDC18, #FF3706);
background-size: 600% 100%;
background-repeat: repeat;
background-attachment: fixed;
animation: gradient 16s linear infinite;
animation-direction: alternate;
}
#keyframes gradient {
0% {
background-position: 0%
}
100% {
background-position: 100%
}
}
Can someone help me?
Use transformation by considering pseudo element:
html::before {
content: "";
position: fixed;
z-index:-2;
top: 0;
left: 0;
width: 600%;
bottom: 0;
background: linear-gradient(45deg, #F17C58, #E94584, #24AADB, #27DBB1, #FFDC18, #FF3706);
animation: gradient 16s linear infinite alternate;
}
#keyframes gradient {
100% {
transform: translateX(-83.33%) /* 5/6x100% */
}
}

Blur filter not working as intended (blur filter does not update to match gradient animation)

I am trying to create a text with a blurred background so it looks like the text has an aura. So far the code I have is
.testRainbow {
position:fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
z-index: 9999;
}
.testRainbow::before {
content:'';
position:fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height:100%;
background: linear-gradient(90deg, #03a9f4, #f441a4, #ffeb3b, #03a9f4);
background-size: 400%;
-moz-animation: slideRainbow 8s linear infinite;
-webkit-animation: slideRainbow 8s linear infinite;
animation: slideRainbow 8s linear infinite;
-moz-filter: blur(1em);
-webkit-filter: blur(1em);
filter: blur(1em);
z-index: -1;
}
#keyframes slideRainbow {
0% {
background-position: 0%;
}
100% {
background-position: 400%;
}
}
#-webkit-keyframes slideRainbow {
0% {
background-position: 0%;
}
100% {
background-position: 400%;
}
}
#-moz-keyframes slideRainbow {
0% {
background-position: 0%;
}
100% {
background-position: 400%;
}
}
<h1 class='testRainbow'>test</h1>
I tested it and it works on Chrome, but it does not work on Safari. Further, I checked that it does not work on mobile Chrome, which is interesting because it works when I open Chrome from my desktop.
The linear gradient is changing as it is supposed to for all browsers, but for the ones that don't work, it seems the blur is not being updated. I checked that while I resize or zoom in, the blur updates to the current gradient. What needs to be changed? Thanks in advance.
EDIT
I fixed the problem, and ran into another problem. I added the filter: blur inside the keyframes as follows:
#keyframes slideRainbow (
0% {
background-position: 0%;
filter: blur(1em);
}
100% {
background-position: 0%;
filter: blur(1em);
}
}
I only have the rainbow gradient here, but there are 3 more colors in the css, and which color is shown is randomized. When the same color is selected twice or more in a row, the animation stops and I have a solid gradient behind the text. When another color is selected, the animation kicks back in.
It is supposed to look like this:
But being selected twice in a row, it becomes like this:

Long CSS animation easing (background-position)

I'm trying to animate a background image position smoothly with CSS over a longer period, let's say 60 seconds:
#movingbackground {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Bigsurflowers.jpg/1280px-Bigsurflowers.jpg');
overflow: hidden;
background-position: left center;
animation: zoomin 60s ease-in infinite;
}
#-webkit-keyframes zoomin {
0% { background-position: 0% center; transform: scale(1.0); }
50% {background-position: 100% center; transform: scale(1.2); }
100% { background-position: 0% center; transform: scale(1.0); }
}
#keyframes zoomin {
0% { background-position: 0% center; transform: scale(1.0); }
50% {background-position: 100% center; transform: scale(1.2); }
100% { background-position: 0% center; transform: scale(1.0); }
}
<div id="movingbackground"></div>
The small movements in the beginning and end are "jumping" a few pixel every second instead of moving slowly (may depend on screen size).
The reason for that is probably that there is not enough movement to fill the required number of frames, especially when the animation is eased. As I think I have seen this effect working smoothly somewhere I wonder how to work around this.
Here's a Fiddle as well.
Animation of background-position makes browser to do layout, paint and composite.
Re-layout and re-paint are heavy on CPU and cause "jumping".
Instead of that, you might apply your background to pseudo-element (or use <img> in your HTML) and animate its transform property using 3d transformation.
It will make browser to use GPU for the animation and animation will run in composition phase pretty smoothly.
See the snippet below:
html,
body {
margin: 0;
padding: 0
}
#movingbackground {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
#movingbackground:before {
content: '';
position: absolute;
top: 0; left: 0; z-index: -1;
height: 100%;
width: 200%;
background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/6/68/Bigsurflowers.jpg/1280px-Bigsurflowers.jpg) 0 50% / cover;
animation: zoomin 60s ease-in infinite;
}
#keyframes zoomin {
50% {
transform: translateX(-50%) scale(1.2)
}
}
<div id="movingbackground"></div>
I did some testing and came to the conclusion that it's probably impossible. (At least with transitions or animations)
The problem is the way browsers render images on a screen. The pixels of the image apparently get lined up with those of your screen.
So the picture always "jumps" exactly one pixel at a time.
That means, that the more pixels you have in your image, the more steps it will make. But when using ease-in it will always stutter in the beginning.
As I think I have seen this effect working smoothly somewhere
That was probably not realized with css.

Animation looks pixelated on safari browser and IE11

Animation i've created works fine on Chrome and Firefox, but is pixelated on Safari (version 10.1.1) and IE11.
Tried using translateZ() / translate3d() so the gpu can render the animations but nothing happened.
I've avoided using top, left props. Had an idea of using the will-change prop but it doesn't take animation as a value.
Removing the border radius would fix the rendering issue.
Can someone explain the cause of this and is there a solution to fix this issue?
https://codepen.io/imrdev/pen/awBZOW
html ->
<div class="dot"></div>
css - >
/* KEYFRAME ANIMATION */
#keyframes ease {
0% {
transform: scale(0) rotate(0);
}
50% {
transform: scale(4)
rotate(.01deg);
}
100% {
transform: scale(0) rotate(0);
}
}
#keyframes ease2 {
0% {
transform: scale(0) rotate(0);
}
50% {
transform: scale(6)
rotate(.01deg);
}
100% {
transform: scale(0) rotate(0);
}
}
.dot {
$scale-duration: 15s;
background-color: black;
position: relative;
width: 7px;
height: 7px;
border-radius: 50%;
&::before,
&::after {
content: "";
background: red;
width: 7px;
height: 7px;
border-radius: inherit;
opacity:.3;
position: absolute;
transform: translate(0px, 0px);
}
&::before {
animation: ease 5s ease-in-out infinite;
}
&::after {
animation: ease2 5s ease-in-out infinite both $scale-duration/15;
}
}
Thanks :-)
I have not enough reputation so i can't comment yet, so sorry if this doesn't qualify as a proper answer, but have you tried changing the size to something bigger than 7px and use eg scale(1) instead of scale(4)?
if you need to scale the width and height up by 4 or 6, why not just double the original size and scale up by 2 ?
I wouldn't be surprise if safari doesn't really scale the size up, but kinda like "zooms in" and since the original size is just 7 x 7 px it gets pixelated when "zoomed in"
and regarding to the will-change: you wouldn't use "animation" but "transform"

CSS animation: Difference between left:100% and translate(100%)

I have read about how using translate has better performance, but it seems they behave slightly differently: using left:100% moves the animated object all the way to the end of the screen, whereas translate(100%) only moves the animated object as far as its length. That is, it moves 100% of the screen versus 100% of the object.
Can explain why this is, and what can be done to reproduce the same behavior when using translate?
You can see a demo here: http://jsfiddle.net/32VJV/1/
.slide_1 {
top: 0px;
left:0%;
position: absolute;
overflow: hidden;
font-size: 30px;
}
.slide_1 {
-webkit-animation: slide 3s infinite;
-webkit-animation-delay: 0s;
-webkit-animation-fill-mode:forwards;
-webkit-transform-origin: 0% 0%;
}
.slide_2 {
top: 25px;
left:0%;
position: absolute;
overflow: hidden;
font-size: 30px;
}
.slide_2 {
-webkit-animation: slide2 3s infinite;
-webkit-animation-delay: 0s;
-webkit-animation-fill-mode:forwards;
-webkit-transform-origin: 0% 0%;
}
#-webkit-keyframes slide {
0% {
-webkit-transform: translate(0%);
}
50% {
-webkit-transform: translate(100%);
}
100% {
-webkit-transform: translate(0%);
}
}
#-webkit-keyframes slide2 {
0% {
left 0%;
}
50% {
left:100%;
}
100% {
left:0%;
}
}
<div style="font-size:18px;">
<div class=""> <span class="slide_1" id="dimensions">ABC</span> <span class="slide_2" id="dimensions">ABC</span>
</div>
</div>
The difference between the two is that animating a property like left will keep the element in the flow of the document whereas translate does not.
For more information on why you might use one or the other, Paul Irish has an excellent write up (with links to more information): Why Moving Elements With Translate() Is Better Than Pos:abs Top/left
There's also a lot of great information on browser performance at jankfree.org
Solution for the translate animation: make the element as wide as the window:
Example
slide_1 {
top: 0px;
left:0%;
right: 0;
position: absolute;
overflow: hidden;
font-size: 30px;
}
An interesting exercise: Open your devtools and what what happens when you activate one animation at a time.
In Chrome:
The translate animation has basically nothing going on except a periodic GC
The Left animation you will see repeatedly:
Recalculate Style
Layout
Pain Setup
Paint
Composite Layers
In this case, the overhead it pretty small, but that can change quickly depending on what is being moved around the screen.

Resources