Animate icon sequence and reverse direction in infinite loop - css

I'm trying to animate icons to show this infinite sequence:
1 2 3 2 1 2 3 2 1 2 3 ...
So 1 2 3, then reverse direction back to 1, then reverse up to 3, etc.
This is what I managed to do:
.fader .icon {
animation-name: fade;
animation-iteration-count: infinite;
animation-duration: 3s;
/*animation-direction: alternate;*/
}
#keyframes fade {
0% { opacity: 1; }
33% { opacity: 0; }
66% { opacity: 0; }
100% { opacity: 1; }
}
#icon3 { animation-delay: 0s; }
#icon2 { animation-delay: -1s; }
#icon1 { animation-delay: -2s; }
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.10.2/font/bootstrap-icons.css" />
<div class="fader mt-3 ms-3">
<div class="position-relative">
<span id="icon3" class="icon bi bi-3-square fs-1 position-absolute top-0 start-0"></span>
<span id="icon2" class="icon bi bi-2-square fs-1 position-absolute top-0 start-0"></span>
<span id="icon1" class="icon bi bi-1-square fs-1 position-absolute top-0 start-0"></span>
</div>
</div>
Currently it goes one way only, without "reversing" direction. Any idea how to fix it?

We set it in shorthand using 'alternate' 1-2-3-2-1-infinite.
In longhand it is:
animation-name: fade;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: ease-in-out;
.icon {
position-relative;
animation: fade 4s infinite alternate ease-in-out;
}
#keyframes fade {
0% { opacity: 1; }
25% { opacity: 0; }
50% { opacity: 0; }
75% { opacity: 0; }
100% { opacity: 1; }
}
#icon1 { animation-delay: 0s; }
#icon2 { animation-delay: -1s; }
#icon3 { animation-delay: -2s; }
#icon4 { animation-delay: -3s; }
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.10.2/font/bootstrap-icons.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<div class="fader mt-3 ms-3">
<div>
<span id="icon1" class="icon bi bi-1-square fs-1 position-absolute top-0 start-0"></span>
<span id="icon2" class="icon bi bi-2-square fs-1 position-absolute top-0 start-0"></span>
<span id="icon3" class="icon bi bi-3-square fs-1 position-absolute top-0 start-0"></span>
<span id="icon4" class="icon bi bi-2-square fs-1 position-absolute top-0 start-0"></span>
</div>
</div>

Related

CSS Animation Not Working when Added via JavaScript

I have a web page that is using Bootstrap 5. This web page has one element stacked on top of another. After a period of time, I'm trying to fade-out the top element. In an attempt to do this, I have:
HTML
<div id="host" class="position-relative">
<div id="content" class="position-absolute top-0 left-0 w-100"></div>
<div id="curtain" class="position-relative top-0 left-0 h-100 opacity-100" style="background-color: orange; z-index:1000;">
Loading...
</div>
</div>
CSS
#-webkit-keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
#keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
.fade-out {
-webkit-animation-name: fade-out;
-webkit-animation-duration: 1s;
animation-name: fade-out;
animation-duration: 1s;
}
The other css class are from Bootstrap 5.
This layout works like I want (i.e. the "Loading" is on top of the content). However, the "curtain" doesn't fade out. In an attempt to make it fade out, I have the following:
<script type="text/javascript">
setTimeout(() => {
alert('here');
var curtain = document.getElementById('curtain');
curtain.classList.add('fade-out');
}, 5000);
</script>
The timeout behaves as expected. I've confirmed in Chrome that the fade-out class is getting added to my element. However, the animation is not occurring. What is wrong with my CSS animation?
Nothing is wrong with your code you can add animation-fill-mode: forwards;
so your animation doesn't reset
setTimeout(() => {
var curtain = document.getElementById('curtain');
curtain.classList.add('fade-out');
}, 3000);
#-webkit-keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
#keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.fade-out {
-webkit-animation-name: fade-out;
-webkit-animation-duration: 1s;
animation-name: fade-out;
animation-duration: 1s;
animation-fill-mode: forwards;
}
<div id="host" class="position-relative">
<div id="content" class="position-absolute top-0 left-0 w-100"></div>
<div id="curtain" class="position-relative top-0 left-0 h-100 opacity-100" style="background-color: orange; z-index:1000;">
Loading...
</div>
</div>
If want animation to remain in its last state use forwards in short hand property
setTimeout(() => {
alert('here');
var curtain = document.getElementById('curtain');
curtain.classList.add('fade-out');
}, 5000);
.fade-out-class {
animation: fade-out 3s;
}
#-webkit-keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
#keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.fade-out {
-webkit-animation: fade-out 5s forwards;
animation: fade-out 5s forwards;
}
#curtain {
position: fixed;
top: 0;
left: 0;
height: 5vw;
width: 100vh;
}
<div id="host" class="position-relative">
<div id="content" class="position-absolute top-0 left-0 w-100">You can't see me before as I was under curtain</div>
<div id="curtain" class="position-relative top-0 left-0 h-100 opacity-100" style="background-color: orange; z-index:1000;">
Loading...
</div>
</div>

