Web animation・Going further

Start motion on scroll

As you scroll, content softly appears—we'll make that classic effect. The mechanism is simply "add a class when it becomes visible."

As you scroll, photos and text softly appear from below—we’ll make that effect you often see on stylish sites. It looks hard, but the mechanism is the same as the like button from last time. It’s just “add a class when the trigger arrives.” The only difference is that the trigger isn’t a click but entering the screen.

CSS side: prepare the before and after of appearing

First, prepare before appearing (transparent and slightly lower) and after appearing (the normal position) in CSS.

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

opacity: 0 makes it transparent, translateY(24px) shifts it just 24px down. When .is-visible is added, both return to the original—because there’s a transition, that return becomes the “soft” appearance.

JS side: watch for entering the screen

The browser provides a dedicated tool that watches for “whether an element has entered the screen.” That’s IntersectionObserver.

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible');
    }
  });
});

document.querySelectorAll('.reveal').forEach((el) => observer.observe(el));

It looks long, but read line by line it says this.

PartMeaning
new IntersectionObserver(...)Hire one watcher
entry.isIntersecting”Is it on screen right now?” (judged with an if statement)
entry.target.classList.add(...)If it’s in, add a class to that element
observer.observe(el)Ask “please watch this element”

The querySelectorAll in the last line is the catch-them-all version of querySelector. It catches all the elements with .reveal together and registers them one by one with the watcher.

Let’s see it move

The class gets added to elements in order as they enter the screen, and they softly appear. Once something has appeared it stays that way—because we’re using add (only adding) the class.

Summary of this lesson

  1. The scroll effect is really “add a class when it enters the screen”—the same division of roles as the like button
  2. The watcher is IntersectionObserver. Register elements with observe() and judge with isIntersecting
  3. To make it appear once and stay, use classList.add (only adding)

That rounds out the tools for motion. Next time, as the finale, we’ll learn how to deliver that motion considerately, even to people who find motion difficult.

FAQ

How do I make it animate again when I scroll back?
If you remove the class with classList.remove when isIntersecting is false, it resets each time it leaves the screen and replays each time it enters. That said, moving over and over tends to feel noisy, so appearing just once is the standard build.
Which is better, this or calculating the position with a scroll event?
IntersectionObserver is recommended. A scroll event runs a calculation on every scroll and tends to get heavy, but IntersectionObserver lets the browser watch efficiently, so it stays snappy even with many elements.