コンテンツにスキップ

ビュートランジション

Astroでは、オプトイン式ページ単位のビュートランジションを数行のコードで実現できます。ビュートランジションは、ブラウザがナビゲーション時に通常おこなうページ全体の更新なしでページコンテンツを更新し、ページ間のシームレスなアニメーションを提供します。

Astroは、単一のページの<head>に追加可能な<ClientRouter />ルーティングコンポーネントを提供しており、これにより別ページへの遷移を制御できます。このコンポーネントは軽量なクライアントサイドルーターを提供し、ナビゲーションをインターセプトしてページ間の遷移をカスタマイズできるようにします。

このコンポーネントを共通のヘッドやレイアウトなど再利用可能な.astroコンポーネントに追加すると、サイト全体でのアニメーション付きのページ遷移(SPAモード)が可能になります。

Astroのビュートランジションは新しいView TransitionsブラウザAPIによって提供されており、また以下の機能も含みます。

<ClientRouter />ルーティングコンポーネントをインポートし、<head>内に追加することで、ビュートランジションを個別のページで有効化できます。

src/pages/index.astro
---
import { ClientRouter } from 'astro:transitions';
---
<html lang="ja">
<head>
<title>私のホームページ</title>
<ClientRouter />
</head>
<body>
<h1>私のウェブサイトへようこそ!</h1>
</body>
</html>

サイト全体でのビュートランジション(SPAモード)

セクションタイトル: サイト全体でのビュートランジション(SPAモード)

<ClientRouter />をインポートし、共通の<head>または共有のレイアウトコンポーネントに追加します。Astroは、旧ページと新ページの類似点に基づいてデフォルトのページアニメーションを作成し、サポートされていないブラウザに対するフォールバック動作も提供します。

以下の例では、このコンポーネントをインポートし<CommonHead /> Astroコンポーネントに追加することで、Astroのデフォルトのページナビゲーションアニメーションをサイト全体に追加しています。これにより、サポートされていないブラウザに対するフォールバック動作も追加されます。

components/CommonHead.astro
---
import { ClientRouter } from 'astro:transitions';
---
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<!-- 主要メタタグ -->
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />
<ClientRouter />

Astroのデフォルトのクライアントサイドナビゲーションを有効にするために、他に必要な設定はありません!

より細かな制御のためには、トランジションディレクティブを使用するか、個々の要素でデフォルトのクライアントサイドナビゲーションをオーバーライドします。

Astroは、旧ページと新ページの両方に存在する対応する要素に、共通かつ一意のview-transition-nameを自動的に割り当てます。マッチする要素のペアは、要素の種類とDOM内の位置の両方によって推測されます。

.astroコンポーネント内のページ要素にオプションのtransition:*ディレクティブを使用すると、ナビゲーション中のページ遷移の動作をより細かく制御できます。

場合によっては、対応するビュートランジション要素を自分で特定したい、または特定する必要があるかもしれません。transition:nameディレクティブを使用して、要素のペアに名前を付けることができます。

old-page.astro
<aside transition:name="hero">
new-page.astro
<aside transition:name="hero">

transition:nameに使った値は、各ページにつき1回しか使用できないことに注意してください。Astroが適切な名前を自動的に推測できない場合や、要素のマッチングをより細かく制御したい場合に、手動で設定してください。

追加: astro@2.10.0

transition:persistディレクティブを使用すると、ページ間のナビゲーションでコンポーネントとHTML要素を(置き換えるのではなく)保持できます。

たとえば以下の<video>は、同じvideo要素を含む別のページに移動しても再生され続けます。これは、進む・戻るの両方のナビゲーションで機能します。

components/Video.astro
<video controls="" autoplay="" transition:persist>
<source src="https://ia804502.us.archive.org/33/items/GoldenGa1939_3/GoldenGa1939_3_512kb.mp4" type="video/mp4">
</video>

Astroアイランドclient:ディレクティブをもつUIフレームワークコンポーネント)にもディレクティブを配置できます。そのコンポーネントが次のページに存在する場合、旧ページのアイランドは現在の状態のまま表示され、新しいページのアイランドに置き換えられることはありません。

