Types
There are multiple built in transitions you can utilize. These can be used individually per anchor link or you can set them globally.
- cross-fade
- slide-right
- slide-left
- expand-from-element
- expand-from-element-back
<!-- Set globally -->
<meta name="view-transition" content="slide-left">
<meta name="view-transition-back" content="slide-right">
<!-- Set transition on anchor link
These will override the global settings -->
<a href="/" view-transition="cross-fade">Welcome</a>
<mc-card href="/item/123" view-transition="expand-from-element"></mc-card>
<!-- Add a back transition
Back will only work after the initial view-transition -->
<a href="/"
view-transition="expand-from-element"
view-transition-back="expand-from-element-back">Welcome</a>
<a href="/"
view-transition="slide-left"
view-transition-back="slide-right">Welcome</a>
Custom view transitions
You can add your own view transitions. Both CSS and code transitions are supported.
/* Use standard css */
::view-transition-old(slide-left) {
animation: page-slide-left-out;
animation-duration: 400ms;
animation-timing-function: ease;
}
::view-transition-new(slide-left) {
animation: page-slide-left-in;
animation-duration: 400ms;
animation-timing-function: ease;
}
@keyframes page-slide-left-in {
0% {
transform: translateX(100%);
clip-path: inset(0px 100% 0px 0px);
}
100% {
transform: translateX(0px);
clip-path: inset(0px 0px 0px 0px);
}
}
@keyframes page-slide-left-out {
0% {
transform: translateX(0px);
clip-path: inset(0px 0px 0px 0px);
}
100% {
transform: translateX(-100%);
clip-path: inset(0px 0px 0px 100%);
}
}
import { registerViewTransition } from '@thewebformula/lithe';
registerViewTransition('the-name', {
setup(container, target) {
const scrollTop = document.documentElement.scrollTop;
document.documentElement.style.setProperty('--mc-view-transition-scroll-fix', `translateY(-${scrollTop}px)`);
const containerBounds = container.getBoundingClientRect();
const targetBounds = target.getBoundingClientRect();
return {
containerBounds,
targetBounds,
scrollTop
};
},
animate(container, { containerBounds, targetBounds, scrollTop }) {
document.documentElement.animate(
[
{
transform: `translate(${targetBounds.x - containerBounds.x}px, ${targetBounds.y - containerBounds.y - scrollTop}px)`,
height: `${targetBounds.height}px`,
width: `${targetBounds.width}px`
},
{
transform: `translate(0px, 0px)`,
height: `${container.offsetHeight}px`,
width: `${container.offsetWidth}px`,
}
],
{
duration: 400,
easing: 'cubic-bezier(0.2, 0, 0, 1)',
pseudoElement: '::view-transition-new(expand-from-element)'
}
);
}
});