Animation keyframes % are not corrrectly running - css

.shimmer {
width: 211px;
overflow: hidden;
}
.shimmer::before {
content: "";
position: absolute;
height: 65%;
width: 45%;
left: -75px;
background-image: linear-gradient(to right, black, 50%, transparent);
transform: rotate(-70deg);
animation-duration: 100s;
animation-iteration-count: infinite;
}
#keyframes test {
0% {
left: -75px;
}
5% {
left: 200px;
}
100% {
left: 20px;
}
}
I need to run an animation on my ::before element at a certain time. I have used Javascript to input the animation name in to the head.
var styleElem = document.head.appendChild(document.createElement("style"));
styleElem.innerHTML = ".shimmer::before {animation-name:test ;}"
When the function runs I need the animation to start and finish within 1 second and then repeat after every 100seconds.
To test the speed etc I wanted this to finish at 5% (as the animation only needs to be roughly 1 second) Then it will wait (hidden) so when the 100s is up it's time to run again.
The javascript works fine and the animation starts. The issue is, the keyframes % are not taken into account it will just animating over 100 seconds? what am i doing wrong?

0%{
left:-75px;
};
Semi colon here was the issue!!!!!

Set 200px at 100% point:
100% {left: 200px;}

Related

CSS Transition : large div disappears completely while animating

I have some problems with a CSS transition effect. I don't understand why, but it isn't working. Here is a demo that isn't working :
https://codyhouse.co/demo/ink-transition-effect/index.html
Here is an article about how this effect was done (before, when it did work) :
https://codyhouse.co/gem/ink-transition-effect
The code I'm working on to debug is this one :
https://codepen.io/1019/pen/YzxzNGX
HTML file :
<body>
CSS ANIMATIONS TEST
<div class='cd-transition-layer'>
<div class="bg-layer"></div>
</div>
</body>
CSS file :
.cd-transition-layer {
position: fixed;
top: 0;
left: 0;
z-index: 30;
height: 100%;
width: 100%;
}
.cd-transition-layer .bg-layer {
position: absolute;
left: 50%;
top: 50%;
z-index: 15;
transform: translateY(-50%) translateX(-2%);
height: 100%;
width: 2500%;
background: url('https://i.imgur.com/9uDdPAP.png') no-repeat 0 0;
background-size: 100% 100%;
animation: cd-sprite 5s steps(24);
animation-fill-mode: forwards
}
.cd-transition-layer.opening .bg-layer {
z-index: 15;
animation: cd-sprite .8s steps(24);
animation-fill-mode: forwards
}
#keyframes cd-sprite {
0% {
transform: translateY(-50%) translateX(-2%)
}
100% {
transform: translateY(-50%) translateX(-98%)
}
}
Can you please help me find what is wrong ?
Thank you !
EDIT : Okay, weird : it seems the div just completely disappears during the animation before reappering. If I keep focus on the div in the inspector, it stays there. Is it because it's too long (2500% width) ?
Moving large divs
It seems that animating a large div over the screen very fast can cause a render/flicker in webkit based browsers.
If i have to guess, it's probably due to performance reasons, where the browser cuts off things thats are not in the viewport. when moving to the next frame, it will not have the pixels ready to be rendered, resulting in a flicker.
It becomes more apparent when you remove the steps(24) from the animation.
The div will slide over the screen, and at some point just stop being visible.
Using background-position instead
When animating, instead of moving a div over the screen, we can also opt to move only the background instead.
background: url("https://i.imgur.com/9uDdPAP.png") no-repeat;
background-size: 2500% 100%; /* Size is needed to stretch 1 frame to fit the div */
background-position: 0% 0%; /* we can start from frame 0 */
animation: cd-sprite 1s steps(24);
/* the animation is the same, we only move the background instead. (in 24 steps) */
#keyframes cd-sprite {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 0%;
}
}
* {
box-sizing: border-box;
}
.cd-transition-layer {
position: fixed;
top: 0;
left: 0;
z-index: 30;
height: 100%;
width: 100%;
}
.cd-transition-layer .bg-layer {
position: absolute;
left: 50%;
top: 50%;
z-index: 15;
height: 100%;
width: 100%;
background: url("https://i.imgur.com/9uDdPAP.png") no-repeat;
background-size: 2500% 100%;
background-position: 4.16% 0%;
transform: translateY(-50%) translateX(-50%);
animation: cd-sprite 1s steps(24) infinite;
animation-direction: alternate;
animation-delay: 1s;
animation-fill-mode: forwards;
border: 36px solid red;
}
#keyframes cd-sprite {
0% {
background-position: 0% 0%;
}
100% {
background-position: 100% 0%;
}
}
<body>
<div class='cd-transition-layer'>
<div class="bg-layer"></div>
</div>
</body>

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.

