<div class="container">
	<h1>Here's some easy to implement scroll animations</h1>
	<p>By using transformations instead of absolute positioning, you can keep using relative positions. Not compatible with IE.</p>
	<h2>Fade in animations</h2>
	<br>
	<div class="box fade-right-desktop fade-up-mobile animation">
		<p>Fade right on desktop, fade up on mobile</p>
	</div>
	<br><br>
	<div class="box fade-left-desktop fade-down-mobile animation">
		<p>Fade left on desktop, fade down on mobile</p>
	</div>
	<br><br>
	<div class="box fade-down-desktop fade-mobile animation">
		<p>Fade down on desktop, simple fade on mobile</p>
	</div>
	<br><br>
	<div class="box fade-up-desktop fade-mobile animation">
		<p>Fade up on desktop, simple fade on mobile</p>
	</div>
	<br><br>
	<h2>Grow animations</h2>
	<p>These require an empty element, or you could alter the code to use pseudo elements.</p>
	<br>
	<div class="box-wrapper">
		<div class="box-background grow-down-desktop grow-up-mobile animation"></div>
		<p>Grow down on desktop, grow up on mobile</p>
	</div>
	<br><br>
	<div class="box-wrapper">
		<div class="box-background grow-left-desktop grow-down-mobile animation"></div>
		<p>Grow left on desktop, grow down on mobile</p>
	</div>
	<br><br>
	<div class="box-wrapper">
		<div class="box-background grow-right-desktop grow-up-mobile animation"></div>
		<p>Grow right on desktop, grow up on mobile</p>
	</div>
	<br><br>
	<div class="box-wrapper">
		<div class="box-background grow-up-desktop grow-down-mobile animation"></div>
		<p>Grow up on desktop, grow down on mobile</p>
	</div>
	<br><br>
	<h2>You can also stagger animations.</h2>
	<p>By adding on a transition delay property to each box. Since it doesn't make sense to delay on mobile, it will just fade in.</p>
	<div class="boxes-row">
		<div class="fade-down-desktop fade-mobile animation">
			<div class="card">
				<img src="https://picsum.photos/200/300" />
				<div class="card-content">
					No delay
				</div>
			</div>
		</div>
		<div class="fade-up-desktop fade-mobile animation stagger-desktop-1">
			<div class="card">
				<img src="https://picsum.photos/200/300?random=1" />
				<div class="card-content">
					Delayed 300ms
				</div>
			</div>
		</div>
		<div class="fade-left-desktop fade-mobile animation stagger-desktop-2">
			<div class="card">
				<img src="https://picsum.photos/200/300?random=2" />
				<div class="card-content">
					Delayed 600ms
				</div>
			</div>
		</div>
		<div class="fade-right-desktop fade-mobile animation stagger-desktop-3">
			<div class="card">
				<img src="https://picsum.photos/200/300?random=3" />
				<div class="card-content">
					Delayed 900ms
				</div>
			</div>
		</div>
		<div class="fade-up-desktop fade-mobile animation stagger-desktop-4">
			<div class="card">
				<img src="https://picsum.photos/200/300?random=4" />
				<div class="card-content">
					Delayed 1200ms
				</div>
			</div>
		</div>
	</div>
	<br><br>
	<h2>And you can combine them to make something interesting.</h2>
	<br>
	<div class="box-wrapper">
		<div class="box-background showcase grow-right-desktop grow-down-mobile animation"></div>
		<img class="fade-left-desktop fade-up-mobile animation stagger-desktop-1 showcase" src="https://picsum.photos/400" />
	</div>
</div>
/* Animation Code */
.animation {
	will-change: transform;
}

