<div class="container scroll-group--image">

  <div class="text">

    <h1>Simple scroll animation with IntersectionObserver API (with setTimeout delay)</h1>

    <p>Scroll down past this text to see the scroll transition in action.</p>

  </div>

  <img class="image" src='https://images.unsplash.com/photo-1524946274118-e7680e33ccc5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNDcwMA&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

  <img class="image" src='https://images.unsplash.com/photo-1437719417032-8595fd9e9dc6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNDcwMA&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

  <img class="image" src='https://images.unsplash.com/photo-1505738093940-b187b0e6d6d9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNDcwMA&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

  <img class="image" src='https://images.unsplash.com/photo-1453872302360-eed3c5f8ff66?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNDcwMA&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

  <img class="image" src='https://images.unsplash.com/photo-1521170813716-0b3f42fcfb65?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNzM5NQ&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

  <img class="image" src='https://images.unsplash.com/photo-1516633630673-67bbad747022?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNzM5NQ&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

  <img class="image" src='https://images.unsplash.com/photo-1524946274118-e7680e33ccc5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNDcwMA&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

  <img class="image" src='https://images.unsplash.com/photo-1437719417032-8595fd9e9dc6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyODUzNDcwMA&ixlib=rb-1.2.1&q=80&w=1200' alt=''>

</div>
.scroll {

	opacity: 0;
	transition: all 1s ease-out;
	transform: translate3d(0, 2rem, 0);

}

.scrolled-in {
	
	opacity: 1;
	transform: translate3d(0, 0, 0);

}

/* demo styles */
body {
  margin: 0;  
}

.container {
  display: flex;
  flex-wrap: wrap;
}

.text {
  display: grid;
  place-items: center;
  min-height: 100vh;
  width: 90%;
  background: #eeeeee;
  padding: 5vw;
  margin: 5vw;
  box-sizing: border-box;
}

img {
  display: inline-block;
  max-width: 25%;
  height: auto;
  margin: 0;
}

h1 {
  font-size: 7vw;
  margin: 10vw;
}

p {
  font-size: 5vw;
  margin: 10vw;
}
View Compiled
document.addEventListener("DOMContentLoaded", function(event) { 

	// get all the scroll-group elemetns.
	scrollGroups = document.querySelectorAll('[class*="scroll-group"]');

	// for each scroll-group element.
  scrollGroups.forEach(el => {
		
		// create an array from the element classes.
		var elClasses = el.className.split ( ' ' );

		// for each of the classes in the array.
		for ( var index in elClasses ) {
	
			// if the class contains the 'scroll-group-' string.
			if ( elClasses[index].match ( /^scroll-group-/ ) ) {
	
				// get the string that follows after the '--' split.
				var targetClassName = elClasses[index].split ( '--' )[1];
	
				// get the children of the element that have the target classname.
				children = el.querySelectorAll('.' + targetClassName);
	
				// for each of the children with the target classname.
				children.forEach(el => {

					// add the 'scroll' class.
					el.classList.add("scroll");
				});
	
				break;
	
			}
		}	
	});

	// get all of the elements with the 'scroll' class.
	const scrollList = document.querySelectorAll(".scroll, [class*='scroll-group']")

	const callback = (entries, observer) => {

		var delay = 0;

		entries.forEach((entry) => {

			if (entry.isIntersecting) {

				setTimeout(function () {
                    // add the class that triggers the animation
                    entry.target.classList.add("scrolled-in");

                }, delay);

                // increase the delay to allow a cascading effect for the elements
                delay += 500; // in milliseconds

			}
	  	})
	}
	
	const options = {}
	
	const myObserver = new IntersectionObserver(callback, options)

	scrollList.forEach(scrollItem => {
		myObserver.observe(scrollItem)
	})

});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.