CSS fade transition (no jQuery) - css

I'm trying to create a visual transition between content changes in a toy SPA I'm writing. To that end, I define a simple class for animating the opacity of an element.
.fade {
transition: opacity 1.5s;
}
In my render function, I now change the opacity of my outlet div after content changes like so:
function render(content) {
var outlet = document.getElementById("outlet");
outlet.classList.remove("fade");
outlet.style.opacity = 0;
outlet.innerHTML = content;
outlet.classList.add("fade");
outlet.style.opacity = 1;
}
Unfortunately, the animation never fires. When I delay changing the opacity to 1 via setTimeout for 10ms, say, it works sometimes if I don't change the content again while the animation is still running, indicating a timing issue/race condition.
I used a similar approach in the past to fade out messages, but there I intentionally delayed changing the opacity by a few seconds so users could read the message before it starts fading out.

Pure CSS animation fadeIn
li {
position: absolute;
top: 50%;
left: 50%;
margin-top: -75px;
}
.logo {
width: 300px;
height: 150px;
background: red;
margin-left: -150px;
z-index: 30;
-webkit-animation: fade-in-slogan 4s .2s ease-in forwards;
-moz-animation: fade-in-slogan 4s .2s ease-in forwards;
animation: fade-in-slogan 4s .2s ease-in forwards;
}
.menu {
width: 600px;
height: 150px;
background: blue;
margin-left: -300px;
opacity: 0;
-webkit-animation: fade-in-menu 3s 4s ease-out forwards;
-moz-animation: fade-in-menu 3s 4s ease-out forwards;
animation: fade-in-menu 3s 4s ease-out forwards;
}
#-webkit-keyframes fade-in-slogan {
0% { opacity: 0; }
30% { opacity: 1; }
50% { opacity: 1; }
70% { opacity: 1; }
100% { opacity: 0; }
}
#-webkit-keyframes fade-in-menu {
0% { display: block; opacity: 0; }
30% { display: block; opacity: .3; }
60% { display: block; opacity: .6; }
80% { display: block; opacity: .8; }
100% { display: block; opacity: 1; }
}
<ul class"main">
<li class="logo"></li>
<li class="menu"></li>
</ul>

Try this, I hope this will solve the issue
.fade{
animation-name: example;
animation-duration: 4s;}
#keyframes example {
from {opacity:1}
to {opacity:0;}
}
div{
width:200px;
height:200px;
background:#000;
}
<html>
<head>
</head>
<body>
<div class="fade"></div>
</body>
</html>

I've solved it now inspired by Muhammad's answer. I defined the fade class as follows:
.fade {
animation-name: fadein;
animation-duration: 1.25s;
#keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
}
Then in the render function, I do
function render(content) {
outlet.classList.remove("fade");
outlet.innerHTML = "";
setTimeout(() => {
outlet.classList.add("fade");
outlet.appendChild(content);
}, 100);
}
Even though this adds an additional delay before the new content actually starts to fade in, it seems the most elegant and concise solution to me.

Related

CSS: animation delay on only one animation

I currently have 3 animations, which I call like this:
animation: 225ms radius-in forwards,
75ms opacity-in forwards,
150ms opacity-out;
Is there a way, using pure css, to delay the "opacity-out" animation, until the radius-in animation is done?
Thanks in advance!
I added a delay of 4 secs to the final animation below. For visibility purpose, I set the duration of each animation to 2 secs.
div {
width: 200px;
height: 200px;
opacity: 0.3;
background-color: darkgray;
animation:2000ms radius-in forwards, 2000ms opacity-in forwards, 2000ms 4000ms opacity-out forwards;
}
#keyframes radius-in {
from { border-radius: 0; }
to { border-radius: 25px; }
}
#keyframes opacity-in {
from { opacity: 0; }
to { opacity: 1; }
}
#keyframes opacity-out {
from { opacity: 1; }
to { opacity: 0.3; }
}
<div></div>

How to make the second element appear after the first one has disappeared?

I want to make the first square appear after 3s and then it needs to disappear. After it disappears, the second square becomes visible after 11s. How to make the second square appear only after the first one has disappeared after 11 seconds?
.one, .two{
background-color: black;
height: 50px;
width: 50px;
}
.one{
animation: fadein 3s, fadeout 7s ;
}
.two{
animation: fadein 11s, fadeout 17s ;
}
#keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}
#keyframes fadeout {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
<div class="one"></div>
<br>
<div class="two"></div>
Use animation-delay maybe?
Also note that you cannot animate the same css attribute in multiple keyframes on the same element. The css defined in the last keyframe will always override the earlier ones. You can try to use % to achieve something similar to what you want.
.one, .two{
background-color: black;
height: 50px;
width: 50px;
opacity: 0;
}
.one{
animation: fadeinout1 10s;
}
.two{
animation: fadeinout2 28s ;
animation-delay: 10s ;
}
#keyframes fadeinout1 {
0%, 100% { opacity: 0; }
30% { opacity: 1; } /*Simulate 3s, out of the whole animation of 10s*/
}
#keyframes fadeinout2 {
0%, 100% { opacity: 0; }
39% { opacity: 1; } /*Simulate 11s, out of the whole animation of 28s*/
}
<div class="one"></div>
<br>
<div class="two"></div>

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?

Opacity Animation for background-image