Timing for opacity keyframe animation

I'm trying to animate the opacity on some simple Font Awesome icons, but I can't get the timing right.
Basically, of the 5 circles, I want the last 3 on either end to animate on together. So, when the far-left 3 are on, the remaining far-right 2 are off and vice versa. I sort of have this happening on the last 2 on either end, but it's not very smooth and I haven't accounted for the middle one yet. I'm reversing the animation on either end, but I'm not sure if I should just create separate keyframes.
Desired pattern: https://youtu.be/zPPhFs1Y4Ts?t=89
#keyframes blinker-skip {
0% {
opacity: 0;
}
10% {
opacity: 0;
}
20% {
opacity: 0;
}
30% {
opacity: 0;
}
40% {
opacity: 0;
}
50% {
opacity: 0;
}
60% {
opacity: 0;
}
70% {
opacity: 1;
}
80% {
opacity: 0;
}
90% {
opacity: 0;
}
100% {
opacity: 0;
}
}
.boosted-led-blink-skip-first {
animation: blinker-skip 1s linear infinite;
}
.boosted-led-blink-skip-second {
animation: blinker-skip 1s linear reverse infinite;
}
.boosted-led-blink-middle {
animation: blinker 1s step-start infinite;
}
.boosted-led-orange {
color: #ff8533;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css">
<div class="boosted-leds">
<span class="boosted-led-orange boosted-led-blink-skip-first boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-skip-first boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-middle boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-skip-second boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-skip-second boosted-led"><i class="fas fa-circle"></i></span>
</div>
Demo: https://codepen.io/ourcore/pen/GRZYjxZ
It looks like you want the dots to show for 50% of the time on one side and then 50% of the time of the other side.
You can do this by having the opacity at 0 from 0-49% and then set it to 1 for 50-100%. You already use reverse for the second set so that will (obviously!) run the opposite way for set 2.
Working example:
.boosted-led-orange {
color: #ff8533;
}
#keyframes blinker-skip {
0% {
opacity: 0;
}
49% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 1;
}
}
.boosted-led-blink-skip-first {
animation: blinker-skip 1s linear infinite;
}
.boosted-led-blink-skip-second {
animation: blinker-skip 1s linear reverse infinite;
}
.boosted-led-blink-middle {
animation: blinker 1s step-start infinite;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css">
<div class="boosted-leds">
<span class="boosted-led-orange boosted-led-blink-skip-first boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-skip-first boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-middle boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-skip-second boosted-led"><i class="fas fa-circle"></i></span>
<span class="boosted-led-orange boosted-led-blink-skip-second boosted-led"><i class="fas fa-circle"></i></span>
</div>
Note that you only need to include the keyframes for the times where the changes occur - there is no need to include the ones in between.
If you are intrested you can do this with one element and without font awesome
.loading {
width:200px;
margin:5px;
background:linear-gradient(#ff8533 0 0) left/60% 100% no-repeat;
-webkit-mask:radial-gradient(circle closest-side, #fff 97%,transparent 100%) 0/calc(100%/5) 100%;
animation: blinker-skip 1s linear infinite;
}
.loading::before {
content:"";
display:block;
padding-top:calc(100%/5 - 5px); /* 5px is the space between circles */
}
#keyframes blinker-skip {
0%,49% {
background-position: left;
}
50%,100% {
background-position: right;
}
}
<div class="loading"></div>
<div class="loading" style="width:150px"></div>
<div class="loading" style="width:120px"></div>

How can I set different animation-delay for all animation's child elements?

I'm trying to give different animation delays to all of my animation container's child elements to make them appear slowly. Here is my project's codepen link: https://codepen.io/emekdev/pen/NWNvLpj
<div id="header-content">
<h1 id="title">Mustafa Kemal Atatürk</h1>
<nav>
<ul>
<li>Early life</li>
<li>Military career</li>
<li>Presidency</li>
<li>Personal life</li>
<li>Illness and death</li>
</ul>
</nav>
</div>
It is my animation div container.
#header-content {
animation-name: header-content-fade-in;
animation-duration: 4s;
animation-fill-mode: forwards;
}
ul:nth-child(1) {animation-delay: .5s;}
ul:nth-child(2) {animation-delay: 1s;}
ul:nth-child(3) {animation-delay: 1.5s;}
ul:nth-child(4) {animation-delay: 2s;}
ul:nth-child(5) {animation-delay: 2.5s;}
In here, I'm trying to give different animation delays to all of my child elements. What am I doing wrong?
Thank you.
li {
animation: header-content-fade-in 4s forwards;
opacity: 0;
}
li:nth-child(1) { animation-delay: 0.5s; }
li:nth-child(2) { animation-delay: 1s; }
li:nth-child(3) { animation-delay: 1.5s; }
li:nth-child(4) { animation-delay: 2s; }
li:nth-child(5) { animation-delay: 2.5s; }
#keyframes header-content-fade-in {
to { opacity: 1; }
}
<div id="header-content">
<h1 id="title">Mustafa Kemal Atatürk</h1>
<nav>
<ul>
<li>Early life</li>
<li>Military career</li>
<li>Presidency</li>
<li>Personal life</li>
<li>Illness and death</li>
</ul>
</nav>
</div>