以下の例では、transition:persist属性をもつ<Counter />コンポーネントを含むページ間を行き来しても、countはリセットされません。

components/Header.astro
<Counter client:load transition:persist count={5} />

また、アイランドあるいは要素が2つのページ間で異なるコンポーネントの中にある場合は、対応する要素を手動で特定できます。

pages/old-page.astro
<Video controls="" autoplay="" transition:name="media-player" transition:persist />
pages/new-page.astro
<MyVideo controls="" autoplay="" transition:name="media-player" transition:persist />

便利な短縮記法として、transition:persistの値にトランジション名を指定できます。

pages/index.astro
<video controls="" autoplay="" transition:persist="media-player">
追加: astro@4.5.0

transition:persist-propsディレクティブを使うと、アイランドのpropsをページ遷移時に保持するかどうかを制御できます。

デフォルトでは、アイランドにtransition:persistを追加すると状態は保持されますが、コンポーネントは新しいpropsで再レンダリングされます。たとえば、ページごとに異なるtitleなどをpropsとして受け取る場合に便利です。

transition:persist-propstransition:persistと併用すると、この動作は上書きされます。アイランドのpropsは再レンダリングされず、現在の状態が維持されます。

Astroには、デフォルトのfadeトランジションをオーバーライドするための組み込みのアニメーションがいくつか用意されています。transition:animateディレクティブを各要素に追加して、特定のトランジションの動作をカスタマイズできます。

  • fade(デフォルト): 独自のクロスフェードアニメーションです。旧コンテンツがフェードアウトし、新コンテンツがフェードインします。
  • initial: Astroの独自のクロスフェードアニメーションを無効にし、ブラウザのデフォルトのスタイルを使用します。
  • slide: 旧コンテンツが左にスライドアウトし、新コンテンツが右からスライドインするアニメーションです。戻る場合のナビゲーションでは、アニメーションは逆になります。
  • none: ブラウザのデフォルトのアニメーションを無効にします。ページの<html>要素で使用すると、ページ内のすべての要素のデフォルトのフェードを無効にします。

ページのアニメーションを完全に制御するには、ディレクティブを組み合わせます。<html>要素でページのデフォルト値を設定し、必要に応じて個々の要素でオーバーライドしてください。

以下の例では、ボディコンテンツにスライドアニメーションを設定し、ページの残りの部分に対してはブラウザのデフォルトのフェードアニメーションを無効にしています。

---
import { CommonHead } from '../components/CommonHead.astro';
---
<html transition:animate="none">
<head>
<CommonHead />
</head>
<body>
<header>
...
</header>
<!-- 個別の要素でページデフォルトをオーバーライドします -->
<main transition:animate="slide">
...
</main>
</body>
</html>

任意のCSSアニメーションプロパティを使用して、トランジションのすべての要素をカスタマイズできます。

組み込みのアニメーションをカスタマイズするには、まずastro:transitionsからアニメーションをインポートし、続いてカスタマイズ用オプションを渡します。

以下の例では、組み込みのfadeアニメーションの継続時間(duration)をカスタマイズしています。

---
import { fade } from 'astro:transitions';
---
<header transition:animate={fade({ duration: '0.4s' })}>

また、transition:animateで独自のアニメーションも定義できます。進む・戻るの挙動と新旧のページについて、以下の型に従って定義します。

export interface TransitionAnimation {
name: string; // キーフレームの名前
delay?: number | string;
duration?: number | string;
easing?: string;
fillMode?: string;
direction?: string;
}
export interface TransitionAnimationPair {
old: TransitionAnimation | TransitionAnimation[];
new: TransitionAnimation | TransitionAnimation[];
}
export interface TransitionDirectionalAnimations {
forwards: TransitionAnimationPair;
backwards: TransitionAnimationPair;
}

カスタムアニメーションbumpをルートレイアウトファイルの<style is:global>タグ内で定義するために必要な全てのプロパティは以下の通りです。

