<main>
<article>
<h2>So...</h2>
<h3>We need to talk</h3>
</article>
<article>
<h2>I started this thing</h2>
</article>
<article>
<h2>It's called</h2>
</article>
<article>
<h2><a href="https://webanimation.blog">webanimation.blog</a></h2>
</article>
</main>
main {
scroll-snap-type: y mandatory;
position: relative;
max-height: 100vh;
overflow-y: auto;
}
article {
height: 100vh;
width: 100vw;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
scroll-snap-align: start;
}
article:nth-of-type(1) {
background-color: rgba(0, 82, 178, 1);
}
article:nth-of-type(2) {
background-color: rgba(255, 164, 0, 1);
}
article:nth-of-type(3) {
background-color: rgba(144, 195, 255, 1);
}
article:nth-of-type(4) {
background-color: rgba(255, 173, 25, 1);
}
h2,
h3, a {
font: 400 3rem/1.5 sans-serif;
color: white;
transform-origin: center;
text-decoration: none;
}
h3 {
font: 400 2em/1.5 sans-serif;
}
View Compiled
gsap.set("main article *", { autoAlpha: 0, y: "1rem" });
const animateVisible = (block, ratio, isIntersecting) => {
if (ratio > 0 && isIntersecting) {
gsap.to(block.querySelectorAll("*"), {
duration: 1,
autoAlpha: 1,
y: "0",
stagger: 0.3,
ease: "power3.inOut"
});
} else {
gsap.set(block.querySelectorAll("*"), {
autoAlpha: 0,
y: "1rem"
});
}
};
const blocks = document.querySelectorAll("main article");
const blocksObserver = new IntersectionObserver(
(entries) => {
return entries.forEach((event) => {
const { target, intersectionRatio, isIntersecting } = event;
animateVisible(target, intersectionRatio, isIntersecting);
});
},
{ threshold: 0.5 }
);
for (const block of blocks) {
blocksObserver.observe(block);
}
View Compiled
This Pen doesn't use any external CSS resources.