How to remove usage of excess keyframes by using animation-delay? - css

I'm looking through Google Polymer's source code and I found this:
/**
* IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee):
*
* iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't
* guarantee that the animation will start _exactly_ after that value. So we avoid using
* animation-delay and instead set custom keyframes for each color (as redundant as it
* seems).
*
**/
.active .spinner-layer.blue {
-webkit-animation: blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .spinner-layer.red {
-webkit-animation: red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .spinner-layer.yellow {
-webkit-animation: yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
.active .spinner-layer.green {
-webkit-animation: green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
animation: green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both;
}
#-webkit-keyframes blue-fade-in-out {
from { opacity: 1; }
25% { opacity: 1; }
26% { opacity: 0; }
89% { opacity: 0; }
90% { opacity: 1; }
100% { opacity: 1; }
}
#keyframes blue-fade-in-out {
from { opacity: 1; }
25% { opacity: 1; }
26% { opacity: 0; }
89% { opacity: 0; }
90% { opacity: 1; }
100% { opacity: 1; }
}
#-webkit-keyframes red-fade-in-out {
from { opacity: 0; }
15% { opacity: 0; }
25% { opacity: 1; }
50% { opacity: 1; }
51% { opacity: 0; }
}
#keyframes red-fade-in-out {
from { opacity: 0; }
15% { opacity: 0; }
25% { opacity: 1; }
50% { opacity: 1; }
51% { opacity: 0; }
}
#-webkit-keyframes yellow-fade-in-out {
from { opacity: 0; }
40% { opacity: 0; }
50% { opacity: 1; }
75% { opacity: 1; }
76% { opacity: 0; }
}
#keyframes yellow-fade-in-out {
from { opacity: 0; }
40% { opacity: 0; }
50% { opacity: 1; }
75% { opacity: 1; }
76% { opacity: 0; }
}
#-webkit-keyframes green-fade-in-out {
from { opacity: 0; }
65% { opacity: 0; }
75% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
#keyframes green-fade-in-out {
from { opacity: 0; }
65% { opacity: 0; }
75% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
I agree that this code looks incredibly verbose, but I wasn't sure how one would go about re-expressing it using animation-delay instead of custom keyframes.
Not all the colors seem to take a full 25% chunk. Green only takes 15%... which seems a bit odd. Nevertheless, would it be as simple as just taking the start % and multiplying it by the animation duration and setting that as the delay? How would the end-time be specified, then?
How would this code look if the bug fix did not need to be addressed?

It looks like somebody has changed the code after the initial comments.
as it is now, only 2 animations are redundant, so the comment doesn¡t make full sense.
It is a common practice in cyclic animations, where in your case 4 elements share - or should share- the same animation, but in a sequential way, to reuse the animation and change only the start time (thru the initial delay property)
In this case, that would be probably
#keyframes red-fade-in-out {
0% { opacity: 1; }
25% { opacity: 1; }
26% { opacity: 0; }
100% { opacity: 0; }
}
and then every class would have a different delay, of 1/4 of the total time of the animation.

Related

Some css #keyframes animation opacity issues

Can anybody explain why this code doesn't hide elemens between 95-100%? I want to show hidden by opacity object and hide it after animation. I have no idea why it doesn't work.
button {
opacity: 0;
animation: button 6s linear infinite 0s;
}
#keyframes button {
0% {
opacity: 0;
transform: translateY(64px);
}
5% {
opacity: 1;
transform: translateY(0px);
}
95% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<button>example</button>

Fade-transitioning effect for background images - overlapping issue

