ダイナミックページトランジション
クロスフェード、ローディングオーバーレイ、ページ間で維持されるchromeを備えたSPA風のソフトナビゲーション。
概要
zudo-docはデフォルトで、ページ間の遷移をブラウザのフルリロードなしで行います。新しいドキュメントを取得してウィンドウ全体を再描画する代わりに、ページのbodyだけをその場で差し替え、周囲のchrome(ヘッダー、サイドバー、フッター)はそのまま保ち、クロスフェードで変化をアニメーションさせます。その結果、シングルページアプリ(SPA)のような体験になります。高速でなめらかで、ハードナビゲーションで生じる白い瞬きがありません。
この挙動はダイナミックページトランジションと呼ばれ、デフォルトで有効です。
Note
ダイナミックページトランジションは純粋に表示上の拡張です。サイトは依然として完全な静的エクスポートであり、すべてのページは独立したHTMLとして存在し、JavaScriptなしでも動作します。トランジションレイヤーはJavaScriptが利用可能なときにアプリ内リンクのクリックを横取りするだけで、それ以外の場合は通常のナビゲーションにフォールバックします。
何をするのか
ダイナミックナビゲーションは3つの要素を組み合わせています。
同一ドキュメント内のbody差し替え。 内部リンクをクリックすると、ルーターはバックグラウンドで遷移先ページを取得し、ドキュメント全体を破棄して再構築することなく、現在のページのbodyの内容を新しいページの内容に置き換えます。ヘッダー、サイドバー、フッターのDOMノードはナビゲーションをまたいで保持されるため、スクロール位置や状態が維持されます。
履歴の処理。 ルーターは
pushStateでブラウザ履歴を更新するため、URLが変化し、戻る/進むボタンは通常のナビゲーションとまったく同じように機能します。戻るボタンを押すとpopstateイベントが発火し、ルーターはこれを処理して前のページへ差し替えます。やはりフルリロードはありません。View Transitions APIによるクロスフェード。 この差し替えはブラウザのView Transitions APIでラップされており、新旧の状態のスナップショットをキャプチャしてその間をアニメーションさせます。chrome以外のコンテンツはクロスフェードし、ヘッダー、サイドバー、フッターはそれぞれ独自のトランジションレイヤーに抽出されて静止したまま保たれるため、ちらつきません。
Info
chrome要素(<header>、デスクトップサイドバー、<footer>、サイドバートグルボタン)には安定したview-transition-nameが付与されており、これによってクロスフェードが記事領域だけをアニメーションさせられます。あるページにchrome要素が存在し、次のページには存在しない場合(たとえばサイドバーのあるドキュメントページから、サイドバーのないトップページへ移動する場合)、その要素はスナップせずにコンテンツと同期してフェードイン/フェードアウトします。
ローディングオーバーレイ
遷移先ページの取得中、zudo-docは中央にスピナーを配置したフルスクリーンのローディングオーバーレイを表示します。ナビゲーションが始まると表示され、新しいコンテンツが差し替えられると同時に消えるため、クリックが受け付けられたことが即座にフィードバックされます。取得に少し時間がかかる低速な接続では特に有用です。
クリックしたリンクやボタンも、そのナビゲーションが進行中の間は短時間ハイライトされるため、どのアクションが実行中なのかが分かります。
Tip
オーバーレイはクリックから差し替えまでの短い間だけ表示されます。ローカルでの高速なナビゲーションではほぼ一瞬で消えることがありますが、これは想定どおりの動作です。その役割は、低速な取得で生じる体感上の遅延を覆い隠すことであり、人為的な間を加えることではありません。
モーション低減
zudo-docはユーザーのprefers-reduced-motion設定を尊重します。訪問者がOSレベルでモーション低減を有効にしている場合、
クロスフェードアニメーションは即時の差し替えに縮退します。新しいページがフェードやスライドなしで即座に表示されます。
スピナーは回転を止め、アニメーションする代わりに静止した暗めのリングとして表示されます。
ナビゲーションそのもの(同一ドキュメント内の差し替え、履歴の処理)は同じように動作し、取り除かれるのはモーションだけです。これにより、アニメーションに敏感なユーザーにとって快適な体験を保ちつつ、ソフトナビゲーションのパフォーマンス上の利点も維持されます。
機能の切り替え
ダイナミックページトランジションはdynamicPageTransition設定で制御され、デフォルトで有効です。
settings.tsで
export const settings = {
// ...
dynamicPageTransition: true,
};falseに設定すると、ダイナミックトランジションが完全に無効になります。
プリセットジェネレーターで
create-zudo-docで新しいプロジェクトを生成する際、このオプションは「Dynamic page transition」というラベルで表示され、デフォルトで有効です。CLIフラグで非対話的に制御できます。
# 明示的に有効化(これがデフォルト)
create-zudo-doc my-docs --dynamic-page-transition
# 無効化 — 通常のフルページナビゲーションのプロジェクトを生成
create-zudo-doc my-docs --no-dynamic-page-transition「オフ」が意味すること
ダイナミックページトランジションを無効にすると、ナビゲーションは通常のフルページ読み込みにフォールバックします。
すべての内部リンクが通常のブラウザナビゲーションを発生させ、ドキュメントが取得されてページ全体が再描画されます。
SPAのbody差し替えはありません。ヘッダー、サイドバー、フッターは保持されるのではなく、ナビゲーションごとに再構築されます。
ローディングオーバーレイもクロスフェードもありません。ブラウザのデフォルトのナビゲーション挙動になります。
これはトランジション用のJavaScriptを一切持たない、よりシンプルなモデルです。クラシックなマルチページ体験を好む場合、ソフトスワップルーターとカスタムのクライアントサイドスクリプトとの相互作用を排除したい場合、あるいは単にアニメーションが不要な場合に選んでください。
Note
機能をオフにしても、コンテンツやルートは一切変わりません。変わるのはブラウザがページ間を移動する方法だけです。どちらの場合でも、すべてのページは独立した静的エクスポートのHTMLドキュメントのままです。
独自レイアウトでオーバーレイを配線する
DocLayoutWithDefaultsでレイアウトを組んでいる場合、ローディングオーバーレイはすでに配線済みです。何もする必要はないので、このセクションは読み飛ばして構いません。ここで説明するのは、DocLayoutWithDefaultsを使わずに独自のレイアウトを組み立てており、同じオーバーレイの挙動を取り入れたい場合だけです。
オーバーレイは@takazudo/zudo-docから、自分で配線する2つの部品として提供されます。PageLoadingOverlayコンポーネントと、そのスタイルシート@takazudo/です。
コンポーネントをマウントする
PageLoadingOverlayをインポートし、bodyの末尾のスロット(他のbody-endプロバイダーをマウントしているのと同じ場所)にレイアウトごとに一度だけレンダリングします。これはサーバーレンダリングされ、ハイドレーションは不要です。表示・非表示をナビゲーションのライフサイクル(zfb:before-preparation / zfb:after-swap)に自動で結びつける小さなインラインスクリプトを出力するため、登録すべきislandも、追加すべきclient:*ディレクティブもありません。
import { PageLoadingOverlay } from "@takazudo/zudo-doc/page-loading";
// ...レイアウト内、<body>の末尾で:
<PageLoadingOverlay />;コンポーネントが受け取るプロパティは、オプションのidが1つだけです。これはオーバーレイ要素のDOM idを上書きします(テストなど、1ページ上に複数のオーバーレイが共存しうる場合にのみ役立ちます)。通常は指定せず、安定したデフォルト値のままにしてください。
Warning
マウントはレイアウトごとに一度だけにしてください。2つ目のインスタンスを置くと、オーバーレイ要素とブートストラップスクリプトが二重に出力されてしまいます。
スタイルシートをインポートする
コンポーネントはオーバーレイのマークアップを出力しますが、CSSは出力しません。提供されているスタイルシートを、他のパッケージCSSのインポートと並べて、global.cssの先頭でインポートしてください。
@import "@takazudo/zudo-doc/page-loading.css";Warning
このインポートは、global.css内のあらゆるルール文よりも前に置かなければなりません。CSSではすべての@importルールが他のルールに先行する必要があります。セレクターや@themeブロックの後ろに置くと、インポートは黙って破棄され、オーバーレイはスタイルが当たらないまま表示されてしまいます。
スタイルシートが参照するホストトークン
このスタイルシートはいくつかのホストのデザイントークンを読み取ります。いずれもオプションで、それぞれに妥当なフォールバックが組み込まれているため、これらを一切定義していない素の状態のプロジェクトでもオーバーレイは動作します。
| トークン | 用途 | フォールバック |
|---|---|---|
--color-page-loading-overlay | スクリム(オーバーレイの背景) | color-mix(in oklch, var(--color-overlay) 60%, transparent) |
--color-overlay | 上記スクリムのフォールバックの下地となる色 | #000(上記フォールバック内でのみ使用) |
--color-fg | スピナーのボーダー色 | #fff |
--color-accent | 遷移待ち中のリンク/ボタンのハイライト | (フォールバックなし — 未設定ならハイライトは単に省略される) |
--z-index-modal | オーバーレイの重ね順 | 100 |
プロジェクトがzudo-docの標準的なセマンティックトークンをすでに定義していれば、オーバーレイは自動的にそれらを拾い、追加の作業なしでテーマに馴染みます。
スクリムを独立して調整する
スクリムは専用のトークン--color-page-loading-overlayを読むようになり、ライトボックス(画像拡大)の背景(--color-overlay)とは切り離されています。これを設定すれば、他のオーバーレイに一切触れることなく、ローディングのスクリムだけを調整できます。
@theme {
/* ローディングオーバーレイ専用の、明るくすりガラス調のブランドスクリム。
画像ライトボックスは引き続き --color-overlay を使う。 */
--color-page-loading-overlay: color-mix(
in oklch,
var(--color-bg) 70%,
transparent
);
}--color-page-loading-overlayが未設定の場合、スタイルシートは--color-overlayを不透明度60%で混ぜた色にフォールバックします。そのため既存のプロジェクトは変更なしでこれまでどおりの見た目を保ちます。
手でコピーしたオーバーレイのルールを削除する
このスタイルシートが提供される前は、独自レイアウトの利用者はオーバーレイ・スピナー・遷移待ちリンクのルールを自分のglobal.cssに手でコピーする必要がありました。それをしていた場合は、@importを採用する際にコピーしたルールを削除してください。両方を残すと、@keyframes page-loading-spinが重複し、.page-loading-overlay / .page-loading-spinnerの宣言が衝突します。どちらのルールが勝つかは記述順に依存し、間違えやすいものです。提供されるスタイルシートが今後は唯一の真実の源(single source of truth)です。