@k8ordo/router

ページの切り替えをアニメーションする

ページを移るときに、前のページから次のページへクロスフェードさせたり、戻るときだけ逆向きにスライドさせたりできます。使うのは、Reactの<ViewTransition>と、ルーターがページの切り替えに付ける種類です。

このページの内容

ページをクロスフェードする

ページが描かれる<Outlet />を、<ViewTransition>で包みます。

src/shell.tsx
import { 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.tsx
import 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のレイアウトの中にそのまま書けます。ページの切り替えに付く種類は、フレームワークの下でも同じです。

k8ordo

Baselineに入った機能を、制限なく使うReactのライブラリ群。

© 2026 k8o — MIT License

組版:Noto Sans JP / M PLUS 2