How to add n-th child class using *ngFor with ionic2,angular2

I am using ionic2. I have an array for product. I am displaying product with grid view.
<ion-row *ngFor="let i of rows" #myElem>
<ion-col class="productlist" col-6 *ngFor="let p of product | slice:(i*2):(i+1)*2" (click)="nav(p.details.id)" >
<div class="product-image">
<img src="{{p.details.P_IMAGES[0].URL}}" alt="Product 1">
</div>
<div class="product-blk">
<div class="product-title">{{p.details.P_TITLE}}</div>
<div class="product-price">
<img src="./assets/images/rupee-yellow.svg" alt="Rupee">{{p.details.PRICE_SALE}}
<span>{{p.details.PRICE_REGULAR}}</span>
</div>
<div class="product-desc">
{{p.Desc}}
</div>
</div>
</ion-col>
</ion-row>
Here is my CSS:
.productlist {
animation: FadeIn 1s linear;
animation-fill-mode: both;
animation-delay: .5s
}
#keyframes FadeIn {
0% {
opacity: 0;
transform: scale(.1);
}
85% {
opacity: 1;
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
It works perfectly, but I need to set animation delay on each grid; I need a custom CSS class like this:
.productlist:nth-child(1),.productlist:nth-child(2),..
How can I do this?
This is the CSS you will need:
.productlist:nth-child(1) {
animation-delay: 1s;
}
.productlist:nth-child(2) {
animation-delay: 2s;
}
.productlist:nth-child(3) {
animation-delay: 3s;
}
.productlist:nth-child(4) {
animation-delay: 4s;
}
You can write a for loop in a CSS preprocessor like Sass, for brevity:
#for $i from 1 through 4 {
.productlist:nth-child(#{$i}){
animation-delay: $i + s;
}
}

Pure CSS crossfade gallery with any number of pictures