src/layouts/Layout.astro
---
import { ClientRouter } from "astro:transitions";
---
<html lang="ja">
<head>
<ClientRouter />
</head>
<body>
<slot />
</body>
</html>
<style is:global>
@keyframes bump {
0% {
opacity: 0;
transform: scale(1) translateX(200px);
}
50% {
opacity: 0.5;
transform: scale(1.1);
}
100% {
opacity: 1;
transform: scale(1) translateX(0);
}
}
</style>

アニメーションの挙動は、アニメーションを使用する各コンポーネントのフロントマターで定義する必要があります。

src/pages/index.astro
---
const anim = {
old: {
name: "bump",
duration: "0.5s",
easing: "ease-in",
direction: "reverse",
},
new: {
name: "bump",
duration: "0.5s",
easing: "ease-in-out",
},
};
const customTransition = {
forwards: anim,
backwards: anim,
};
---
<header transition:animate={customTransition}> ... </header>

カスタムアニメーションを定義はとても柔軟に行えます。目的の動作を実現するために、進む・戻るで異なるオブジェクトを使ったり、old/newで別々のキーフレームアニメーションを指定したりといった工夫もできます。

<ClientRouter />ルーターは、以下のイベントでナビゲーションを制御します。

  • <a>要素のクリック
  • 戻る・進むのナビゲーションイベント

さらに、以下の属性や関数で挙動を細かく制御できます。

  • data-astro-reload: <a><form>タグに付与すると、クライアントサイドナビゲーションを強制的に無効化し、フルページ遷移にします。
  • data-astro-history="auto | push | replace": <a>タグに付与すると、ブラウザの履歴の扱いを制御できます。
  • navigate(href, options): クライアントスクリプトやフレームワークコンポーネントからナビゲーションをトリガーできます。

<ClientRouter />コンポーネントを追加してページでクライアントサイドルーティングを有効にすると、サイト内の別のページにリンクするページ内のすべてのアンカーは、クライアントサイドルーティングによってナビゲートされます。ただ、クライアントサイドルーティングでナビゲートしたくないような場合もあります。たとえば、public/フォルダ内のPDFや、画像を生成するAPIルートなどの非ページへのリンクです。

こうした場合、data-astro-reload属性を使用して、リンクごとにクライアントサイドルーティングをオプトアウトできます。

以下の例は、ホームページから記事に移動する際にクライアントサイドルーティングを防止する方法です。同様に、記事一覧ページから同じページに移動する場合のように、ヒーロー画像などの共有要素にアニメーションを適用することも可能です。

<a href="/quarterly-earnings.pdf" data-astro-reload>

これらのリンクはルーターによって無視され、フルページのナビゲーションが発生します。

astro:transitions/clientモジュールのnavigate関数を使うと、通常のリンク以外のイベントでもクライアントサイドナビゲーションを発生させることができます。

components/Form.astro
<script>
import { navigate } from "astro:transitions/client";
document.querySelector("select").onchange = (event) => {
let href = event.target.value;
navigate(href);
};
</script>
<select>
<option value="/play">Play</option>
<option value="/blog">Blog</option>
<option value="/about">About</option>
<option value="/contact">Contact</option>
</select>
src/pages/index.astro
---
import Form from "../components/Form.astro";
import { ClientRouter } from "astro:transitions";
---
<html>
<head>
<ClientRouter />
</head>
<body>
<Form />
</body>
</html>

クライアントディレクティブでハイドレートされたフレームワークコンポーネント内でもnavigateを使用できます。

src/components/Form.jsx
import { navigate } from "astro:transitions/client";
export default function Form() {
return (
<select onChange={(e) => navigate(e.target.value)}>
<option value="/play">Play</option>
<option value="/blog">Blog</option>
<option value="/about">About</option>
<option value="/contact">Contact</option>
</select>
);
}

この<Form /> コンポーネントは、<ClientRouter />ルーターを使用するAstroページに、クライアントディレクティブを使用してレンダリングできます。