#extend class animations cancel each other out

I'm trying to create a loading animation where the outer ring spins to the right, while the inner one spins to the left.
This is all the CSS code:
html {
height: 100%;
}
.loadingCircle {
width: 100px;
height: 100px;
border: solid 5px transparent;
border-top: solid 5px blue;
border-radius: 50%;
transform-origin: center center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.loadingCircleOuter {
#extend .loadingCircle;
animation: circleSpinOuter 2s linear infinite;
}
.loadingCircleInner {
#extend .loadingCircle;
height: 80px;
width: 80px;
animation: circleSpinInner 2s linear infinite;
}
#keyframes circleSpinOuter {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
}
#keyframes circleSpinInner {
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(-360deg);
}
}
Doing this results in the inner circle not spinning at all.
If I comment out the animation of the outer circle the inner one spins properly and making the inner circle spin twice as fast is enough to cancel the out the spin of the outer animation and add the proper spin to the left to it (oddly enough, only to it and not to the outer one, that one is still spinning correctly to the right).
It's clear that the outer animation is applied to both circles, but why?
I don't understand why it's behaving like that, changing the color of the outer circle does not apply the change to both circles, why does it alter the animation for both though?
Am I doing something horribly wrong?

Improve CSS3 background-position animation's performance

I'm trying to improve a CSS3 animation as it seems the current code is causing some excessive CPU load and the browser seems to be laggy.
What can I do? I've got all the vendor prefixes etc. I'm not sure I can improve the code or refactor it to use it as best code practices.
Fiddle Demo
.wrapper {
width: 960px;
height: 140px;
margin-top: 80px;
position: relative;
}
.content:before {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: "";
-webkit-transform: translateZ(0);
transform: translateZ(0);
-webkit-transform-origin: 50% 50% 0;
-ms-transform-origin: 50% 50% 0;
transform-origin: 50% 50% 0;
v -webkit-animation-name: sideupscroll;
animation-name: sideupscroll;
/*animation-duration*/
-webkit-animation-duration: 80s;
animation-duration: 80s;
/*animation-timing-function*/
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
/*animation-iteration-count*/
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
background: url("http://i.imgur.com/wNna7D3.png") repeat fixed 0 0 indigo;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
/* Safari and Chrome */
#-webkit-keyframes sideupscroll {
0% {
background-position: 0 0;
}
50% {
background-position: -50% -100%;
}
100% {
background-position: -100% -200%;
}
}
#keyframes sideupscroll {
0% {
background-position: 0 0;
}
50% {
background-position: -50% -100%;
}
100% {
background-position: -100% -200%;
}
}
<div class="wrapper">
<div class="content"></div>
</div>
Reason
Animating the background-position of an element is always going to be resource intensive and it has a high probability of causing laggy animations in almost all browsers. This is because, a change to the background-position results in a repaint + a composition in all browsers (+ it also results in re-layout in Webkit). Because of the need to perform so many costly operations, the result is always laggy.
Snippet with problem:
The below snippet is the same as your fiddle (without vendor prefixes). Run this snippet and inspect it using Chrome Dev tools after enabling "Show Paint Rects" option. You would see a red or green color box on top of the element (this is the paint rect) and the box will either keep blinking constantly or stay colored for the entire duration of the animation. It indicates that a repaint is happening often and thus it impacts performance.
In Firefox, the paint rects can be seen by enabling nglayout.debug.paint_flashing in about:config page (set it to true).
.wrapper {
width: 960px;
height: 140px;
margin-top: 80px;
position: relative;
}
.content:before {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: "";
transform: translateZ(0);
transform-origin: 50% 50% 0;
animation-name: sideupscroll;
animation-duration: 80s;
animation-timing-function: linear;
animation-iteration-count: infinite;
background: url("http://i.imgur.com/wNna7D3.png") repeat fixed 0 0 indigo;
animation-fill-mode: both;
}
#keyframes sideupscroll {
0% {
background-position: 0 0;
}
50% {
background-position: -50% -100%;
}
100% {
background-position: -100% -200%;
}
}
<div class="wrapper">
<div class="content"></div>
</div>
Solution
It is always better to avoid animating the background-* properties (all of which are visual properties) and use properties like transform. Using transform produces better performance atleast in Blink (Chrome) and EdgeHTML as Blink only does a re-composition while EdgeHTML triggers a re-layout only for the first time (1st update within animation).
Snippet without problem: (or atleast much lesser impact on performance in Blink and EdgeHTML)
The below snippet uses transform property (translateX and translateY) to achieve what is very similar to your expected output (but not the same). If you inspect this snippet with dev tools, you'd see that the green box (paint rect) appears only once at the start of the animation. Post that, the browsers only perform compositing and hence the performance is much better.
.wrapper {
width: 960px;
height: 140px;
margin-top: 80px;
position: relative;
overflow: hidden;
}
.content:before {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 200%;
height: 400%;
content: "";
background: url("http://i.imgur.com/wNna7D3.png") 0 0 indigo;
background-repeat: repeat;
}
.content {
position: relative;
height: 100%;
width: 100%;
animation-name: sideupscroll;
animation-duration: 80s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-fill-mode: both;
}
#keyframes sideupscroll {
0% {
transform: translateX(0%) translateY(0%);
}
50% {
transform: translateX(-50%) translateY(-100%);
}
100% {
transform: translateX(-100%) translateY(-200%);
}
}
<div class="wrapper">
<div class="content"></div>
</div>
What about Gecko and Webkit?
Unfortunately there doesn't to be a solution for browsers using these rendering engines as at the time of writing. The only option seems to be to reduce the animation-duration. A reduction in animation's duration means that the no. of re-paint + re-layout + re-composition cycles required is lesser and thus the animation's performance is better.
The below snippet looks less laggy in Firefox as the duration is only 20s.
.wrapper {
width: 960px;
height: 140px;
margin-top: 80px;
position: relative;
overflow: hidden;
}
.content:before {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 200%;
height: 400%;
content: "";
background: url("http://i.imgur.com/wNna7D3.png") 0 0 indigo;
background-repeat: repeat;
}
.content {
position: relative;
height: 100%;
width: 100%;
animation-name: sideupscroll;
animation-duration: 20s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-fill-mode: both;
}
#keyframes sideupscroll {
0% {
transform: translateX(0%) translateY(0%);
}
50% {
transform: translateX(-50%) translateY(-100%);
}
100% {
transform: translateX(-100%) translateY(-200%);
}
}
<div class="wrapper">
<div class="content"></div>
</div>
Useful Links:
CSS Triggers - Lists out which properties result in which operations being triggered.
HTML5 Rocks - Accelerated Rendering in Chrome - Explains how accelerated rendering works in Chrome (and how to enable "Show Paint Rects" option)
Note: As I had already stated above, the animation is not 100% the same as what you had in question but in my opinion this is about the closest you could get.

