js/observers.js — IntersectionObserver
In the code column — js/observers.js. Two functions, both built on IntersectionObserver.
revealOnScroll(elements) — cards "fade in" as you scroll. For each card we watch whether it has entered the viewport; when it has, we add the CSS class revealed (the animation lives in style.css).
Three details that separate amateur code from tidy code:
observer.unobserve(entry.target)after the reveal — essential. A card appears once and won't change again; if you never stop observing, the observer "watches" it forever and wastes resources for nothing.prefers-reduced-motion— if the user has disabled animations at the system level (motion sickness), we addrevealedimmediately with no fade. Accessibility, not an option.thresholdandrootMargin— exactly when to fire (when 10% is visible, but 40px before it reaches the bottom).
onReachEnd(sentinel, onReach) shows how the same observer powers infinite scroll: you place an invisible "sentinel" element at the end of the list, and when it appears, you call "load more". That's how every modern feed works.
Verify. With the real pictures from lesson 4:
1. The gallery shows a grid of cards (newest on top).
2. Scrolling down, cards fade in smoothly.
3. Images far down the page only download as you approach (loading="lazy").
Gotcha (watching forever). Forget
unobserve()— and the observer keeps getting called for every card on every scroll, long after they've appeared. The page slows down for no obvious reason. The rule: when the observation's job is done —unobserve(). (The same principle as cleaning up event listeners.)