Practice: Build an animated responsive interface
Outcome
Section titled “Outcome”Continue the task board from the Web interaction assignment. Keep its event-state-render behavior intact while you make the page composition and task components adapt to available space. Add short, finite motion that reinforces one user-triggered state change and provide an equivalent reduced-motion result.
This is Stage 2 of the same source-code project. Do not create another product or repository.
What you will practice
- Separate viewport-responsive page composition from container-responsive component behavior.
- Build a complete narrow-first fallback before adding wider arrangements.
- Use a transition and finite keyframe animation to reinforce existing interaction states.
- Verify responsive, keyboard, motion-preference, and Stage 1 behavior against one commit.
Why this project matters
Section titled “Why this project matters”An interactive feature is not complete when it works at only one width or depends on motion to communicate state. This stage treats layout, wrapping, focus, static state, and motion preferences as parts of the feature’s technical contract.
What is new and what is reused
Section titled “What is new and what is reused”- New: A responsive test matrix, a wider page composition, one container-responsive task component, one finite state-change animation, and explicit reduced-motion behavior.
- Reused: The same product brief, repository, HTML landmarks, form controls, JavaScript state object, task renderer, keyboard route, status output, visual tokens, and verified Stage 1 behavior.
- Not reopened: Do not redesign the data model or add optional task features while the responsive and motion contract is active.
Starting point
Before you start
- Complete the interactive task-board assignment and preserve its final verified commit in the private repository.
- Complete the responsive-components and web-animation lessons.
- Use the same level-2-task-board folder, Git repository, and private GitHub remote.
- Use a current browser that can emulate viewport widths and prefers-reduced-motion.
- Current state
- The task board passes its Stage 1 interaction tests and has a complete narrow single-column baseline, but it has no deliberate wide composition, container query, project motion, or responsive test report.
- First action
- Open level-2-task-board, run git status, and reload the Stage 1 application before changing any file.
- First checkpoint
- The identified Stage 1 commit is clean, every interaction still passes, and responsive-test-report.md records the baseline at 320 and 1280 CSS pixels.
- Help trigger
- Return to the last passing Stage 1 commit or ask for help when an interaction fails before responsive work begins; do not style around an unconfirmed regression.
Requirements
The required assignment is complete when every applicable criterion below is met.
Required responsive behavior
- The complete application works without horizontal page scrolling at 320 CSS pixels, 1280 CSS pixels, and 200% browser zoom.
- The base CSS provides the complete narrow layout without depending on a media query or container query.
- One viewport media query changes the page-level composition when the page has enough space. The breakpoint follows the content rather than a named device.
- The task-list region establishes an inline-size query container, and each task card has one wider arrangement controlled by that container.
- The task card remains complete when placed in a narrow container inside an otherwise wide viewport.
- Long task titles and long category labels wrap without overlap, clipping, inaccessible content, or page overflow.
Required motion behavior
- One short CSS transition gives feedback for a control state such as hover or active.
- One finite keyframe animation reinforces a user-triggered task completion or reopening event.
- The animation runs once, does not flash, does not move a large page area, and does not delay the state update or keyboard focus result.
- The completed or open state remains visible through text, checkbox state, decoration, or another static cue when animation is unavailable.
- A prefers-reduced-motion: reduce rule removes the project transition and keyframe motion while preserving the same content, state, focus, and function.
- No required motion starts automatically, repeats indefinitely, or requires a time-sensitive response.
Accessibility and interaction
- Every Stage 1 form, validation, checkbox, status, and focus-restoration path still passes with the keyboard.
- Focus indicators remain visible in narrow and wide arrangements and are not clipped by task-card overflow.
- Source order remains logical when CSS changes visual arrangement.
- No information or active state depends only on color, position, or motion.
- Text can reflow at 200% browser zoom without forcing two-dimensional scrolling for the application content.
Technical constraints
- Continue the existing index.html, styles.css, app.js, README.md, repository, and private remote.
- Use CSS Grid or Flexbox for layout. Do not use absolute positioning to create the main page or task-card arrangement.
- Use one page-level media query and at least one component-level @container query for different layout responsibilities.
- Use intrinsic and flexible sizing. Do not make the required layout depend on fixed task-card widths or fixed text heights.
- Keep the event → state update → render sequence from Stage 1. JavaScript can expose the changed task state, but CSS owns the required motion.
- Add responsive-test-report.md and record every required environment, action, expected result, actual result, and final status.
Design freedom
- Choose the page grid, task-card wider arrangement, breakpoint values, transition properties, keyframe properties, and exact motion duration.
- Refine the existing color, type, spacing, border, and elevation system while preserving contrast and state visibility.
- Choose whether the completion confirmation uses a small emphasis, border, background, opacity, or short transform, provided it meets every motion constraint.
Out of scope
- A new product brief, new repository, CSS framework, JavaScript framework, build tool, and component library are not required.
- Task removal, filtering, editing, persistence, APIs, deployment, CMS integration, SEO changes, and analytics changes are not required in this stage.
- Parallax, scroll-jacking, autoplay sequences, infinite animation, large zoom effects, and flashing content are outside the required motion contract.
- Pixel-perfect matching to a reference design is not assessed.
Definition of done
Section titled “Definition of done”The required assignment is complete when one identified commit passes the full Stage 1 regression, responsive matrix, keyboard route, standard-motion result, and reduced-motion result. The commit must exist on the private remote, responsive-test-report.md and README.md must identify it, and git status must be clean.
Protect the project baseline
Section titled “Protect the project baseline”Open a terminal in level-2-task-board and run:
git statusgit log -1 --onelinegit remote -vStop if the working tree contains changes you cannot explain. Preserve them in an intentional commit or ask for help before continuing. Do not reset or discard work to make the output look clean.
Run the Stage 1 self-check from a fresh reload. Record the commit ID and results at the top of a new responsive-test-report.md:
# Responsive and motion test report
## Baseline
- Product:- Brief:- Stage 1 commit:- Browser and version:- Baseline interaction result:- Known limits:The Stage 1 commit is the recovery point. Keep it in the existing history. A new branch or tag is optional and does not replace the required checkpoint commits.
Checkpoint 1: Record the narrow and wide baseline
Section titled “Checkpoint 1: Record the narrow and wide baseline”Before changing CSS, test the current application with at least three fictional tasks:
- a short title;
- a title long enough to wrap across several lines;
- a title that contains one uninterrupted test string such as
AccessibilityReviewCheckpoint.
Use developer tools to inspect these environments:
| ID | Environment | Expected baseline evidence |
|---|---|---|
| BASE-01 | 320 × 640 CSS pixels | No horizontal page scroll; form and task controls remain usable |
| BASE-02 | 1280 × 800 CSS pixels | Current single-column layout remains complete, even if space is not used well |
| BASE-03 | 1280 × 800 at 200% browser zoom | Content reflows; focus and text remain available |
| BASE-04 | Narrow task-list host in a wide viewport | Record how the current task card uses its own available width |
For each row, record Pass, Fail, or Blocked and one actual observation. A failure is baseline evidence, not a reason to hide the row.
Confirm that the report names the Stage 1 commit, browser, four baseline rows, long-content values, and the first responsive problem you will address.
Assistance for Checkpoint 1
Section titled “Assistance for Checkpoint 1”Assistance 1 — Separate a viewport from a component container
The viewport is the browser’s layout area. The task-list region is the component’s containing context. A wide viewport can still give the task list a narrow column, so record both widths when they differ.
Assistance 2 — Find the first element that creates overflow
In developer tools, inspect the element whose right edge extends beyond the visible page. Check fixed widths, min-content sizing, long strings, padding under border-box sizing, and flex or grid children that need min-width: 0.
Checkpoint: The responsive baseline is explicit
- What now works
- The original application still passes Stage 1, and the report records its actual narrow, wide, zoom, and component-host behavior against one commit.
- Files changed
responsive-test-report.md- What remains
- Build the complete narrow foundation and a wider page composition without changing application behavior.
- Next action
- Open styles.css and group the existing base rules before any responsive condition.
- If it does not work
- If Stage 1 fails, stop responsive work and repair or recover the interaction baseline before editing layout rules.
Record responsive checkpoints in the same repository
Section titled “Record responsive checkpoints in the same repository”Use focused commits after each passing behavior. Suitable outcomes include:
Build responsive task board compositionAdd container-responsive task cardsAdd reduced-motion completion feedbackDocument responsive application testsEach commit must preserve the earlier interaction paths. Push after a checkpoint so the remote remains a usable recovery route.
Checkpoint 2: Build the page composition narrow first
Section titled “Checkpoint 2: Build the page composition narrow first”Review styles.css and arrange its layers in this order:
- design tokens and box sizing;
- base type and element behavior;
- complete narrow page and component styles;
- control states;
- page-level media query;
- task-card container query;
- motion layer;
- reduced-motion override.
The order makes the fallback visible and reduces conflicts between unrelated conditions.
In the base layer:
- keep the page in one column;
- let inputs, selects, buttons, list items, titles, and categories shrink and wrap;
- use a flexible content width rather than a fixed page width;
- keep controls at least 44 CSS pixels high;
- keep the complete form, summary, task list, and status in source order.
Add one viewport media query only after the narrow route passes. At the chosen content-based breakpoint, arrange the task-entry region and task-list region into a deliberate wider page grid. The status output can span the complete grid.
Choose column proportions from the content. A form often needs a stable readable minimum while the list can use the remaining space. Use minmax() if it helps the grid shrink without overflow.
Test at 1 CSS pixel below and above the page breakpoint. Confirm:
- the narrow layout is complete below the breakpoint;
- the wide layout uses space without changing the DOM source order;
- no control or task text overlaps during the switch;
- Tab order follows the source order in both arrangements;
- Stage 1 add and complete behavior still passes.
Assistance for Checkpoint 2
Section titled “Assistance for Checkpoint 2”Assistance 2 — Choose a page breakpoint from a visible failure
Start narrow and increase the viewport. Choose the first width where the two main regions can sit side by side with readable content and control sizes. Record that observation in the test report instead of choosing a device label.
Assistance 3 — Build the page grid without changing component rules
Keep task-card styles unchanged. First name the two main regions with classes. Make main a one-column grid. At one media query, define the wider columns and place the status across them. Verify the page grid before opening the task-card container query.
Checkpoint: The page composition adapts
- What now works
- The complete narrow page reflows into a deliberate wider composition at a content-based breakpoint while source order, focus order, and Stage 1 behavior remain stable.
- Files changed
index.html, styles.css, responsive-test-report.md- What remains
- Make task cards respond to the task-list container instead of the viewport.
- Next action
- Open index.html and identify the task-list wrapper that will establish container-type: inline-size.
- If it does not work
- If the wide grid overflows, remove explicit column placement, confirm the narrow base, then restore one minmax column definition at a time.
Checkpoint 3: Make task cards respond to their container
Section titled “Checkpoint 3: Make task cards respond to their container”The page media query and component container query answer different questions:
| Condition | Responsibility |
|---|---|
| Viewport media query | Can the page arrange the form and task-list regions side by side? |
| Task-list container query | Does this specific list give a task card enough space for a wider internal arrangement? |
Add a class to the stable task-list region or wrapper. In styles.css, establish an inline-size query container:
.task-list-region { container-type: inline-size;}Keep the base task card stacked and complete. Then add one container query that rearranges existing task-card content only when the list region is wide enough. For example, the title can use the flexible column while the category occupies an auto-sized column.
Do not query the card’s own size when the card is the element you want to style. Query the stable parent container and change descendants inside it.
Use developer tools to test the same card in both of these conditions:
- a narrow list column inside a wide page;
- a wide list region when the page gives it enough space.
Long content must determine whether the chosen threshold works. Adjust the container breakpoint when the category or title becomes cramped.
Add these rows to responsive-test-report.md:
| ID | Condition | Expected result |
|---|---|---|
| RESP-01 | 320 CSS-pixel viewport | Stacked page and stacked task cards; no overflow |
| RESP-02 | 1 pixel below page breakpoint | Complete one-column page |
| RESP-03 | 1 pixel above page breakpoint | Wide page composition appears without overlap |
| RESP-04 | Narrow list container in wide viewport | Task card keeps its stacked internal layout |
| RESP-05 | Wide list container | Task card uses its wider internal arrangement |
| RESP-06 | Long title and category | Text wraps; control, label, and focus remain available |
| RESP-07 | 200% browser zoom | Reflow works without horizontal application scrolling |
Record the container’s measured width for RESP-04 and RESP-05. This evidence shows that the component responds to its host rather than a remembered viewport value.
Assistance for Checkpoint 3
Section titled “Assistance for Checkpoint 3”Assistance 1 — Identify the query container and changed descendant
The task-list region establishes container-type. The task card or its internal content receives the conditional layout rules. Write those two selectors beside each other before debugging the threshold.
Assistance 2 — Diagnose a container query that never matches
Inspect the intended parent in developer tools. Confirm its computed container-type is inline-size, the @container rule is valid, and the measured container width crosses the threshold. Confirm that the conditional selector targets a descendant of that container.
Assistance 3 — Prove container behavior independently of the viewport
Keep the viewport wide. Temporarily change only the page-grid column allocation so the list becomes narrow and then wide. If the task card changes at its container threshold in both cases, the component boundary works. Remove temporary values after recording the result.
Checkpoint: Task cards adapt to their host
- What now works
- The task component has a complete stacked fallback and one wider arrangement controlled by the measured task-list container width.
- Files changed
index.html, styles.css, responsive-test-report.md- What remains
- Add finite interaction feedback and an equivalent reduced-motion result.
- Next action
- Open app.js and expose which rendered task changed during the completion event.
- If it does not work
- If only viewport resizing triggers the component, inspect whether the rule is an @media query or whether the container always receives the same width from the page grid.
Checkpoint 4: Add motion after the static state works
Section titled “Checkpoint 4: Add motion after the static state works”The task’s checkbox, completion text treatment, summary, and status message already communicate the state. Keep those static results. Motion can reinforce the change but cannot become its only evidence.
Add one control transition
Section titled “Add one control transition”Choose one small control property, such as background color, border color, or a short button transform. Define the transition on the control’s base rule so both entry and exit states use the same timing. Keep the duration short and the affected area local.
Expose the task that changed
Section titled “Expose the task that changed”Let renderTasks know which task triggered the completion render. On the matching new list item, add a data attribute such as data-changed="true". Other tasks must not receive that value.
This attribute is temporary interface state for the new render. The task’s persistent completion state remains in the state object.
Add one finite keyframe effect
Section titled “Add one finite keyframe effect”Target only the changed task card. Use one animation name, one short duration, a finite iteration count of 1, and no start delay. Prefer local emphasis over large movement. The effect must end in the normal static open or completed appearance.
Remove motion for the user preference
Section titled “Remove motion for the user preference”At the end of styles.css, add:
@media (prefers-reduced-motion: reduce) { /* Name the project controls that normally transition. */ .project-control { transition: none; }
/* Keep the changed task state but remove the effect. */ .task-card[data-changed="true"] { animation: none; }}Replace .project-control with the actual selector or selectors. Do not use a global rule that changes unrelated browser or extension behavior.
Run these paths with the keyboard:
| ID | Preference | Action | Expected result |
|---|---|---|---|
| MOTION-01 | No preference | Complete one open task | Static state updates immediately; local animation runs once; focus returns to its checkbox |
| MOTION-02 | No preference | Reopen the same task | Static state updates immediately; effect runs once; focus remains useful |
| MOTION-03 | Reduced motion | Complete one open task | Same checkbox, text, summary, status, and focus results; no project transition or keyframe motion |
| MOTION-04 | Reduced motion | Reopen the task | Same open-state result; no delay and no motion |
| MOTION-05 | Either preference | Wait after the event | No animation repeats or continues |
Use the browser rendering or emulation controls to change prefers-reduced-motion. Record the exact tool and setting in the report.
Assistance for Checkpoint 4
Section titled “Assistance for Checkpoint 4”Assistance 2 — Trace a state change that animates every task
Inspect the rendered data attributes. Only the task whose ID matches the event’s task ID should receive data-changed="true". Keep data-completed separate because several tasks can be complete at once.
Assistance 3 — Separate static state, event emphasis, and preference
First confirm the checkbox, completion decoration, summary, status, and focus without animation. Then add the changed-task attribute and finite keyframe. Last, emulate reduced motion and disable the transition and animation while leaving all static results unchanged.
Checkpoint: Motion reinforces but does not own the result
- What now works
- One local effect runs once after a user-triggered task change, while standard and reduced-motion modes provide the same state, content, function, and focus result.
- Files changed
styles.css, app.js, responsive-test-report.md- What remains
- Run the complete regression, document decisions and limits, and record the verified Stage 2 commit.
- Next action
- Reload the application and execute the self-check from the first interaction path through the final reduced-motion path.
- If it does not work
- If reduced motion still moves, inspect computed animation-name and transition-duration on the exact changed task and control while emulation is active.
Complete the responsive and motion report
Section titled “Complete the responsive and motion report”For every required ID, record:
- environment or preference;
- precondition;
- action;
- expected result;
- actual result;
- Pass, Fail, or Blocked;
- evidence or focused repair commit when applicable.
Add a final regression section for the Stage 1 paths. Identify any test limit. A result observed in one browser is evidence for that browser and version, not every browser or assistive technology.
Update README.md with:
- page-level and component-level responsive responsibilities;
- the page and container breakpoint values and why content supports them;
- the static completion cues;
- the motion trigger, duration, affected properties, and iteration count;
- the reduced-motion result;
- how to reproduce the responsive and motion tests;
- the final verified commit;
- known limits and the next quality-planning step.
Record and push the final checkpoint:
git statusgit diffgit add index.html styles.css app.js README.md responsive-test-report.mdgit diff --stagedgit commit -m "Complete responsive animated task board"git pushgit statusSelf-check
Complete these checks against the required result.
- The final commit begins from the verified Stage 1 repository and preserves its product brief, state model, private remote, and history.
- Every Stage 1 form, validation, add-task, completion, summary, status, safe-text, and focus-restoration path still passes.
- The complete narrow layout works at 320 CSS pixels without a media query or horizontal page scrolling.
- One content-based viewport breakpoint changes the page composition without changing source or focus order.
- The task-list region is an inline-size query container, and a task card changes its internal layout at a measured container threshold.
- The same task card stays stacked in a narrow host inside a wide viewport and uses its wider arrangement in a wide host.
- Long task titles, long categories, and 200% browser zoom pass without clipping, overlap, lost controls, or inaccessible content.
- One control transition and one changed-task keyframe effect remain local, short, finite, and user-triggered.
- The completed or open state is fully understandable from static checkbox, text, summary, and status evidence.
- Reduced-motion emulation removes the project transition and keyframe motion without delaying or removing state, content, focus, or function.
- responsive-test-report.md records every BASE, RESP, MOTION, and regression result against the final identified commit.
- README.md explains the responsive boundaries, motion contract, test route, limits, and next step.
- The final commit exists on the private remote, the Console has no unresolved errors, and git status reports a clean working tree.
Assessment
Section titled “Assessment”| Area | Evidence |
|---|---|
| Responsive foundation | Narrow-first CSS, intrinsic sizing, long-content behavior, zoom reflow, and page composition pass |
| Component responsiveness | The task card responds to a measured container boundary independently of viewport width |
| Motion design | Static state remains primary; the transition and finite effect have a clear trigger and bounded scope |
| Motion accessibility | Reduced-motion mode preserves content, state, interaction, timing, and focus without project motion |
| Regression safety | Every Stage 1 interaction path passes after the CSS and motion changes |
| Development evidence | Focused commits, report rows, README decisions, private remote, and clean final state identify one verified result |
The review does not reward more breakpoints or more animation. One well-supported page breakpoint, one well-supported component threshold, and one meaningful finite effect meet the required technical scope.
Assignment-wide assistance
Section titled “Assignment-wide assistance”Assistance 4 — Review a responsive and motion CSS structure
Adapt selectors and values to your application. The comments identify responsibility boundaries; they are not a required visual design.
/* 1. Complete narrow page and component fallback */.app-layout { display: grid; gap: var(--space-5);}
.task-list-region { container-type: inline-size; min-width: 0;}
.task-card,.task-copy { min-width: 0;}
/* 2. Page composition responds to the viewport */@media (min-width: 56rem) { .app-layout { grid-template-columns: minmax(16rem, 0.75fr) minmax(0, 1.25fr); }
.status { grid-column: 1 / -1; }}
/* 3. Task internals respond to their list container */@container (min-width: 34rem) { .task-copy { grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; }}
/* 4. Optional motion reinforces an existing static state */.project-control { transition: background-color 180ms ease, transform 180ms ease;}
.task-card[data-changed="true"] { animation: confirm-task 240ms ease-out 1;}
@keyframes confirm-task { 50% { outline: 0.2rem solid var(--accent); outline-offset: 0.2rem; }}
/* 5. Preference removes motion, not the result */@media (prefers-reduced-motion: reduce) { .project-control { transition: none; }
.task-card[data-changed="true"] { animation: none; }}Complete and test one numbered layer before you open the next.
Assistance 5 — Review one complete Stage 2 change patternExample solution
This pattern assumes the Stage 1 reference classes. Adapt it to your own DOM. It is complete for the responsive and motion changes, not a replacement for your existing application files.
Add class="app-layout" to the element that contains the task-entry section, task-list section, and status. Add class="task-list-region" to the task-list section. Keep the existing semantic source order.
In the render loop, add the changed-task state after the item receives its task-card class:
item.dataset.changed = String(task.id === focusTaskId);The existing checkbox handler already passes task.id to renderTasks. The valid submit handler calls renderTasks() without an ID, so adding a task does not receive the completion effect.
Append this tested layer after the complete Stage 1 base CSS. Adjust only a breakpoint that your content evidence shows is unsuitable:
.app-layout { display: grid; gap: var(--space-5);}
.task-list-region { container-type: inline-size; min-width: 0;}
.task-card,.task-control,.task-copy { min-width: 0;}
.task-copy { display: grid; gap: var(--space-1);}
button { transition: background-color 180ms ease, transform 180ms ease;}
button:hover { background: #18594d;}
button:active { transform: translateY(0.1rem);}
@media (min-width: 56rem) { .site-header, main { width: min(100% - 3rem, 70rem); }
.app-layout { grid-template-columns: minmax(16rem, 0.75fr) minmax(0, 1.25fr); align-items: start; }
.status { grid-column: 1 / -1; }}
@container (min-width: 34rem) { .task-copy { grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: var(--space-3); }}
.task-card[data-changed="true"] { animation: confirm-task 240ms ease-out 1;}
@keyframes confirm-task { 0%, 100% { outline: 0 solid transparent; outline-offset: 0; }
50% { outline: 0.2rem solid var(--accent); outline-offset: 0.2rem; }}
@media (prefers-reduced-motion: reduce) { button { transition: none; }
button:active { transform: none; }
.task-card[data-changed="true"] { animation: none; }}Run the complete responsive and motion matrix after adapting the pattern. A matching screenshot does not prove container independence, keyboard focus, or reduced-motion behavior.
Safe stopping point and re-entry
Section titled “Safe stopping point and re-entry”Stop after a passing checkpoint and push the commit. Add this current-state note to responsive-test-report.md before a longer interruption:
## Resume here
- Last passing commit:- Page widths that pass:- Container widths that pass:- Motion preference last tested:- First failing or unfinished test ID:- Exact next action:- File and selector or function to open:When Stage 2 is complete, leave the task-board repository intact. The Quality, SEO, and analytics lessons and final project will use this verified application and its existing history.