CSS Animation Not Working when Added via JavaScript - css

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>

Related

Iterate animation as a group not as individual animations in CSS

I've written this CSS code that fades in text boxes and then fades them out consecutively. The text boxes are overlapping. I want to loop this animation infinitely, but when I use the animation-iteration-count function, each individual animation iterates and they overlap. I wish to loop the animation only after the last (third) text box has finished its fade-in fade-out cycle.
.fade-container {
position: relative;
}
.fade-box {
position: absolute;
opacity: 0;
animation: fade 3s ease-in-out forwards;
animation-iteration-count: infinite;
}
#keyframes fade {
0% {
opacity: 0;
}
33% {
opacity: 1;
}
66% {
opacity: 0;
}
100% {
opacity: 0;
}
}
.fade-box:nth-child(1) {
animation-delay: 0s;
}
.fade-box:nth-child(2) {
animation-delay: 2s;
}
.fade-box:nth-child(3) {
animation-delay: 4s;
}
<div class="fade-container">
<div class="fade-box">Box 1</div>
<div class="fade-box">Box 2</div>
<div class="fade-box">Box 3</div>
</div>

CSS grid building animation

I would like to build a background animation when a website is opened. I want to create a grid on the whole website, but I also want it to build gradually. Does any body have an idea how I could build this grid gradually?
This is something I wrote for an animation of a single line:
div{
height:0px;
width:1px;
border-bottom:1px solid #000;
-webkit-animation: increase 3s;
-moz-animation: increase 3s;
-o-animation: increase 3s;
animation: increase 3s;
animation-fill-mode: forwards;
}
#keyframes increase {
100% {
width: 300px;
}
}
The problem is I want to do this animation in the background, how can I achieve this?
Another option is to use a rectangle that repeats itself in the background. Is there a way to animate this?(rectangles appearing gradually)
Background image:
Without sample code, can't do much. Here is a CSS approach to do a Grid-like reveal. You could crop your image in squares and use as separate background for each of the boxes, or use one image and set the background-position of each box.
html,
body {
margin: 0;
padding: 0;
}
.grid {
width: 100%;
height: 100vh;
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.block {
border: solid 1px #252525;
opacity: 0;
visibility: hidden;
animation: reveal 1s forwards ease;
}
#keyframes reveal {
100% {
opacity: 1;
visibility: visible;
}
}
.block:nth-child(1) {
animation-delay: 50ms;
}
.block:nth-child(2) {
animation-delay: 100ms;
}
.block:nth-child(3) {
animation-delay: 150ms;
}
.block:nth-child(4) {
animation-delay: 200ms;
}
.block:nth-child(5) {
animation-delay: 250ms;
}
.block:nth-child(6) {
animation-delay: 300ms;
}
.block:nth-child(7) {
animation-delay: 350ms;
}
.block:nth-child(8) {
animation-delay: 400ms;
}
.block:nth-child(9) {
animation-delay: 450ms;
}
<div class="grid">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
</div>

Split animation with Vue

I'm struggling with creating split animation with two icons. I want to split icons with some translation in X axis after hover on container but it seems that I'm doing something wrong. On codepen its not even animating, in my app its working but icons return to their original position after animation, forwards property doesn't help.
<html>
<head>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<div #mouseenter="showButtons()" #mouseleave="hideButtons()" class="container">
<transition name="icon-left">
<span v-show="show_buttons"> A </span>
</transition>
<transition name="icon-right">
<span v-show="show_buttons"> B </span>
</transition>
</div>
</div>
</body>
</html>
const { createApp } = Vue
createApp({
data() {
return {
show_buttons: false,
}
},
methods: {
showButtons() {
this.show_buttons = true
},
hideButtons() {
this.show_buttons = false
}
}
}).mount('#app')
.container {
display: flex;
justify-content: center;
align-items: center;
width: 800px;
height: 400px;
border: 1px black solid ;
}
.icon-left-enter-from {
opacity: 0;
transform: translate(0px);
}
.icon-left-enter-active {
transition: all 0.3s forwards;
}
.icon-left-enter-to {
opacity: 1;
transform: translate(-200px);
}
.icon-right-enter-from {
opacity: 0;
transform: translate(0px);
}
.icon-right-enter-active {
transition: all 0.3s forwards;
}
.icon-right-enter-to {
opacity: 1;
transform: translate(200px);
}
Here is live codepen https://codepen.io/dymek662/pen/bGMxJwY
Here I have it working: https://codepen.io/yoduh/pen/yLjRRRN
I slowed the left one down so you can see the opacity change more clearly. Here's all the relevant code:
<transition name="icon-left" class="left">
<span v-show="show_buttons"> A </span>
</transition>
<transition name="icon-right" class="right">
<span v-show="show_buttons"> B </span>
</transition>
.icon-left-enter-from {
opacity: 0
}
.icon-left-enter-active {
animation: left-translate 3s;
transition: opacity 3s;
}
.left {
transform: translate(-200px);
}
#keyframes left-translate {
0% {
transform: translate(0px);
}
100% {
transform: translate(-200px);
}
}
.icon-right-enter-active {
animation: right-translate 0.3s;
transition: opacity 0.3s;
}
.right {
transform: translate(200px);
}
#keyframes right-translate {
0% {
transform: translate(0px);
}
100% {
transform: translate(200px);
}
}
"forwards" is not used with transition, but with animation instead, specifically it is shorthand for animation-fill-mode. If you want to maintain the end state, you should use animation. However, animation-fill-mode: forwards only holds the final animation state for as long as the animation property exists, e.g. for as long as a hover event is ongoing. In your case, once the animation is complete the animation property is removed. There is a workaround which is to set the "default" state of your element to match the final state of your animation. That's why I added a separate left and right class to always apply the translate transformation as long as the elements are visible (and not currently animating)

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