Color Mode

Animated Navigation

Navigation is one of the most interaction-heavy parts of any interface, and it is where motion design has the most direct impact on how polished a site feels. A slide-out menu that snaps open without animation feels broken. One that glides in with a well-chosen easing curve feels intentional and professional. In this assignment you will build exactly that: a responsive navigation with a slide-out menu driven entirely by CSS transitions and keyframe animations.

Alongside the navigation you will implement two additional animated components — buttons and cards — that reinforce the same principles in different contexts. All your work lives in CSS. The HTML and JavaScript are complete and provided for you.

Setup Instructions

Download the assignment files and add them to your portfolio repository. The package includes a complete HTML page, a JavaScript file that handles menu toggle logic, base CSS files, and three component CSS files where your work happens. All HTML is complete; do not modify it.

1. Download and Extract

Download animated-navigation.zip and extract it. The package contains:


        animated-navigation/
        ├── css/
        │   ├── base/
        │   │   ├── reset.css          # complete, do not modify
        │   │   ├── variables.css      # complete, do not modify
        │   │   └── typography.css     # complete, do not modify
        │   ├── layout/
        │   │   └── page.css           # complete, do not modify
        │   └── components/
        │       ├── nav.css            # your work here
        │       ├── buttons.css        # your work here
        │       └── card.css           # your work here
        ├── js/
        │   └── nav.js             # complete, do not modify
        └── index.html             # complete, do not modify
    

2. Add to Your Portfolio

Move the extracted folder into your portfolio repository under the correct unit directory:


        portfolio/
        └── unit-5/
            └── animated-navigation/
                ├── css/
                ├── js/
                └── index.html
    

3. Open and Examine the Files

Open index.html in your browser to see the unstyled page. Read through each component CSS file from top to bottom — every section has detailed TODO comments explaining exactly what to implement and why. Open js/nav.js to understand what JavaScript does: it adds and removes the is-open class on the menu and overlay, and toggles aria-expanded on the hamburger button. Your CSS listens for those changes.

Assignment Instructions

1. Style and Animate the Navigation Header

Work in css/components/nav.css. Start with the .site-header and .site-nav: the header should be fixed to the top of the viewport with a background and appropriate z-index. The nav should be a flex row with the logo on the left and links on the right, sized to var(--nav-height).

Style the desktop .nav-link elements with a hover transition. Think carefully about what to transition: color is simple and effective, or you can build an underline that grows in from the left using a pseudo-element with a width transition. Whatever you choose, keep the duration around 200ms.

Desktop links hide on mobile

The .nav-links list should be hidden below 768px. The slide menu replaces it at that breakpoint. Hide it with display: none inside a media query — the hamburger button takes over on mobile.

2. Build the Hamburger Button

The .nav-toggle button contains three .hamburger-line spans. Style them as horizontal bars stacked vertically with consistent spacing to form the classic hamburger icon. The button should only be visible on mobile (below 768px).

When the menu opens, JavaScript sets aria-expanded="true" on the button. Use that attribute in your CSS to animate the lines into an X shape using transform. The first line rotates and translates down to cross the third, the middle line fades out, and the third rotates and translates up:


        .nav-toggle[aria-expanded="true"] .hamburger-line:nth-child(1) {
            transform: translateY(8px) rotate(45deg);
        }

        .nav-toggle[aria-expanded="true"] .hamburger-line:nth-child(2) {
            opacity: 0;
        }

        .nav-toggle[aria-expanded="true"] .hamburger-line:nth-child(3) {
            transform: translateY(-8px) rotate(-45deg);
        }
    

Transition transform and opacity on the base .hamburger-line so the animation plays in both directions.

3. Build the Slide-Out Menu

The .slide-menu panel should be fixed, full-height, and var(--slide-menu-width) wide. In its default state it sits completely off-screen to the right using transform: translateX(100%). When JavaScript adds .is-open, it slides in with transform: translateX(0).

Place the transition on the base .slide-menu element so it animates in both directions. Use ease-out for a natural deceleration as the panel arrives. A duration of 300–350ms feels responsive without being rushed.

Use transform, not left or right

Animating right: -100% to right: 0 triggers layout recalculation on every frame. Animating translateX runs entirely on the GPU compositor. Always use transform for sliding panels.

4. Add Staggered Link Entrance Animation

Inside the slide menu, each .slide-menu-link should animate in after the panel arrives. Write a @keyframes rule that fades each link in while sliding it slightly from the right. Apply the animation only when .is-open is present on the parent:


        @keyframes link-enter {
            from {
                opacity: 0;
                transform: translateX(16px);
            }
            to {
                opacity: 1;
                transform: translateX(0);
            }
        }

        .slide-menu.is-open .slide-menu-link {
            animation: link-enter 250ms ease-out forwards;
        }
    

Apply increasing animation-delay values to each link using :nth-child so they stagger in one after another. A delay increment of around 50ms per item works well. Set the base .slide-menu-link to opacity: 0 so links are hidden when the menu is closed and ready to animate again on the next open.

5. Style and Animate the Overlay

The .slide-overlay should cover the full viewport with a semi-transparent dark background. By default it should be invisible and non-interactive (opacity: 0; pointer-events: none). When JavaScript adds .is-open, fade it in. Transition opacity with a duration that matches or slightly trails the slide panel.

6. Animated Buttons

Work in css/components/buttons.css. Implement the four button variants: .btn-primary, .btn-ghost, .btn-icon, and .btn-loading. Each has detailed TODO comments in the CSS file. The key requirements:

7. Animated Cards

Work in css/components/card.css. Each .card should lift on hover with a translateY and box-shadow transition. The .card-image should scale slightly on card hover for a subtle zoom effect — the overflow: hidden on the card clips it cleanly to the card boundary. Use a flex column layout on .card-body so the CTA button is always pushed to the bottom regardless of description length.

Key Concepts Review

This assignment applies several concepts from the unit in combination:

Assignment Submission

When you have completed all components, test the slide menu at mobile width, verify the hamburger animates correctly in both directions, and check that staggered link animations replay each time the menu opens. Then complete the form below, download the PDF, and submit it via Canvas.

Animated Navigation
Portfolio Link

Live URL:

Rendering and Performance

In this assignment you animated the hamburger icon (transform and opacity), the overlay (opacity), and the buttons (e.g. transform, box-shadow). Pick one of those and explain why the properties you used are compositor-friendly. Then name one property you could have animated there that would have been costly, and what the user would likely notice if you had.

State and Replay

The script only adds or removes .is-open; it never starts, stops, or resets an animation. Reflect on what that constraint forced you to get right in CSS. Why is keeping "state" in the DOM and "motion" in the stylesheet a useful separation, and when might you break that separation on purpose?