Skip to content

Latest commit

 

History

History
229 lines (191 loc) · 8.06 KB

File metadata and controls

229 lines (191 loc) · 8.06 KB

03‑visual‑effects/view‑transitions/README.md

Single‑file Alpine.js + Tailwind tutorial that teaches the View Transitions API with runnable demos, step playback, and a Terminal‑Neon aesthetic.

1) What This Is

An interactive tutorial and playground for the View Transitions API. It explains SPA (same‑document) transitions, shared‑element transitions, optional cross‑document (MPA) navigation, and how to build robust fallbacks that respect accessibility and performance.

  • Stack: Plain HTML + Alpine.js (CDN) + Tailwind (CDN) + Fira Code
  • Design: Terminal‑Neon cards, glow accents, dark theme
  • File: index.html (no build step)

2) Requirements & Support

  • Modern Chromium‑based browsers; partial features land in others over time
  • Feature detection is mandatory:
    const supported = 'startViewTransition' in document;
  • Prefer reduced motion respect:
    const prefersReduced = matchMedia('(prefers-reduced-motion: reduce)').matches;

3) Concepts at a Glance

  • startViewTransition(cb): Snapshot → DOM update in cb → browser creates transition pseudo‑elements → animate per CSS.
  • Promises: transition.ready resolves when snapshots & pseudo‑elements are ready; transition.finished resolves after animation completes.
  • Shared elements: Link visual continuity by giving the same view-transition-name to old/new DOM counterparts.
  • Cross‑document: Some browsers support declarative navigation transitions; provide graceful fallback.

4) Demos Included

  1. SPA Route Fade – swap section content via Alpine state inside startViewTransition.
  2. Shared Element (Grid → Detail) – card thumbnail travels/expands into detail.
  3. MPA/Cross‑Doc (Optional) – pattern + fallback when unsupported.
  4. Reduced Motion – skip animations, still log phases for learning.

Each demo has:

  • Controls: Prev / Next / Auto / Reset
  • A pipeline strip: Snapshot → Update → Animate → Finish with active phase highlight
  • Live code with current line highlight
  • Console panel logging ready/finished timestamps

5) Usage

Include Tailwind and Alpine via CDN:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

Run by simply opening index.html in a supported browser.

6) Authoring Pattern

Minimal pattern you’ll see in the demos:

document.startViewTransition(() => {
  // mutate DOM synchronously here (swap route, toggle view, etc.)
});

Then style the pseudo‑elements in CSS (see Cheat‑Sheet below).

7) Accessibility

  • Respect prefers-reduced-motion; disable or drastically soften transitions.
  • Maintain focus order on route changes.
  • Avoid disorienting large‑scale moves; prefer small, meaningful continuity.

8) Performance Notes

  • Snapshot cost scales with the painted area. Prefer shared‑element transitions over whole‑page fades.
  • Avoid heavy filters (blur, drop‑shadow) on large regions.
  • Constrain layout shifts; prefer transforms over geometry reflow.
  • Lazy assets (images) may pop in late—consider placeholders or preloading.

9) Debugging Tips

  • Outline participating elements (utility toggles in page)
  • Temporarily slow animations with longer durations
  • Use devtools to inspect layers/paint (Rendering/Performance panels)

10) Common Gotchas

  • Missing view-transition-name on either side → no shared animation
  • Reparenting DOM without maintaining the named element → transition breaks
  • Animating huge containers → jank; animate smaller focus elements instead
  • Mutations outside the startViewTransition callback → won’t be captured

11) API “Recipe Cards”

  • Fade route: whole‑root fade with soft easing
  • Shared thumbnail → detail: scale & translate via image‑pair
  • List reorder: per‑row shared names to preserve continuity
  • Panel slide‑in: constrain to sub‑tree and animate transform

12) Roadmap / Extensions

  • Add “staging” via transition.updateCallback(cb) patterns
  • Add user‑editable CSS sandbox per demo
  • Time travel scrubber for phases

13) License & Credits

  • MIT. Credit MDN & Chrome DevRel articles for references; plus internal design system origins.

CSS Pseudo‑Elements Cheat‑Sheet (drop into index.html)

A) Whole‑page Fade (root)

/* Root pseudo‑elements */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 300ms;
  animation-timing-function: cubic-bezier(.2,.8,.2,1);
}
::view-transition-old(root) { animation-name: vt-fade-out; }
::view-transition-new(root) { animation-name: vt-fade-in; }

@keyframes vt-fade-out { from { opacity: 1 } to { opacity: 0 } }
@keyframes vt-fade-in  { from { opacity: 0 } to { opacity: 1 } }

Use:

document.startViewTransition(() => swapRoute());

B) Shared Element (card → detail)

/* Give both old and new elements the SAME name */
.card-thumb[data-id] { view-transition-name: card-attr; }
.detail-hero         { view-transition-name: card-attr; }

/* Optional: tune the pair */
::view-transition-group(card-attr) {
  /* grouping layer for the named element */
}
::view-transition-image-pair(card-attr) {
  /* controls the interpolated snapshot pair */
  isolation: isolate; /* reduce blending surprises */
}

DOM idea:

<div class="card-thumb" :data-id="id" style="view-transition-name: card-{{id}}"></div>
<!-- In detail view -->
<div class="detail-hero"    style="view-transition-name: card-{{id}}"></div>

C) Sliding Panel (sub‑tree only)

/* Limit to a container by naming only that subtree's key element */
.sidebar-panel { view-transition-name: sidebar; }

::view-transition-old(sidebar) { animation: slide-out 250ms both; }
::view-transition-new(sidebar) { animation: slide-in  250ms both; }

@keyframes slide-out { from { transform: translateX(0) } to { transform: translateX(-8%) } }
@keyframes slide-in  { from { transform: translateX(8%) } to { transform: translateX(0) } }

D) Reduced Motion Respect

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root),
  ::view-transition-group(*),
  ::view-transition-image-pair(*) {
    animation: none !important;
  }
}

JS toggle (optional):

const prefersReduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReduced) {
  // Skip startViewTransition entirely, or drastically shorten durations
}

E) Timings & Easing

:root {
  --vt-dur-short: 180ms;
  --vt-dur-base: 300ms;
  --vt-ease: cubic-bezier(.2,.8,.2,1);
}
::view-transition-old(root),
::view-transition-new(root) { animation-duration: var(--vt-dur-base); animation-timing-function: var(--vt-ease); }

F) Debug Outlines (dev mode)

/* Visualize participants */
::view-transition-old(*),
::view-transition-new(*) {
  outline: 1px dashed rgba(0, 255, 255, .35);
}

G) Feature Detection & Fallback

<script>
  const supported = 'startViewTransition' in document;
  document.documentElement.classList.toggle('vt-supported', supported);
</script>
<style>
  .vt-supported .vt-fallback { display: none; }
  .vt-fallback { /* show a CSS/JS fallback notice */ }
</style>

H) Staging Updates (pattern)

const t = document.startViewTransition(() => {
  // Phase 1 DOM change
});
// Optional staged update after ready
await t.ready;
// do additional class toggles or lazy decorations if needed
await t.finished;

Copy‑Paste Sections for the Tutorial Page

  • Pipeline strip CSS (active phase glow)
  • Console panel styles (monospace, scrollback)
  • Card grid (shared element demo)
  • Controls (Prev/Next/Auto)

Keep the above blocks co‑located in index.html with clear comments so learners can see exactly how the pseudo‑elements and names drive the animation behavior.