src/pages/index.astro
---
import Form from "../components/Form.jsx";
import { ClientRouter } from "astro:transitions";
---
<html>
<head>
<ClientRouter />
</head>
<body>
<Form client:load />
</body>
</html>

navigateは以下のオプションを受け取ります。

  • href(必須): 遷移先のURL
  • options:
    • history: "push" | "replace" | "auto"
      • push: 「history.pushState」を使用して、ブラウザの履歴に新しいエントリを作成します。
      • replace: 「history.replaceState」を使用して、現在の履歴を上書きします。
      • auto(デフォルト): ルーターは ‘history.pushState’ を試みますが、遷移先のURLが有効でない場合、現在のURLはブラウザの履歴を変更せずに残ります。
    • formData: POSTリクエストを送信するためのFormDataオブジェクト。

ブラウザの履歴を使った「戻る」「進む」ナビゲーションには、navigate()と組み合わせて、ブラウザ組み込みのhistory.back()history.forward()history.go()関数を利用できます。なお、navigate()がコンポーネントのサーバーサイドレンダリング中に呼び出された場合は、何も起こりません。

通常、ナビゲーションごとにブラウザの履歴に新しいエントリが追加されますが、data-astro-history属性を<a>タグに付与することで、履歴の追加方法を制御できます。

  • push: history.pushStateで新しい履歴エントリを追加します。
  • replace: history.replaceStateで現在の履歴を上書きします。
  • auto(デフォルト): 遷移先のURLが有効な場合はpushStateを実行し、そうでなければブラウザの履歴を更新しません。
pages/confirmation.astro
<a href="/main" data-astro-history="replace">
追加: astro@4.0.0

<form>要素でもGET/POSTの両方に対応したクライアントサイドトランジションが利用できます。

デフォルトでは、POST時はmultipart/form-dataで送信されます。通常のブラウザと同じapplication/x-www-form-urlencodedで送信したい場合はenctype属性を指定してください。

components/Form.astro
<form action="/contact" method="POST" enctype="application/x-www-form-urlencoded">

data-astro-reload属性を付与すると、そのフォームだけクライアントサイドトランジションを無効化できます。

components/Form.astro
<form action="/contact" data-astro-reload>

<ClientRouter />ルーターは、ビュートランジションをサポートするブラウザ(すなわちChromium系ブラウザ)で最も有効に機能しますが、他のブラウザにもデフォルトのフォールバックサポートが含まれています。ブラウザがView Transitions APIをサポートしていない場合でも、Astroのクライアントルーターはフォールバックオプションのいずれかを使ってブラウザ内ナビゲーションを提供できます。

サポート状況によっては、すべてのブラウザで同等の体験を得るために、アニメーションさせたい要素にnameanimateトランジションディレクティブを明示的に設定する必要があります。

src/pages/about.astro
---
import Layout from "../layouts/LayoutUsingClientRouter.astro";
---
<title transition:animate="fade">このサイトについて</title>

<ClientRouter />コンポーネントにfallbackプロパティを追加し、swapまたはnoneに設定することで、Astroのデフォルトのフォールバックサポートをオーバーライドできます。

  • animate (デフォルト、推奨) - Astroは、ページコンテンツを更新する前に、カスタム属性を使用してビュートランジションをシミュレートします。
  • swap - Astroはページのアニメーションを試みません。代わりに、旧ページはすぐに新しいページに置き換えられます。
  • none - Astroはアニメーションによるページ遷移を一切おこないません。代わりに、サポート外のブラウザではフルページのナビゲーションがおこなわれます。
---
import { ClientRouter } from 'astro:transitions';
---
<title>私のサイト</title>
<ClientRouter fallback="swap">

