Advanced Animation Practice
You have been reading about scroll-driven animations, the View Transitions API, the Web Animations API, and accessibility considerations for motion. This assignment gives you a pre-built page to bring to life using those techniques. The markup, layout, visual design, and all JavaScript are already done. Your job is entirely in CSS.
The starter files include a fully styled showcase page with a reading progress bar, a filterable card gallery, and a series of alternating feature sections. The JavaScript that powers the gallery filter and the hero entrance animation is pre-written so you can see how WAAPI and the View Transitions API work in practice. Your task is to write the CSS that makes everything animate correctly and accessibly.
Preparation
Download the starter files and add them to your portfolio repository under the following path:
portfolio/
└── unit-5/
└── advanced-animation-practice/
├── css/
│ ├── base.css
│ ├── animations.css
│ └── transitions.css
├── js/
│ └── gallery.js
└── index.html
Open index.html in your browser. The page is fully styled but nothing moves yet. The hero text, cards, and feature sections all start invisible because base.css sets them to their animation starting states. Your work lives entirely in animations.css and transitions.css, both of which contain TODO comments marking exactly where each implementation goes. base.css, index.html, and gallery.js are complete and do not need to be modified.
Before writing any CSS, open gallery.js and read through it. The filter logic wraps its DOM update in document.startViewTransition(), and the hero entrance uses Element.animate() with staggered delays. You will not be writing any of this JavaScript, but understanding what it does will help you write the CSS that completes each effect.
Assignment Instructions
1. Reading Progress Bar
The header contains a thin bar with the class .progress-bar. It is already positioned correctly in base.css and has transform-origin: left set so any scale starts from the left edge. In animations.css, write a @keyframes rule that animates transform: scaleX() from 0 to 1, then apply it to .progress-bar using animation-timeline: scroll(root block). Do not set animation-duration; when a scroll timeline drives playback, duration is meaningless and should be omitted.
Animating transform: scaleX() is significantly more performant than animating width directly. Transforms are handled on the compositor thread and never trigger layout recalculation, which keeps the animation smooth even on slower devices.
2. Card Entrance Animations
Each card in the gallery has the class .card. In animations.css, write a @keyframes rule that fades a card in and translates it upward by a modest amount, then apply it to .card using animation-timeline: view(). Set animation-range: entry 0% entry 50% to constrain the effect to the entry phase. Without this, the animation would reverse as each card continues scrolling up through the viewport. Add animation-fill-mode: both so cards that have not yet entered the viewport remain invisible rather than snapping to their visible state before the animation begins.
3. Feature Section Reveals
The feature sections below the gallery alternate between two classes: .feature-section--left and .feature-section--right. In animations.css, write two separate @keyframes rules that slide each variant in from its respective side, then apply them using animation-timeline: view() with the same animation-range approach you used for the cards. Keep the translate distance around 3rem so the effect feels polished rather than dramatic.
4. View Transition Styling
The gallery filter is already wired to document.startViewTransition() in gallery.js. Click any filter button and you will see the browser's default cross-fade. Open transitions.css and find the TODO comment there. Customize the ::view-transition-old(root) and ::view-transition-new(root) pseudo-elements so the transition uses a duration and easing that feels intentional rather than the generic browser default. Experiment with different values until the filter change feels smooth and purposeful.
5. Reduced Motion Support
Open animations.css and find the @media (prefers-reduced-motion: reduce) block near the bottom of the file. It is already there with a TODO comment; it just needs content. Inside it, disable all scroll-driven animations by setting animation: none on .progress-bar, .card, .feature-section--left, and .feature-section--right. Because those elements start from an invisible or offset state in base.css, removing the animation alone will leave them invisible or visually broken. You must also restore their final visible values explicitly: opacity: 1 and transform: none.
The JavaScript in gallery.js already checks prefers-reduced-motion and skips the WAAPI hero entrance when it is set, so the hero elements are handled for you. Your CSS block covers everything else.
Enable reduced motion in your operating system accessibility settings and reload the page. On macOS this is under Accessibility → Display. On Windows it is under Ease of Access → Display. Chrome DevTools also lets you emulate the preference under the Rendering panel without changing your system settings. Nothing on the page should animate, and nothing should be invisible or visually broken.
Submission
Once you have completed all five steps and confirmed the page works correctly with reduced motion enabled, fill out the form below. Download the PDF and submit it to Canvas.
Live page:
The progress bar uses scroll() and the card entrances use view(), but both are scroll-driven timelines. Explain the conceptual difference between the two functions and why each one was the correct choice for its element.
Setting animation: none is not sufficient on its own when elements start from an invisible or offset state. Explain specifically what you had to do beyond removing the animation to ensure all elements remained visible and correctly positioned for users who prefer reduced motion.