@media screen and (min-width: 768px) {
	.fade-left-desktop,
	.fade-right-desktop {
		opacity: 0;
		transition: 1500ms all ease-in-out;
	}
	.fade-left-desktop {
		transform: translateX(50px);
	}
	.fade-right-desktop {
		transform: translateX(-50px);
	}
	.fade-left-desktop.animate,
	.fade-right-desktop.animate {
		opacity: 1;
		transform: translateX(0);
	}
	.fade-down-desktop,
	.fade-up-desktop {
		opacity: 0;
		transition: 1500ms all ease-in-out;
		transform: translateY(50px);
	}
	.fade-up-desktop {
		transform: translateY(50px);
	}
	.fade-down-desktop {
		transform: translateY(-50px);
	}
	.fade-down-desktop.animate,
	.fade-up-desktop.animate {
		opacity: 1;
		transform: translateY(0);
	}
	.grow-left-desktop,
	.grow-right-desktop {
		transform: scaleX(0);
		transform-origin: left;
		transition: 1200ms all ease-in-out;
	}
	.grow-left-desktop {
		transform-origin: right;
	}
	.grow-right-desktop {
		transform-origin: left;
	}
	.grow-left-desktop.animate,
	.grow-right-desktop.animate {
		transform: scaleX(1);
	}
	.grow-down-desktop,
	.grow-up-desktop {
		transform: scaleY(0);
		transition: 1200ms all ease-in-out;
	}
	.grow-up-desktop {
		transform-origin: bottom;
	}
	.grow-down-desktop {
		transform-origin: top;
	}
	.grow-down-desktop.animate,
	.grow-up-desktop.animate {
		transform: scaleY(1);
	}
	.stagger-desktop-1 {
		transition-delay: 300ms;
	}
	.stagger-desktop-2 {
		transition-delay: 600ms;
	}
	.stagger-desktop-3 {
		transition-delay: 900ms;
	}
	.stagger-desktop-4 {
		transition-delay: 1200ms;
	}
}
@media screen and (max-width: 767px) {
	.fade-down-mobile,
	.fade-up-mobile {
		opacity: 0;
		transition: 1500ms all ease-in-out;
	}
	.fade-up-mobile {
		transform: translateY(50px);
	}
	.fade-down-mobile {
		transform: translateY(-50px);
	}
	.fade-down-mobile.animate,
	.fade-up-mobile.animate {
		opacity: 1;
		transform: translateY(0);
	}
	.grow-left-mobile,
	.grow-right-mobile {
		transform: scaleX(0);
		transition: 1200ms all ease-in-out;
	}
	.grow-left-mobile {
		transform-origin: right;
	}
	.grow-right-mobile {
		transform-origin: left;
	}
	.grow-left-mobile.animate,
	.grow-right-mobile.animate {
		transform: scaleX(1);
	}
	.grow-down-mobile,
	.grow-up-mobile {
		transform: scaleY(0);
		transform-origin: top;
		transition: 1200ms all ease-in-out;
	}
	.grow-up-mobile {
		transform-origin: bottom;
	}
	.grow-down-mobile {
		transform-origin: top;
	}
	.grow-down-mobile.animate,
	.grow-up-mobile.animate {
		transform: scaleY(1);
	}
	.fade-mobile {
		opacity: 0;
		transition: 1000ms all ease-in-out;
	}
	.fade-mobile.animate {
		opacity: 1;
	}
}

body {
	background-color: #defff2;
	margin: 0;
	padding: 0;
	width: 100%;
}

/* Page Styles */
.container {
	max-width: 1200px;
	width: 100%;
	margin: 0 auto;
	padding: 2rem 1rem 5rem;
}
.box {
	width: 400px;
	padding: 3rem;
	background-color: #041f1e;
	color: #03cea4;
	border-radius: 10px;
}
.box-wrapper {
	position: relative;
	width: 400px;
	padding: 3rem;
	color: #041f1e;
}
.box-wrapper p {
	z-index: 1;
	position: relative;
}
.box-wrapper img {
	z-index: 1;
	position: relative;
	border-radius: 10px;
}
.box-background {
	background-color: #03cea4;
	border-radius: 10px;
	height: 100%;
	width: 100%;
	position: absolute;
	left: 0;
	top: 0;
	z-index: 0;
}
.boxes-row {
	margin-top: 3rem;
	display: flex;
	justify-content: space-between;
	align-items: center;
}
.boxes-row > div {
	border: 1px solid #fafafa;
	border-radius: 10px;
	overflow: hidden;
	width: 100%;
	margin: 0.5rem;
}
.card {
	display: flex;
	flex-direction: column;
}
.card img {
	width: 100%;
	height: 200px;
}
.card-content {
	background-color: #fff;
	padding: 1rem;
}
.box-background.showcase {
	width: 400px;
	height: 400px;
}
img.showcase {
	width: 400px;
	height: 400px;
	object-fit: cover;
}
@media screen and (max-width: 767px) {
	.box,
	.box-wrapper {
		max-width: 300px;
		width: 100%;
		margin: 0 auto;
	}
	.boxes-row {
		flex-direction: column;
		flex-wrap: wrap;
	}
	.boxes-row > div {
		margin-bottom: 2rem;
		width: 100%;
		max-width: 300px;
	}
}
// Reverted back to non-arrow functions because it would break IE11 completely.

var observer = new IntersectionObserver(
	function (entries) {
		entries.forEach(function (entry) {
			var el = entry.target;
			if (entry.isIntersecting) {
				el.classList.add("animate");
				return;
			}
		});
	},
	{ threshold: 0.2 }
);

document.querySelectorAll(".animation").forEach(function (i) {
	if (i) {
		observer.observe(i);
	}
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.