<ClientRouter />ルーターを使用すると、以下の流れでAstroのクライアントサイドナビゲーションが実行されます。

  1. サイト訪問者が以下のいずれかのアクションを実行し、ナビゲーションが実行されます。

    • サイト内の別のページへ内部リンクする<a>タグをクリックする。
    • 戻るボタンをクリックする。
    • 進むボタンをクリックする。
  2. ルーターが次のページの取得を開始します。

  3. ルーターが、'forward'または'back'の値をもつdata-astro-transition属性をHTML要素に追加します。

  4. ルーターがdocument.startViewTransitionをコールします。これにより、ブラウザのview transition processがトリガーされます。このとき、ブラウザはページの現在の状態をスクリーンショットします。

  5. startViewTransitionコールバック内で、ルーターがswapを実行します。これは以下の一連のイベントから構成されます。

    • <head>のコンテンツが、いくつかの要素を残して入れ替わる。

      • FOUCを防止するために、スタイルシートのDOMノードが新しいページに存在する場合は残されます。
      • 新しいページにスクリプトが存在する場合は残されます。
      • 新しいページに対応する要素がある場合、transition:persistをもつ他のhead要素は残されます。
    • <body>は、新しいページのbodyに完全に置き換えられる。

    • transition:persistとマークされた要素が新しいページに存在する場合、新しいDOMに移動する。

    • 必要に応じてスクロール位置が復元される。

    • astro:after-swapイベントがdocumentでトリガーされます。ここでswapプロセスが終了する。

  6. ルーターが、トランジションを解決する前に新しいスタイルシートのロードを待ちます。

  7. ルーターが、ページに追加された新しいスクリプトを実行します。

  8. astro:page-loadイベントが発生します。これでナビゲーションプロセスが完了します。

<ClientRouter />コンポーネントを使ってページ間を遷移する場合、スクリプトはブラウザの挙動に合わせて順番に実行されます。

  • Astroのバンドル済みモジュールスクリプトは1度だけ実行され、再遷移時は無視されます。
  • インラインスクリプトは、ページを再訪した場合や、同じスクリプトが含まれるページに戻った場合に再実行されることがあります。

スクリプトを確実に再実行したい場合は、ライフサイクルイベント(後述)でラップしてください。

<ClientRouter />コンポーネントを使用してページ間を遷移する場合、スクリプトはブラウザの挙動に合わせて順番に実行されます。

バンドル済みモジュールスクリプト(Astroのデフォルトスクリプト)は、初回実行後は再遷移時に無視されます。同じスクリプトが新しいページに含まれていても再実行されません。

一方で、インラインスクリプトは、訪問者が複数回同じページを訪れた場合や、スクリプトが含まれるページに戻った場合に再実行される可能性があります。

ビュートランジションを使用すると、ページ遷移後に一部のスクリプトがフルページリフレッシュ時のように再実行されなくなる場合があります。クライアントサイドルーティング中に発生するイベントを監視し、適切なタイミングでスクリプトを実行することができます。

以下の例では、モバイル用の「ハンバーガーメニュー」のスクリプトをastro:page-loadイベントリスナーでラップし、ページ遷移後にクリックに反応するようにしています。このイベントはページ遷移の終了時に発生します。

src/scripts/menu.js
document.addEventListener("astro:page-load", () => {
document.querySelector(".hamburger").addEventListener("click", () => {
document.querySelector(".nav-links").classList.toggle("expanded");
});
});

次の例は、astro:after-swapイベントに応答して実行される関数を示しています。このイベントは、新しいページが古いページを置き換えた直後、DOM要素が画面に描画される前に発生します。これにより、ページ遷移後にライトモードが一瞬表示されるのを防ぐために、ダークモードのテーマを確認し、必要に応じて設定します。

src/components/ThemeToggle.astro
<script is:inline>
function applyTheme() {
localStorage.theme === "dark"
? document.documentElement.classList.add("dark")
: document.documentElement.classList.remove("dark");
}
document.addEventListener("astro:after-swap", applyTheme);
applyTheme();
</script>
追加: astro@4.5.0

インラインスクリプトにdata-astro-rerun属性を付与すると、ページ遷移ごとに必ず再実行されます。

<script is:inline data-astro-rerun>...</script>

グローバルな状態を設定する場合は、スクリプトが複数回実行される可能性を考慮し、windowなどで状態を判定してください。

<script is:inline>
if (!window.SomeGlobal) {
window.SomeGlobal = {};
}
</script>