Css Animation not working correct

I have to elements and I want to animate them seperatly. Element one should play animation one and element two should play animation two.
But when I test it element one plays both animations and element two none.
This is not happening if I start the animation of element two with a delay, but this is no solution...
Here's element one:
#wrapper_splashscreen #logo {
position: absolute;
left: 50%;
top: 50%;
width: 200px;
height: 200px;
margin-top: -100px;
margin-left: -100px;
-webkit-animation: logoIntro 0.5s 1; }
#-webkit-keyframes logoIntro
{
0% {
-webkit-transform: scale(0, 0);
opacity: 0;
}
80% {
-webkit-transform: scale(1.4, 1.4);
}
90% {
-webkit-transform: scale(1.1, 1.1);
}
100% {
-webkit-transform: scale(1, 1);
opacity: 1;
}
}
and here's element two:
#wrapper_splashscreen #menu {
position: absolute;
bottom: 0px;
left: 0px;
width: 100%;
height: 40px;
background: #151515;
-webkit-animation-name: menuIntro 1s 1; }
#-webkit-keyframes menuIntro
{
0%, 30% {
bottom: -40px;
}
100% {
bottom: 0px;
}
}
The logo (element one) is fadeing in and moving down and the menu (element two) is doing nothing.
In the second element you've an error:
-webkit-animation-name: menuIntro 1s 1;
It should be -webkit-animation.
I'm not sure what's the problem with the first element (please add a fiddle/demo), buy maybe setting a transform-origin will help
It seems like the animation becomes buggy when you navigate to the animated element with an anchor. The browser navigates to the element while its moving and the animation gets broken.

Resources