UNIT 17 • STAGE 7 OF 7
Complete the site: IntersectionObserver scroll animations, Today section, and era series footer
Stage 7 completes the Termination Era site. You will add the Today section with three cards and a reflection card, the site footer with the era series navigation, and your first look at the IntersectionObserver API: JavaScript that watches elements and triggers an animation when they scroll into view.
The IntersectionObserver is this unit's new JavaScript concept. It is a browser API that lets you know when an element enters or leaves the visible portion of the screen. You have used addEventListener for user-triggered events (clicks, form submissions). The IntersectionObserver handles something different: a scroll-triggered event that fires automatically based on what the browser can see.
You create an observer object with new IntersectionObserver(callback, options). The callback runs whenever a watched element enters or exits the viewport. Inside the callback, you check entry.isIntersecting to know if the element just became visible. You then add a class, and call observer.unobserve(entry.target) so the animation only triggers once. You register elements to watch with observer.observe(el).
Before writing the JavaScript, set up the CSS states. Elements start invisible and slightly shifted down. When JavaScript adds the .visible class, the CSS transition animates them in.
[data-fade]: An attribute selector. It targets any element that has a data-fade HTML attribute, regardless of the element's tag or class. This is more flexible than a class: you can add data-fade to any element without changing its class list, and the selector applies automatically.transform: translateY(24px): Shifts the element 24 pixels downward from its normal position. Combined with opacity: 0, the element is both invisible and slightly below where it will land. When it transitions to translateY(0), it slides up as it fades in.transition: opacity 0.6s ease, transform 0.6s ease: Animates both properties simultaneously over 0.6 seconds. The ease timing function starts fast and decelerates, which feels natural for a scroll reveal.The script goes at the bottom of your HTML, before the closing </body> tag. It creates an observer, tells it what to do when an element becomes visible, and registers all [data-fade] elements.
new IntersectionObserver(callback, options): Creates the observer. The callback is a function that receives an array of entries, one per element that changed visibility. The options object configures the observer; threshold: 0.15 means "fire when at least 15% of the element is visible."entry.isIntersecting: A boolean. true means the element just entered the viewport; false means it just left. You only want to add .visible on entry, so you check if (entry.isIntersecting).entry.target: The specific DOM element that triggered this entry. Since the observer watches multiple elements, entry.target tells you which one just became visible.fadeObserver.unobserve(entry.target): Stops watching this element after it has been seen once. Without this, the observer would keep firing every time the element scrolled in and out, toggling the class on and off. One-time animations should call unobserve.document.querySelectorAll('[data-fade]'): Selects all elements with the data-fade attribute. The .forEach loop then registers each one with observer.observe(el). Any element you add data-fade to in the HTML will automatically be watched.The Today section grid and reflection card follow the same patterns as Units 13, 14, and 15. The footer uses a 2fr 1fr 1fr grid with the era series pill navigation in the footer-bottom row. Add data-fade to each .today-card and the .reflection-card to activate the scroll animation.
border-left: 4px solid var(--gold) with border-radius: 0 12px 12px 0: The left side is flat (0) because the border-left creates a visual edge there. The right side is rounded. This is the same pattern as the sovereignty callout in Stage 5: a left-border accent card where the flat left aligns with the accent line.border-top usages at different layout levels: .site-footer uses border-top to separate the footer from the section above it. .footer-bottom uses a second border-top to separate the copyright row from the footer columns above. Same property, different purpose, different level of the layout.grid-template-columns: 2fr 1fr 1fr: The brand/description column gets twice the space of each link column. 2 + 1 + 1 = 4 parts. The brand column is 50%, each link column is 25%. The proportional split gives the description room for a few sentences without cramping the link lists.The Today section and footer are pre-built. Add data-fade to the three .today-card elements and the .reflection-card in the HTML, then verify in the preview that the cards start invisible and animate in as you scroll down to them. The section intro has a REPLACE comment.
[data-fade] CSS is in the stylesheet and that you added data-fade to the HTML elements.index.html page in a new tab and use the pill navigation.Your Termination Era research site is done. You have covered the policy (HCR 108, PL 280, Dillon Myer), the scale (109 nations, 1.36 million acres), the relocation program and AIM's founding, the Menominee and Klamath nation profiles, your own nation research, and the present-day record. You have also learned IntersectionObserver, your first browser observation API.
This site will become one of seven era sections in your Unit 18 capstone project. Save it and keep your sources.