モジュールスクリプトは、ブラウザがロード済みのモジュールを追跡しているため、常に1回だけ実行されます。これらのスクリプトでは再実行の心配は必要ありません。

<ClientRouter /> ルーターは、ナビゲーション中に document 上で複数のイベントを発生させます。これらのイベントは、ナビゲーションのライフサイクルにフックし、新しいページのローディングインジケーターの表示や、デフォルト動作の上書き、ナビゲーション完了時の状態復元などに利用できます。

ナビゲーションプロセスは、準備フェーズ(新しいコンテンツの読み込み)、DOMスワップフェーズ(古いページの内容が新しいページの内容に置き換えられる)、完了フェーズ(スクリプトの実行やローディング完了の通知、クリーンアップなど)で構成されます。

AstroのView Transition APIのライフサイクルイベントは、以下の順で発生します。

一部のアクションはどのイベントでも実行できますが、ローディングスピナーの表示や、スワップ前のアニメーションペアの上書きなど、特定のイベントでのみ最適に実行できるタスクもあります。

追加: astro@3.6.0

ナビゲーションが開始された直後(例:リンククリック直後)、コンテンツの読み込み前に発生するイベントです。

このイベントは以下の用途で使えます。

  • ローディング開始前にスピナーを表示するなどの処理。
  • 外部URLではなくテンプレートで定義したコンテンツを読み込むなど、ローディング処理の変更。
  • カスタムアニメーションのためにナビゲーションのdirection(通常はforwardまたはbackward)を変更。

以下は、astro:before-preparationイベントでスピナーを表示し、ローディング完了後に停止する例です。loaderコールバックを使うことで非同期処理が可能です。

<script is:inline>
document.addEventListener("astro:before-preparation", (event) => {
const originalLoader = event.loader;
event.loader = async function () {
const { startSpinner } = await import("./spinner.js");
const stop = startSpinner();
await originalLoader();
stop();
};
});
</script>

追加: astro@3.6.0

新しいページのコンテンツが読み込まれパースされた後、ビュー遷移フェーズの直前に発生するイベントです。

以下のように、astro:before-preparationでローディングインジケーターを表示し、astro:after-preparationで非表示にできます。

<script is:inline>
document.addEventListener("astro:before-preparation", () => {
document.querySelector("#loading").classList.add("show");
});
document.addEventListener("astro:after-preparation", () => {
document.querySelector("#loading").classList.remove("show");
});
</script>

上記は、すべての処理が同期的に実行できる場合のシンプルな例です。loaderコールバックを使う必要はありません。

追加: astro@3.6.0

準備フェーズで生成された新しいドキュメントが、現在のドキュメントに置き換わる直前に発生するイベントです。このイベントはビュー遷移中に発生し、ユーザーはまだ古いページのスナップショットを見ています。

このイベントでは、スワップ前に変更を加えることができます。event.newDocumentプロパティは、これから表示される新しいドキュメントを表します。以下は、localStorageのダークモード設定を新しいページにも適用する例です。

<script is:inline>
function setDarkMode(document) {
let theme = localStorage.darkMode ? "dark" : "light";
document.documentElement.dataset.theme = theme;
}
setDarkMode(document);
document.addEventListener("astro:before-swap", (event) => {
// 新しいドキュメントにもテーマを適用
setDarkMode(event.newDocument);
});
</script>

astro:before-swapイベントでは、スワップの実装自体も変更できます。デフォルトのスワップ実装は、headの内容の差分適用、__persistent__要素の移動、body全体の置き換えを行います。

このタイミングで、独自のスワップの実装(例:既存ドキュメント全体の差分適用)を定義することも可能です。

<script is:inline>
document.addEventListener("astro:before-swap", (event) => {
event.swap = () => {
diff(document, event.newDocument);
};
});
</script>

追加: astro@4.15.0

astro:transitions/clientモジュールのswapFunctionsオブジェクトは、ドキュメント属性やページ要素、スクリプト実行など、スワップ関連のタスクを処理する5つのユーティリティ関数を提供します。これらを使って独自のスワップ実装を定義できます。

