ohvienna ohvienna - 6 months ago 27
CSS Question

Staggered fade-in divs from 0 opacity

I have three divs I fade in based on a waypoint on the page. I am trying to stagger these divs. The issue I'm having is because I am fading them in from opacity: 0, once the 'animated' class is added, all the divs display (and then the delayed divs will play their animation from opacity: 1). This is probably a stupid question but I can't think of a way to delay the opacity on the 2nd and 3rd divs without having to give them individual animated classes. Any help would be much appreciated!

.project {
opacity: 0;
}

.project.animated {
opacity: 1;
animation-name: fadeInDown;
animation-duration: 1s;

&:nth-child(2) {
animation-delay: .3s;
}
&:nth-child(3) {
animation-delay: .6s;
}
}

@keyframes fadeInDown {
from {
opacity: 0;
transform: translate3d(0, -40%, 0);
}

to {
opacity: 1;
transform: none;
}
}


Compiled CSS:

.project {
opacity: 0;
}
.project.animated {
opacity: 1;
animation-name: fadeInDown;
animation-duration: 1s;
}
.project.animated:nth-child(2) {
animation-delay: .3s;
}
.project.animated:nth-child(3) {
animation-delay: .6s;
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translate3d(0, -40%, 0);
}
to {
opacity: 1;
transform: none;
}
}

Answer

Option 1:

Remove the opacity: 1 from the .animated class and add animation-fill-mode: forwards. This setting means that the animated element will maintain the state as at its last keyframe (which has the opacity: 1) and so there is no need for the extra property setting.

window.onload = function() {
  setTimeout(function() {
    var els = document.querySelectorAll('.project');
    for (var i = 0; i < els.length; i++) {
      els[i].classList.add('animated');
    }
  }, 100);
}
.project {
  opacity: 0;
}
.project.animated {
  /*opacity: 1;*/
  animation-name: fadeInDown;
  animation-duration: 1s;
  animation-fill-mode: forwards;
}
.project.animated:nth-child(2) {
  animation-delay: .3s;
}
.project.animated:nth-child(3) {
  animation-delay: .6s;
}
@keyframes fadeInDown {
  from {
    opacity: 0;
    transform: translate3d(0, -40%, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* just for demo */

.project {
  height: 100px;
  width: 100px;
  background: red;
<div class='project'>First</div>
<div class='project'>Second</div>
<div class='project'>Third</div>


Option 2:

If for whatever reasons you don't want to remove the opacity: 1 from the .animated class then set the animation-fill-mode: backwards to the element. This would make the animated element hold the state mentioned in its first keyframe (opacity: 0) during the animation-delay period and hence the element would not show up immediately.

window.onload = function() {
  setTimeout(function() {
    var els = document.querySelectorAll('.project');
    for (var i = 0; i < els.length; i++) {
      els[i].classList.add('animated');
    }
  }, 100);
}
.project {
  opacity: 0;
}
.project.animated {
  opacity: 1;
  animation-name: fadeInDown;
  animation-duration: 1s;
  animation-fill-mode: backwards;
}
.project.animated:nth-child(2) {
  animation-delay: .3s;
}
.project.animated:nth-child(3) {
  animation-delay: .6s;
}
@keyframes fadeInDown {
  from {
    opacity: 0;
    transform: translate3d(0, -40%, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* just for demo */

.project {
  height: 100px;
  width: 100px;
  background: red;
<div class='project'>First</div>
<div class='project'>Second</div>
<div class='project'>Third</div>

Comments