I have a slideshow where pictures crossfade automatically in a loop. It is set so that 3 pictures are scrolling.
Demo in Codepen (http://codepen.io/lopis/pen/VYRoKE)
<section class="crossfade">
<article class="slide">
<img src="http://lorempixel.com/400/200/people" alt="" />
</article>
<article class="slide">
<img src="http://lorempixel.com/400/200/cats" alt="" />
</article>
<article class="slide">
<img src="http://lorempixel.com/400/200/sports" alt="" />
</article>
</section>
The CSS:
$slideDuration: 4; // seconds
$slideNum: 3;
#mixin loop($name, $duration, $delay) {
-webkit-animation: $name #{$duration}s #{$delay}s infinite;
-moz-animation: $name #{$duration}s #{$delay}s infinite;
animation: $name #{$duration}s #{$delay}s infinite;
}
#mixin slide() {
#for $i from 1 through $slideNum {
.slide:nth-child( #{$i} ) {
#include loop( crossfade, ($slideNum * $slideDuration), (($i - 1) * $slideDuration) );
}
}
}
#mixin keyframes() {
#-webkit-keyframes crossfade {
0% {
opacity:1;
}
25% {
opacity:1;
}
33% {
opacity:0;
}
86% {
opacity:0;
}
100% {
opacity:1;
}
}
#keyframes crossfade {
0% {
opacity:1;
}
25% {
opacity:1;
}
33% {
opacity:0;
}
86% {
opacity:0;
}
100% {
opacity:1;
}
}
}
.crossfade {
position: relative;
}
.slide {
position: absolute;
top: 0;
}
.slide:first-child {
position: static;
}
#include slide();
#include keyframes();
Is there a way to make an animation like this that would work with any number of slides using just CSS?
Edit: I understand that such dynamism is not intended in CSS but you can have some dynamic content, like by using calc(), etc.
Some libraries, as the one suggested in the comments, allow the use of mixins for this task. This is not what I'm looking for as it requires a rebuild of the source.
You can get this using only CSS, using a content responsive technique
Let's set a time for each slide of 2 seconds.
We need to set a staggered delay for every nth child of 2 seconds. That is easily acieved with nth-child.
Now, we need to increase the duration of the transition depending on the number of elements. Using this technique we achieve this easily.
The third issue is managing the fade-out. In the standard approach, that would involve changing the keyframes changing point, and it would be cumbersome. The trick to get this working with much less code, is to make a z-index movement in the animation itself. The elements are moving backward, and then we don't care about their opacity anymore
Example set only for 3 posible number of elements:
.container {
width: 100px;
height: 50px;
position: relative;
margin: 10px;
display: inline-block;
}
.element {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
animation: anim 6s infinite;
}
.element:nth-child(1) {
background-color: lightyellow;
animation-delay: 0s;
}
.element:nth-child(2) {
background-color: lightgreen;
animation-delay: 2s;
}
.element:nth-child(3) {
background-color: pink;
animation-delay: 4s;
}
.element:nth-child(4) {
background-color: lightblue;
animation-delay: 6s;
}
.element:nth-child(5) {
background-color: coral;
animation-delay: 8s;
}
.element:nth-child(6) {
background-color: aliceblue;
animation-delay: 10s;
}
.element:nth-child(7) {
background-color: burlywood;
animation-delay: 12s;
}
.element:nth-child(8) {
background-color: bisque;
animation-delay: 14s;
}
.element:nth-child(9) {
background-color: beige;
animation-delay: 16s;
}
.element:nth-last-child(3):first-child,
.element:nth-last-child(3):first-child ~ .element {
animation-duration: 6s;
}
.element:nth-last-child(6):first-child,
.element:nth-last-child(6):first-child ~ .element {
animation-duration: 12s;
}
.element:nth-last-child(9):first-child,
.element:nth-last-child(9):first-child ~ .element {
animation-duration: 18s;
}
#keyframes anim {
0% { opacity: 0; z-index: 100;}
15% { opacity: 1;}
50% { opacity: 1;}
100% { opacity: 0; z-index: 1;}
}
<div class="container">
<div class="element">ONE</div>
<div class="element">TWO</div>
<div class="element">THREE</div>
</div>
<div class="container">
<div class="element">ONE</div>
<div class="element">TWO</div>
<div class="element">THREE</div>
<div class="element">FOUR</div>
<div class="element">FIVE</div>
<div class="element">SIX</div>
</div>
<div class="container">
<div class="element">ONE</div>
<div class="element">TWO</div>
<div class="element">THREE</div>
<div class="element">FOUR</div>
<div class="element">FIVE</div>
<div class="element">SIX</div>
<div class="element">SEVEN</div>
<div class="element">EIGHT</div>
<div class="element">NINE</div>
</div>

Resources