AIM
I would like to show a faded transition among three pictures (ideally 10, I used three for this question). Each image should gradually increase its opacity until fully opaque and then the next picture should start the same process, i.e. starting from opacity 0 to 1.
PROBLEM
If you have a look at the snippet, you'd see that only the third image follows this opacity process while the first two are vaguely shown as the first image overlaps them.
Thanks for your help!
ATTEMPT
.slider {
margin: 0;
padding: 0;
}
.slide {
position: absolute;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-size: cover;
}
.slide-1 {
background-image: url("https://images.immediate.co.uk/production/volatile/sites/23/2019/10/Federico_Veronesi_Lions-cover-image-e359a4e.jpg?quality=45&crop=10px,234px,3691px,2458px&resize=620,413");
animation: fade1 10s infinite;
}
.slide-2 {
background-image: url("https://images.unsplash.com/photo-1490100886609-e401a775fb3a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80");
animation: fade2 10s infinite;
}
.slide-3 {
background-image: url("https://images.pexels.com/photos/326055/pexels-photo-326055.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500");
animation: fade3 10s infinite;
}
#keyframes fade1 {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fade2 {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fade3 {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<body class="slider">
<div class="slide slide-1"></div>
<div class="slide slide-2"></div>
<div class="slide slide-3"></div>
</body>
CSS animation is doable but requires some kind of trick. The reason why your code does not work is because all the CSS animations are happening at the same time. What you want is to ensure that fade1, fade2, and fade3 all start and stop at consecutive intervals, so that they will come after each other:
fade1 starts at 0% and ends at 33% (1/3)
fade2 starts at 33% (1/3) and ends at 67% (2/3)
fade3 starts at 67% (2/3) and ends at 100% (3/3)
Of course, this means that you will need to (1) declare a new keyframe for each slide added and (2) adjust the start/end points of all keyframes when a new slide is added. This can be cumbersome, and the only way to automate this (or do it programmatically) is to use JS or preprocessed CSS.
See proof-of-concept below:
.slider {
margin: 0;
padding: 0;
}
.slide {
position: absolute;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-size: cover;
}
.slide-1 {
background-image: url("https://images.immediate.co.uk/production/volatile/sites/23/2019/10/Federico_Veronesi_Lions-cover-image-e359a4e.jpg?quality=45&crop=10px,234px,3691px,2458px&resize=620,413");
animation: fade1 10s infinite;
}
.slide-2 {
background-image: url("https://images.unsplash.com/photo-1490100886609-e401a775fb3a?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80");
animation: fade2 10s infinite;
}
.slide-3 {
background-image: url("https://images.pexels.com/photos/326055/pexels-photo-326055.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500");
animation: fade3 10s infinite;
}
#keyframes fade1 {
0% {
opacity: 0;
}
33% {
opacity: 1;
}
}
#keyframes fade2 {
33% {
opacity: 0;
}
67% {
opacity: 1;
}
}
#keyframes fade3 {
67% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<body class="slider">
<div class="slide slide-1"></div>
<div class="slide slide-2"></div>
<div class="slide slide-3"></div>
</body>
SCSS solution
If you are using a CSS preprocessor such as SCSS, you can simply generate slides on the fly: all you need is to remember to add the corresponding markup:
// Just some demo images
$images: [
'https://via.placeholder.com/400x300/3077FF/fff?text=Slide1',
'https://via.placeholder.com/400x300/2C9EE8/fff?text=Slide2',
'https://via.placeholder.com/400x300/3DE4FF/fff?text=Slide3',
'https://via.placeholder.com/400x300/2CE8CE/fff?text=Slide4',
'https://via.placeholder.com/400x300/30FFA8/fff?text=Slide5',
];
.slide {
position: absolute;
width: 400px;
height: 300px;
background-repeat: no-repeat;
background-size: cover;
opacity: 0;
}
#for $i from 1 through length($images) {
$image: nth($images, $i);
// Custom animation styles and background image for each slide
.slide-#{$i} {
animation: fade#{$i} 10s infinite;
background-image: url(#{$image});
}
// Generate keyframe for each slide
#keyframes fade#{$i} {
#{(($i - 1) / length($images)) * 100%} {
opacity: 0;
}
#{($i / length($images)) * 100%} {
opacity: 1;
}
}
}
See example below (the CSS has been precompiled):
.slider {
margin: 0;
padding: 0;
}
.slide {
position: absolute;
width: 400px;
height: 300px;
background-repeat: no-repeat;
background-size: cover;
opacity: 0;
}
.slide-1 {
animation: fade1 10s infinite;
background-image: url(https://via.placeholder.com/400x300/3077FF/fff?text=Slide1);
}
#keyframes fade1 {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
}
.slide-2 {
animation: fade2 10s infinite;
background-image: url(https://via.placeholder.com/400x300/2C9EE8/fff?text=Slide2);
}
#keyframes fade2 {
20% {
opacity: 0;
}
40% {
opacity: 1;
}
}
.slide-3 {
animation: fade3 10s infinite;
background-image: url(https://via.placeholder.com/400x300/3DE4FF/fff?text=Slide3);
}
#keyframes fade3 {
40% {
opacity: 0;
}
60% {
opacity: 1;
}
}
.slide-4 {
animation: fade4 10s infinite;
background-image: url(https://via.placeholder.com/400x300/2CE8CE/fff?text=Slide4);
}
#keyframes fade4 {
60% {
opacity: 0;
}
80% {
opacity: 1;
}
}
.slide-5 {
animation: fade5 10s infinite;
background-image: url(https://via.placeholder.com/400x300/30FFA8/fff?text=Slide5);
}
#keyframes fade5 {
80% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div class="slider">
<div class="slide slide-1"></div>
<div class="slide slide-2"></div>
<div class="slide slide-3"></div>
<div class="slide slide-4"></div>
<div class="slide slide-5"></div>
</div>
To do a faded transition you need to add percentages to the keyframes. This depicts the percentage of time you would like the image to appear on screen.
For this example you picked three so it would be 100/3 which unfortunately is 33.33333(you get the idea.)
Anyway, here's the updated keyframes for your three images. To adjust these over 10 images you would simply need to 100/10 (10% for each image).
All should start with opacity 0 at 0% then opacity 0 at the starting percentage(in the first image's case it's 33%. Then 0 opacity at 100%.
#keyframes fade1 {
0% {
opacity: 0;
}
33% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes fade2 {
0% {
opacity: 0;
}
33% {
opacity: 0;
}
66% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes fade3 {
0% {
opacity: 0;
}
66% {
opacity: 0;
}
100% {
opacity: 1;
}
}
If you would like further explanation let me know.

rewrite my jquery fadein / fadeout using CSS3 only and running infinite

$(function() {
$('.text1').delay(1000).fadeIn(1500);
$('.text1').delay(600).fadeOut(1500);
$('.text2').delay(5000).fadeIn(1500);
$('.text2').delay(600).fadeOut(1500);
$('.text3').delay(10000).fadeIn(1500);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="text1">Lorem Ipsem</div>
<div class="text2">Lorem Ipsem</div>
<div class="text3">Lorem Ipsem</div>
Above is my simple jQuery animation; simple delay -> fadeIn -> delay -> fadeOut. However I find when trying to create a loop, for my animations to run continuously my code becomes way to large and bulky. I am wondering if it's at all possible to rewrite what I have above with CSS3 only, and then using the infinite option CSS allows.
I've gotten close with CSS below code however, I need to completely hide or fadeOut each line of text before new text shows.
#-webkit-keyframes slider {
0% { opacity: 0.4; }
100% { opacity: 1; }
}
#-moz-keyframes slider {
0% { opacity: 0.4; }
100% { opacity: 1; }
}
#-ms-keyframes slider {
0% { opacity: 0.4; }
100% { opacity: 1; }
}
.slider {
-webkit-animation: slider 1s alternate infinite;
-moz-animation: slider 1s alternate infinite;
-ms-animation: slider 1s alternate infinite;
}
<div class="slider">Lorem Ipsum</div>
As stated in other answers you can not achieve what you are asking using pure CSS solutions.
You can a solution like to an extensible approach (in case you want have many more child elements).
$("#fadeinout div").on("animationend", function() {
_this = jQuery(this);
// remove animation class
_this.removeClass("animate");
// If there is no next element then go to first one otherwise choose next element
var next = (_this.next().length < 1) ? _this.prevAll(':first-child') : _this.next();
// Add class to the new element
next.addClass("animate");
});
#fadeinout div {
width: 100px;
height: 100px;
background: red;
opacity: 0;
margin: 5px;
}
.animate {
animation-name: fadeinout;
animation-duration: 4s;
animation-delay: 0s;
}
#keyframes fadeinout {
50% {
opacity: 1;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="fadeinout">
<div class='animate'></div>
<div></div>
<div></div>
<div></div>
</div>
This is the same example with many child elements animated: https://jsfiddle.net/j4zdgopr/1/
You can't really time the animation of multiple elements in css only. Well you could probably fake it with something like:
div {
width: 50px;
height: 50px;
background: #f00;
opacity: 0;
}
#d1 {
animation: d1 10s infinite;
}
#d2 {
animation: d2 10s infinite;
}
#d3 {
animation: d3 10s infinite;
}
#d4 {
animation: d4 10s infinite;
}
#keyframes d1 {
0% { opacity: 0; }
5% { opacity: 1; }
20% { opacity: 1; }
25% { opacity: 0; }
}
#keyframes d2 {
25% { opacity: 0; }
30% { opacity: 1; }
45% { opacity: 1; }
50% { opacity: 0; }
}
#keyframes d3 {
50% { opacity: 0; }
55% { opacity: 1; }
70% { opacity: 1; }
75% { opacity: 0; }
}
#keyframes d4 {
75% { opacity: 0; }
80% { opacity: 1; }
95% { opacity: 1; }
100% { opacity: 0; }
}
<div id="d1"></div>
<div id="d2"></div>
<div id="d3"></div>
<div id="d4"></div>
...but I would recommend against it. First of all I don't think the timing will be reliable - ie. it will get out of sync. Second your code will most likely be even more bulky than what you have.
So I would recommend a combination of simple CSS transitions and JS like this:
var curslide = 0;
var slides = $("#slider div");
var nextslide = function() {
slides.removeClass('shown');
if (curslide >= slides.length) curslide = 0;
slides.eq(curslide).addClass('shown');
curslide++;
setTimeout(nextslide, 3000);
}
nextslide();
#slider div {
width: 50px;
height: 50px;
background: #f00;
opacity: 0;
transition: opacity .5s linear;
}
#slider div.shown {
opacity: 1;
transition: opacity .5s .5s linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="slider">
<div id="d1"></div>
<div id="d2"></div>
<div id="d3"></div>
<div id="d4"></div>
</div>
With this solution you can add as many frames as needed without modifying the css or js.
I'd try playing with animation-delay, but I think it only applies to the first time the animation is run. After that, unless you write one animation for each .text element, they'll all fade in/out with the same frequency.
Would:
setInterval(function(){
$('.text1').delay(5000).fadeIn(1500);
$('.text2').delay(5000).fadeIn(1500);
$('.text3').delay(5000).fadeIn(1500);
$('.text1').delay(1000).fadeOut(1500);
$('.text2').delay(5000).fadeOut(1500);
}, 11500);
get you somewhere close?

CSS3 Keyframes Issue

So I am trying to get an fade in effect where I want the fade in opacity to start off from 0 and go to 1 but then when it gets played the second time I want it to start from 0.5 and get played to 1. If you need more explanation then please let me know. I have inserted the code below. Thanks
#-webkit-keyframes fadeInCustom {
0% {
opacity: 0;
}
1%{
opacity: 0.1;
}
10%{
opacity: 0.2;
}
30% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
#keyframes fadeInCustom {
0% {
opacity: 0;
}
1%{
opacity: 0.1;
}
10%{
opacity: 0.2;
}
30% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}

Avoid transition in CSS3 animation

Using this kind of simple animation :
<style type="text/css" media="screen">
.item {
-webkit-animation: blink 2s linear 0 infinite;
}
#-webkit-keyframes blink {
from { opacity: 0; }
49.999% { opacity: 0; }
50% { opacity: 1; }
to { opacity: 1; }
}
</style>
<div class="item">Lorem Ipsum</div>
Is there a way to avoid the transition between 0% and 50%, without fixing a value at 49.999% ?
As far as I know, not really
All I can suggest to make your life easier is to shorten it to
#-webkit-keyframes blink {
0%, 49.999% { opacity: 0; }
50% { opacity: 1; }
}

Resources