ページの切り替えをアニメーションする
ページを移るときに、前のページから次のページへクロスフェードさせたり、戻るときだけ逆向きにスライドさせたりできます。使うのは、Reactの<ViewTransition>と、ルーターがページの切り替えに付ける種類です。
このページの内容
ページをクロスフェードする
ページが描かれる<Outlet />を、<ViewTransition>で包みます。
src/shell.tsximport { Outlet } from '@k8ordo/router';
import { ViewTransition } from 'react';
export function Shell() {
return (
<>
<header>…</header>
<ViewTransition
default="none"
update={{ navigation: 'auto', default: 'none' }}
>
<Outlet />
</ViewTransition>
</>
);
}updateに書くのは、<ViewTransition>そのものは残り、中身だけが入れ替わるからです。autoは、ブラウザ標準のクロスフェードです。
このサイトも、ページをこれと同じ<ViewTransition>で包んでいます。サイドバーから別のページを開くと、本文がクロスフェードします。
ページの切り替えのときだけ動かす
ルーターは、ページを切り替える描画にnavigationという種類を付けます。updateのキーにnavigationを書き、defaultをnoneにすると、この種類の描画のときだけアニメーションします。
種類で絞るのは、ページの切り替えのほかにも<ViewTransition>を動かす更新があるからです。たとえば@k8ordo/uiのButtonは、アクションの実行中をtransitionで表します。絞らないと、ボタンを押すたびにページ全体がクロスフェードしてしまいます。
クエリ文字列だけを変える状態の更新は、ページを切り替えないので、アニメーションしません。
戻るときは逆向きにスライドする
ルーターはnavigationに加えて、ナビゲーションの種類を表すnavigation-push、navigation-replace、navigation-traverseのどれかも付けます。
リンクのクリックとnavigateToはpushです。{ history: 'replace' }を渡したときはreplaceで、ブラウザの戻ると進むはtraverseです。
src/shell.tsx<ViewTransition
default="none"
update={{
'navigation-push': 'slide-forward',
'navigation-replace': 'slide-forward',
'navigation-traverse': 'slide-back',
default: 'none',
}}
>
<Outlet />
</ViewTransition>updateの値は、view transitionのクラス名になります。クラスごとの動きは、::view-transition-old()と::view-transition-new()で書きます。
src/app.css@keyframes slide-from-right {
from {
opacity: 0;
translate: 32px 0;
}
}
@keyframes slide-from-left {
from {
opacity: 0;
translate: -32px 0;
}
}
::view-transition-new(.slide-forward) {
animation: 200ms ease-out both slide-from-right;
}
::view-transition-new(.slide-back) {
animation: 200ms ease-out both slide-from-left;
}動きを減らす設定に従う
@k8ordo/uiのスタイルシートは、prefers-reduced-motionがreduceのとき、view transitionのアニメーションを止めます。@k8ordo/uiを使っていないアプリでは、同じ規則を自分で書きます。
src/app.css@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none;
}
}フレームワークの下でアニメーションする
@k8ordo/staticや@k8ordo/serverでは、レイアウトのchildrenを同じように<ViewTransition>で包みます。
src/routes/layout.tsximport type { LayoutProps } from '@k8ordo/router';
import { ViewTransition } from 'react';
export default function RootLayout({ children }: LayoutProps<'/'>) {
return (
<html lang="en">
<body>
<ViewTransition
default="none"
update={{ navigation: 'auto', default: 'none' }}
>
{children}
</ViewTransition>
</body>
</html>
);
}メモ
<ViewTransition>はServer Componentのレイアウトの中にそのまま書けます。ページの切り替えに付く種類は、フレームワークの下でも同じです。