Skip to content Skip to sidebar Skip to footer

How To Modify Multiple Elements, One After The Other

I'm working on an image fader. I have it so that it fades the image (or in this case div with a background color) selected by the getElementById method, but I'm wondering how I can

Solution 1:

This is what you're looking for:

var interval = 4000,
  collection = document.querySelectorAll('#container>.inner');

for (var i = 0; i < collection.length; i++) {
  (function(i) {
    setTimeout(function() {
      collection[collection.length - i - 1].style.opacity = 0;
    }, i * interval);
  })(i)
}
#container {
  position: relative;
  margin: 0 auto;
  text-align: center;
  width: 350px;
  height: 350px;
  background-color: rgb(200, 200, 200);
}

.inner {
  position: absolute;
  margin: 0 auto;
  left: 25px;
  top: 25px;
  width: 300px;
  height: 300px;
  transition: opacity 4s linear;
}

#one {
  background-color: rgb(100, 100, 100);
}

#two {
  background-color: rgb(0, 160, 230);
}

#three {
  background-color: rgb(0, 255, 130);
}

#four {
  background-color: rgb(255, 130, 255);
}
<divid="container"><divclass="inner"id="one"></div><divclass="inner"id="two"></div><divclass="inner"id="three"></div><divclass="inner"id="four"></div></div>

To give it a more natural feel (impression of intent, gesture, livelyness) you need to change linear to the easing of your choice in CSS:

var interval = 4000,
  collection = document.querySelectorAll('#container>.inner');

for (var i = 0; i < collection.length; i++) {
  (function(i) {
    setTimeout(function() {
      collection[collection.length - i - 1].style.opacity = 0;
    }, i * interval);
  })(i)
}
#container {
  position: relative;
  margin: 0 auto;
  text-align: center;
  width: 350px;
  height: 350px;
  background-color: rgb(200, 200, 200);
}

.inner {
  position: absolute;
  margin: 0 auto;
  left: 25px;
  top: 25px;
  width: 300px;
  height: 300px;
  transition: opacity 4scubic-bezier(.6, 0, .3, 1);
}

#one {
  background-color: rgb(100, 100, 100);
}

#two {
  background-color: rgb(0, 160, 230);
}

#three {
  background-color: rgb(0, 255, 130);
}

#four {
  background-color: rgb(255, 130, 255);
}
<divid="container"><divclass="inner"id="one"></div><divclass="inner"id="two"></div><divclass="inner"id="three"></div><divclass="inner"id="four"></div></div>

Principle: whenever you want to stagger animations (repeat exact same animation on a collection of elements), chaining the start of one animation upon the end of the previous is, to say the least, improper. You are limiting yourself to always having to wait for one animation to end in order to start the next. But you normally want this behavior when the duration of an action is unknown at the time you are executing the script. Here, it's the same duration so chaining is only a useless limitation.

Instead, use setTimeout() on the collection and you will end up having the option of animating multiple elements at any given moment and having better (separated) controls over animation details (duration, timing function and stagger step).

Another big problem with your approach is you're making 20 changes for each element, instead of only one. CSS animations give you control over animation-duration, animation-timing-function (very important when animating movement) and animation-delay (not used here). Besides, it's smoother and lighter on the browser.

I'll exemplify below, by animating movement instead of opacity:

// only set the stagger step and the collection in js// set animation duration and easing in CSS for best resultsvar interval = 63, // stagger step
  collection = document.querySelectorAll('div');
// in your case, use document.querySelectorAll('#container>.inner');for (var i = 0; i < collection.length; i++) {
  (function(i) {
    setTimeout(function() {
      collection[i].style.transform = 'translateX(0)';
    }, i * interval);
  })(i)
}
div {
  background-color: #ddd;
  margin-top: 1px;
  min-height: .5rem;
  transform: translateX(100%);
  /* here it is: duration 300ms, and transition
   * I've put in cubic, as it's good for staggered movement
   * it looks natural. For opacity it doesn't matter
   * it can be linear, ease-out, anything.
   */transition: transform 1scubic-bezier(.5, 0, .1, 1);
}

body {
  overflow-x: hidden;
  margin: 0;
}
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>

Initial answer, before noticing a jQuery free solution is required:

// only set the stagger step and the collection in js// set animation duration and easing in CSS for best resultsvar interval = 42, // stagger step
  collection = $('div'); // in your case, use $('#container>.inner');

collection.each(function(i) {
  setTimeout(function() {
    collection.eq(i).css('opacity', 0);
  }, i * interval);
})
div {
  background-color: #ddd;
  margin-top: 1px;
  min-height: .5rem;
  /* here it is: duration 300ms, and transition
   * I've put in cubic, as it's good for staggered movement
   * it looks natural. For opacity it doesn't matter
   * it can be linear, ease-out, anything.
   */transition: opacity 300mscubic-bezier(.4, 0, .2, 1);
}
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>

End note: This answer did not even touch the new (and promising) way to animate: Web Animations Api, because it's still experimental tech. WAA animates using chaining but provides methods to cancel animation requests. It works in all major browsers and can be used with polyfill in older browsers. It will probably gain huge popularity once Android browsers will support it. Until then, the best way to animate is using CSS animations and transitions which, even if not declaratively, also support canceling a request: you just change the property and it automatically starts a new animation on the same property from the current state, canceling the old one. The only CSS current limitation is that it won't calculate the new duration based on how much of the old one has been completed, which is possible in WAA. What WAA does is unifying CSS animations, CSS transitions and SVG animations under one, common set of specs and will provide a unified set of methods for controlling animations.

Post a Comment for "How To Modify Multiple Elements, One After The Other"