crossfade() and FLIP Technique DOM Layout Animations
- Last updated
- Prerequisites:
- Svelte transitions and {#each} blocks
- Understanding of layout measurement and DOM order
- svelte
- crossfade
- flip
- animation
- layout
- transitions
Read at your depth
The practical view
crossfade() creates paired transitions for elements moving between lists: const [send, receive] = crossfade({ duration: 400 });. Apply send to the source element's out: transition and receive to the destination's in: transition; Svelte measures both positions and animates one fading out while the other fades in at the matching spot. The FLIP technique animates reordering: {#each items as item (item.id)}<div animate:flip>{item}</div>{/each} — when items reorder, elements smoothly slide to their new positions. The animate: directive only fires when the element's position changes due to reordering in a keyed each block.
The same idea in other frameworks
Framer Motion's layoutId and AnimatePresence approximate crossfade/FLIP.Angular animations have no built-in FLIP; libraries provide it.Vue's <TransitionGroup> with FLIP (move-class) is the direct analogue.Legacy vs modern
Keyed reorder without animation vs animate:flip
Reordering a keyed list snaps items instantly; the FLIP directive slides each item from its old to new position.
{#each items as item (item.id)}
<div>{item}</div> <!-- ❌ OLD: reorder snaps instantly -->
{/each}{#each items as item (item.id)}
<div animate:flip>{{item}}</div> <!-- ✅ NEW: slides to new position -->
{/each}Interview gotchas
Context
This tests the core animation technique — interviewers want the First/Last/Invert/Play mechanics and why it is performant (transform-only animation), not just that Svelte has an animate: directive.
The mechanical answer
FLIP stands for First, Last, Invert, Play. First: record each element's starting position. Last: let the layout change happen and record the final positions. Invert: apply a transform equal to the negative delta (old - new) so each element appears exactly where it was, even though the DOM/layout has already moved it. Play: animate the transform back to zero, so the element visibly slides from its old spot to its new one. Because the animation is a pure transform (translate), it runs on the compositor without triggering layout or paint per frame — avoiding jank. The keyed each block is what lets Svelte track identity so FLIP can measure the same element's before/after rects.
Trap
The naive answer is 'FLIP animates between old and new layout positions directly'. The inverted-transform trick is the essence: the element is ALREADY at its new layout position, and the animation is the transform unwinding to zero. Another trap: thinking FLIP works without keyed each blocks — identity tracking is required to pair before/after rects. Candidates who name the four steps and the transform-only payoff show real understanding.
Context
This probes the paired-transition coordination — interviewers want to know how send/receive find each other across lists and the graceful fallback when a move isn't a clean swap.
The mechanical answer
crossfade() returns two transition functions (send and receive) that share an internal registry. When an element with the send transition starts its outro, it records its bounding rect in the registry. When an element with the receive transition starts its intro, it looks up a pending send partner (matched by a shared key when you pass one, or by order/heuristic). If a partner exists, the engine computes the transform between the outgoing and incoming rects and animates both — the sender slides/fades toward the receiver's position while the receiver fades in there, creating the illusion of one element moving across lists. If no partner exists (e.g. an element simply appears), the receive transition falls back to a plain fade/scale intro. The fallback keeps the API safe for non-swap cases.
Trap
The naive answer is 'crossfade just fades both elements'. The position-matching transform is what makes it look like an element travels between lists — without a matched partner it degrades to a plain fade. Another trap: assuming crossfade works without keyed each blocks or without the send/receive pairing correctly — misordered pairs produce jittery double-fades. Candidates who describe the registry and the transform computation show real depth.