I'm currently attempting to get the background image of #InnerImage to fade out. Here is the code for #InnerImage:
<div id="InnerImage" style="background-image:url('imgurl.com'););background-repeat:no-repeat;background-position:50% 0%;">
Here's the code that I'm using:
#OuterImage #InnerImage {
-webkit-animation: 3s ease 0s normal forwards 1 fadein;
animation: 3s ease 0s normal forwards 1 fadein;
}
#keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
#-webkit-keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
I'm running into an issue where the code is making every other child(?) div within #InnerImage fade out as well, but I only want the background-image to fade.
I have two questions:
1) I did read that it was not possible for background-image opacity changes that the above code is performing. Is there a work around for this?
2) How do I go about making it so that after the image has been faded in, it fades back out in an infinite loop?
[EDIT]
#OuterImage #InnerImage{
-webkit-animation: 3s ease 0s normal forwards 1 fadein;
animation: 3s ease 0s normal forwards 1 fadein;
animation-iteration-count: infinite;
}
#keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
#-webkit-keyframes fadein{
0% { opacity:0; }
66% { opacity:0; }
100% { opacity:1; }
}
#OuterImage #InnerImage::before {
background: url('imgurl.com') no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0;
right: 0;
bottom: 0;
left: 0;
transition: opacity 1s ease 2s;
z-index: 1;
}
#OuterImage #InnerImage {
position: relative;}
#OuterImage #InnerImage * {
position: relative;
z-index: 2;
}
#OuterImage #InnerImage
Answer to your first question:
Put the background-image on a pseudo element ::before instead:
#InnerImage::before {
background: url('imgurl.com') no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0; right: 0; bottom: 0; left: 0;
z-index: 1;
}
This requires to set position: relative; on #InnerImage:
#InnerImage {
position: relative;
}
and you need to make sure all other child elements are above the pseudo element using z-index (which only applies the way you need if you position those elements):
#InnerImage * {
position: relative;
z-index: 2;
}
Notice: #OuterImage #InnerImage can be safely shortened to #InnerImage since there may be only one element on a page with any given id value anyway. Also I'd advise not to use id selectors in CSS unless you know for sure why you are doing it.
Regarding your animation, it seems like you want it to start only after two seconds have gone by. This can be achieve using a transition like this:
transition: opacity 1s ease 2s;
where 1s is transition-duration and 2s is transition-delay.
https://developer.mozilla.org/en/docs/Web/CSS/transition
Example:
#InnerImage::before {
background: url(http://lorempixel.com/300/200) no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0;
right: 0;
bottom: 0;
left: 0;
transition: opacity 1s ease 2s;
z-index: 1;
}
#InnerImage {
position: relative;
width: 300px;
height: 200px;
}
#InnerImage * {
position: relative;
z-index: 2;
}
#InnerImage:hover::before {
opacity: 0.25;
}
<div id="InnerImage">
<h2>Hey!</h2>
<button>noop</button>
</div>
If you want a permanently on-going fadein-fadeout, you'll have to go with an animation instead of a transition.
#InnerImage::before {
background: url(http://lorempixel.com/300/200) no-repeat center left;
content: "";
position: absolute;
/* the following makes the pseudo element stretch to all sides of host element */
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
animation: 3s ease 0s normal forwards 1 fadein;
animation-iteration-count: infinite;
}
#InnerImage {
position: relative;
width: 300px;
height: 200px;
}
#InnerImage * {
position: relative;
z-index: 2;
}
#keyframes fadein{
0% { opacity:0; }
50% { opacity: 1; }
100% { opacity:0; }
}
<div id="InnerImage">
<h2>Hey!</h2>
<button>noop</button>
</div>
To animate in an infinite loop you can use the animation-iteration-count property and set the value to infinite.
#OuterImage #InnerImage {
-webkit-animation: 3s ease 0s normal forwards 1 fadein;
animation: 3s ease 0s normal forwards 1 fadein;
animation-iteration-count: infinite;
}
Changing the opacity of an element will effect all child elements there is no way around that.
A work around you may consider is to create a element inside #InnerImage that solely handles the background. You set the background div to be position absolute, with a z-index of 0, then animate only this div. That way the other elements will not change in opacity as the animation changes.
#InnerImage {
height:200px;
position:relative;
}
.bg {
position: absolute;
height: 100%;
width: 100%;
background: red;
z-index: 0;
animation-name: fadein;
animation-duration: 6s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
}
.content {
position: relative;
}
#keyframes fadein{
0% { opacity:0; }
50% { opacity:1; }
100% { opacity:0; }
}
<div id="InnerImage">
<div class="bg"></div>
<div class="content">other content</div>
</div>
Note in the example the text content does not fade while the background does

Staggered infinite CSS animation

I was wondering if it was possible to have a looped animation that staggers each time the animation completes one full loop?
.hex{
animation: fio $animation-speed ease-in-out infinite;
transform: scale(.9);
opacity: 0;
&.one{
}
&.two{
animation-delay: $animation-speed * 1;
}
&.three{
animation-delay: $animation-speed * 2;
}
}
#keyframes fio{
0% {
opacity:0;
transform: scale(0.90);
}
50% {
opacity:1;
transform: scale(1.00);
}
100% {
opacity:0;
transform: scale(0.90);
}
}
As you can see from the code, it is currently staggering the first time it goes through the animation, however after that it just fades all 3 elements in and out at the same time. Is it possible to get it to stagger after every loop?
If you need any more information please let me know.
Thanks!
You just need to calculate the whole animation duration with all the delays and set them accordingly like this:
.hex {
animation: fio 1800ms ease-in-out infinite; /* This devided to three is the amount you want for the delay below */
animation-delay: 3600ms; /* All animation delays in one + two + three and add animation duration above to this */
transform: scale(.9);
opacity: 0;
&.one {
animation-delay: 0ms;
width: 50px;
height: 50px;
background-color: red;
}
&.two {
animation-delay: 600ms;
width: 50px;
height: 50px;
background-color: blue;
}
&.three {
animation-delay: 1200ms;
width: 50px;
height: 50px;
background-color: green;
}
}
Fiddle: https://jsfiddle.net/2u43tc8z/2/

Resources