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>
Related
I made a CSS3 animation, it works well in Firefox and Chrome, but it behaves differently in IE11 and Edge.
I couldn't fix the issue because it's hard to debug CSS3 Animation using IE Developer Tools. This issue also occurs on Edge (But i think my Edge version is outdated so please try to reproduce this issue only in IE11. The fix will probably work on both).
Here is how i want the animation to look (Works on Chrome/Firefox):
Here is how it animates differently on IE11:
Code:
HTML:
<div class="block"></div>
<span>click</span>
CSS:
span {
width: 50px;
height: 50px;
background: red;
font-size: 50px;
}
.block {
position: fixed;
height: 0%;
bottom: 0;
width: 100%;
top: auto;
display: block;
background-color: #0B0B0B;
z-index: 99999;
animation-fill-mode: both;
animation-duration: 2s;
animation-timing-function: ease-in-out;
}
.animate-up {
animation-name: overlayEffectUp;
}
#keyframes overlayEffectUp {
0% {
bottom: 0;
top: auto;
height: 0%;
}
35%,
65% {
height: 100%;
}
100% {
bottom: auto;
top: 0;
height: 0%;
}
}
JavaScript (With jQuery):
$('span').on('click', function() {
$('.block').addClass('animate-up')
})
Here is the Demo link: https://jsfiddle.net/zoq9h7xp/3/
Please, any help would be appreciated!
Edge seems to be buggy with position: fixed. Supposedly the switch between top: 0 and top: auto (and same story with the bottom property) causes this behaviour.
If you must maintain the fixed position, you can try to animate with the transform property. Change your rulesets as follow:
#keyframes overlayEffectUp {
0% {
transform: translateY(100%); // totally offscreen
}
35%,
65% {
transform: translateY(0%); // totally on screen from bottom
}
100% {
transform: translateY(-100%); // totally off screen again to top
}
}
.block {
position: fixed;
top:0;
bottom:0;
transform: translateY(100%);
width: 100%;
background-color: #0B0B0B;
z-index: 99999;
animation-fill-mode: both;
animation-duration: 2s;
animation-timing-function: ease-in-out;
}
Hope this helps.
Cheers, Jeroen
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.
I am simply trying to reverse the direction my pure css horizontal image slider is sliding. I have tried altering the key frame animation portion with opposite direction, with both - position and toggling left to right, all my attempts do is allow one slide to slide in the correct direction and then just blank white space due to my images float: left;
Here is live jsFiddle. And here is a Jsfiddle of my attempt and how it's rendering (ie. not working. it slides through one image in the correct direction, but not the rest)
Also, my code below.
Mark-Up:
<div class="slider3">
<figure>
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
<img src="http://img00.deviantart.net/a251/i/2007/347/c/8/drunk_santa_by_yakuks.png">
</figure>
</div>
CSS:
.slider3 {
width: 100%;
max-width: 960px;
overflow: hidden;
}
.slider3 figure img {
width: 25%;
float: left;
background: red;
}
.slider3 figure{
width: 400%;
position: relative;
margin:0;
padding: 0;
animation: 10s slide infinite;
-webkit-animation: 10s slide infinite;
}
#-webkit-keyframes slide {
0% { left:0%; }
16% { left:0%; }
33% { left:-100%; }
49% { left:-100%; }
66% { left:-200%; }
82% { left:-200%; }
100% { left:-300%; }
}
Actually you don't have to do any modifications other than add animation-direction: reverse to the list of rules (or you can set it as a value in the animation shorthand). As you'd have guessed, adding this property-value pair would reverse the flow of your animation.
When you place 4 images on a page (with float: left and 100% width for each), the 1st image is at 0%, the 2nd is at 100%, 3rd at 200% and 4th at 300%. What your current animation does is - start with the left: 0% which means the first image is in view. After sometime the left offset is set as -100% and what this means is that the second image which was at 100% on the page will now get displayed (as 100% - 100% = 0% and so it lands in the viewing area). Similarly the 3rd and 4th also gets shown.
Now to reverse the animation, you need the left offset to start at -300% so that the fourth image is visible first and then it slides towards the right instead of slide towards the left. Note: If you want the first image in the DOM to show up first then change float:left to right for .slider3 figure img.
With fourth image in DOM appearing first: (float: left)
.slider3 {
width: 100%;
max-width: 960px;
overflow: hidden;
}
.slider3 figure img {
width: 25%;
float: left;
background: red;
}
.slider3 figure {
width: 400%;
position: relative;
margin: 0;
padding: 0;
animation: 10s slide infinite reverse backwards;
-webkit-animation: 10s slide infinite reverse backwards;
}
#-webkit-keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
#keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
<div class="slider3">
<figure>
<img src="http://lorempixel.com/200/200/nature/1">
<img src="http://lorempixel.com/200/200/nature/2">
<img src="http://lorempixel.com/200/200/nature/3">
<img src="http://lorempixel.com/200/200/nature/4">
</figure>
</div>
With first image in DOM appearing first: (float: right)
.slider3 {
width: 100%;
max-width: 960px;
overflow: hidden;
}
.slider3 figure img {
width: 25%;
float: right;
background: red;
}
.slider3 figure {
width: 400%;
position: relative;
margin: 0;
padding: 0;
animation: 10s slide infinite reverse backwards;
-webkit-animation: 10s slide infinite reverse backwards;
}
#-webkit-keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
#keyframes slide {
0% {
left: 0%;
}
16% {
left: 0%;
}
33% {
left: -100%;
}
49% {
left: -100%;
}
66% {
left: -200%;
}
82% {
left: -200%;
}
100% {
left: -300%;
}
}
<div class="slider3">
<figure>
<img src="http://lorempixel.com/200/200/nature/1">
<img src="http://lorempixel.com/200/200/nature/2">
<img src="http://lorempixel.com/200/200/nature/3">
<img src="http://lorempixel.com/200/200/nature/4">
</figure>
</div>
You'd notice that I have added a backwards also to the animation short-hand property. This stands for animation-fill-mode and it makes the element hold the state as at its last keyframe until the time the animation starts. If this isn't added there will be a snap at the start where the first image will display before immediately changing to 4th (no slide) with float:left and vice-versa for float: right.
Amr Aly's second answer will work (and there are other possible ways too) but there is absolutely no reason to make it so complex.
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.
Using the second answer found here. I combined my images into a sprite and then updated my CSS to reflect the keyframes element like in the example provided. The sprite image (castle) shows up but the slide effect does not take place? What am I missing?
Sample URL, center element on home page: http://216.157.26.175/cookiedouglas/
Here is my CSS:
.agentpress-pro-cookie .home-featured .widget {
/* background-color: rgba(255, 255, 255, 0.8); */
background: url("http://216.157.26.175/cookiedouglas/wp-content/uploads/sites/58/2015/05/fort-myers-homes-for-sale.jpg");
opacity: 0.95;
content: '';
/* position: absolute;
width: 400%;
height: 100%; */
z-index: -1;
/* background: url(http://placekitten.com/500/500/); Image is 500px by 500px, but only 200px by 50px is showing. */
animation: slide 3s infinite;
}
#keyframes slide {
20% {
left: 0;
}
40%, 60% {
left: -50%;
}
80%, 100% {
left: -100%;
}
}
Use browser (vendor) specific prefixes.
Browser prefixes are used to add new features that may not be part of a formal specification and to implement features in a specification that hasn’t been finalized.
CSS3 animation is one of those features. It has partial support across different browsers. Browser support for CSS3 animations can be checked here.
As evident from the above link, to make the animation work on browsers other than IE and Firefox, you meed the -webkit- prefix.
Also, CSS left propery works only with absolutely positioned elements.
So you should try something like this (read added comments in snippet for explanation):
/*visible portion of the larger 5120x680 pixel image*/
.widget {
width: 1024px;
height: 680px;
position: relative;
overflow: hidden;
border: 1px solid black;
}
.widget:before {
content: '';
position: absolute;
/*needed for CSS left property to work*/
width: 5120px;
height: 680px;
z-index: -1;
/*ExampleImageSprite.jpg is a 5120x680 pixel image which is a combination of 5 individual 1024x680 pixel images*/
background: url("https://dl.dropboxusercontent.com/u/192824325/00_sandbox/30150865/ExampleImageSprite.jpg");
-webkit-animation: slide 10s infinite;
animation: slide 10s infinite;
}
#-webkit-keyframes slide {
0% {
left: 0px;
}
20% {
left: -1024px;
}
40% {
left: -2048px;
}
60% {
left: -3072px;
}
80% {
left: -4096px;
}
100% {
left: -5120px;
}
}
#keyframes slide {
0% {
left: 0px;
}
20% {
left: -1024px;
}
40% {
left: -2048px;
}
60% {
left: -3072px;
}
80% {
left: -4096px;
}
100% {
left: -5120px;
}
}
<div class=widget></div>