Next route/WORK
INTERACTION_162CSS + JS
Liquid Wipe Transition
A curved wipe sweeps across the screen between pages.
Transitions / MediumView
A card image flies into position on the detail page. The image at its grid position before the trigger; animating from the source rect to the destination rect using FLIP once navigating to the detail route.
/* Shared Element Transition — A card image flies into position on the detail page. */
.shared-element-transition {
--dur: 560ms;
--ease: cubic-bezier(0.22, 1, 0.36, 1);
--stagger: 60ms;
will-change: transform, opacity;
}
.shared-element-transition > * {
opacity: 0;
transform: translateY(14px);
animation: shared-element-transition-in var(--dur) var(--ease) forwards;
animation-delay: calc(var(--i, 0) * var(--stagger));
}
/* the image at its grid position -> animating from the source rect to the destination rect using FLIP */
@keyframes shared-element-transition-in {
to {
opacity: 1;
transform: none;
filter: none;
}
}
@media (prefers-reduced-motion: reduce) {
.shared-element-transition > * {
opacity: 1;
transform: none;
animation: none;
}
}import { useEffect, useRef } from "react";
/** Shared Element Transition — trigger: navigating to the detail route */
export function SharedElementTransition({ children }: { children: React.ReactNode }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
el.dataset["state"] = "in";
return;
}
const io = new IntersectionObserver(
([entry]) => {
if (entry?.isIntersecting) {
el.dataset["state"] = "in";
io.unobserve(el);
}
},
{ threshold: 0.2 },
);
io.observe(el);
return () => io.disconnect();
}, []);
return (
<div ref={ref} className="shared-element-transition" data-state="out">
{children}
</div>
);
}A curved wipe sweeps across the screen between pages.
Panels close over the page then lift to reveal the next route.
The outgoing page blurs out and the next resolves into focus.
Routes slide horizontally in the direction of travel.