以下は、Astroの組み込みスワップ実装を再現する例です。

<script>
import { swapFunctions } from "astro:transitions/client";
// `window.document`を`doc`で置き換え
function mySwap(doc: Document) {
swapFunctions.deselectScripts(doc);
swapFunctions.swapRootAttributes(doc);
swapFunctions.swapHeadElements(doc);
const restoreFocusFunction = swapFunctions.saveFocus();
swapFunctions.swapBodyElement(doc.body, document.body);
restoreFocusFunction();
}
event.swap = () => mySwap(event.newDocument);
<script>

カスタムスワップ実装はこのテンプレートをベースに、必要に応じて個別のステップを追加・置換できます。

旧ページが新ページに置き換わった直後に発生するイベントです。documentオブジェクトにイベントリスナーを登録して検知することで、新しいページのDOM要素が描画され、スクリプトが実行される前にアクションを実行できます。

遷移元ページでこのイベントを監視することで、新しいページに引き継ぐ必要のあるDOM上の状態を渡したり復元したりできます。

このタイミングは、例えばダークモード用のクラス名(<html class="dark-mode">)を追加するのに安全な最後のポイントです(より早いイベントで行っても構いません)。

astro:after-swapイベントは、ブラウザの履歴が更新され、スクロール位置が復元された直後に発生します。 そのため、履歴ナビゲーション時のデフォルトのスクロール復元を上書きする用途にも使えます。

document.addEventListener("astro:after-swap", () =>
window.scrollTo({ left: 0, top: 0, behavior: "instant" }),
);

あるいは、ダークモードのサポートを実装している場合、このイベントを使用してページロード間で状態を復元できます。

<script>
const setDarkMode = () => {
if (localStorage.darkMode) {
document.documentElement.dataset.dark = '';
}
};
// 初回のナビゲーションで実行される
setDarkMode();
// ビュートランジションのナビゲーションで実行される
document.addEventListener('astro:after-swap', setDarkMode);
</script>

新しいページが表示され、ブロッキングスタイルやスクリプトの読み込みが完了した後に発生するイベントです。documentオブジェクトでイベントを監視できます。

<ClientRouter />コンポーネントは、プリレンダリングされたページの初回ナビゲーション時と、その後のすべてのナビゲーション(進む・戻る含む)でこのイベントを発生させます。

このイベントを使って、ナビゲーションごとに毎回実行したいコード(例:イベントリスナーの再設定など)を記述できます。

<script>
document.addEventListener("astro:page-load", () => {
// 初回ページロードとすべてのナビゲーション後に実行されます。
setupStuff(); // 例:イベントリスナーの追加
});
</script>

クライアントサイドルーティングやページ遷移アニメーションの有効化にはアクセシビリティ上の課題も伴いますが、AstroはView Transitionsを利用するサイトがデフォルトでアクセシブルになるよう配慮しています。

追加: astro@3.2.0

<ClientRouter />コンポーネントは、クライアントサイドルーティング時のページナビゲーションにルーティングアナウンサーを含みます。

アクセシビリティ機能は、ナビゲーション後に新しいページタイトルをアナウンスすることで、ページが変わったことを利用者に伝えます。サーバーサイドルーティング(フルページリフレッシュ)ではこれが自動で行われますが、クライアントサイドルーティングでは<ClientRouter />がこの役割を担います。

ルーティングアナウンスのため、コンポーネントは新しいページにaria-live="assertive"属性を持つ要素を追加します。これによりアクセシビリティツールが以下の優先順位にしたがって、アナウンスします。

  • <title>が存在すればその内容
  • 最初に見つかった<h1>
  • ページのpathname

アクセシビリティ向上のため、各ページには必ず<title>を含めるようにしてください。

Astroの<ClientRouter />コンポーネントは、prefer-reduced-motion設定が検出された場合、フォールバックアニメーションを含むすべてのビュートランジションアニメーションを無効化するCSSメディアクエリを含みます。代わりに、ブラウザはアニメーションなしでDOM要素を単純にスワップします。

貢献する コミュニティ Sponsor