Skip to content
Mash+

Astro の <ClientRouter /> 導入メモ

ページ遷移時のちらつき(FOUC)が気になったため、Astro の <ClientRouter /> を導入して解決したときのメモ。

追記(2026/04/11):
FOUC の原因を解消したため、現在は <ClientRouter /> を使用していない。
参照:ページ遷移のちらつき(FOUC)は @view-transition が原因だった

Astro の <ClientRouter /> とは

Astro の <ClientRouter /> は、ページ遷移のアニメーションを追加したり、クライアントサイドルーティングを有効にして、SPA(シングルページアプリケーション)のような振る舞いにするコンポーネントだ。

<ClientRouter /> コンポーネントを <head> 内に追加することで導入できる。 これだけで FOUC の問題が解決した。

スクリプトの再実行

Astro のスクリプトは通常 1 回しか実行されない。 そのため、クライアントサイドルーティングによってページの一部が置き換わるようになると、ページ遷移後にスクリプトが実行されなくなる。

ページ遷移後に実行が必要なスクリプトに対しては、以下の対応を行った。

astro:after-swap

astro:after-swap は、ページ遷移して新しい DOM に置き換わったとき(描画前)に発生するライフサイクルイベントだ。 初回表示や再読み込み時には発生しない。

テーマの設定に使用した。

Layout.astro
<script is:inline>
function applyTheme() {
const theme = (() => {
const localStorageTheme = localStorage?.getItem("theme") ?? "";
if (["dark", "light"].includes(localStorageTheme)) {
return localStorageTheme;
}
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
return "dark";
}
return "light";
})();
document.documentElement.setAttribute("data-theme", theme);
window.localStorage.setItem("theme", theme);
}
document.addEventListener("astro:after-swap", applyTheme);
applyTheme();
</script>

astro:page-load

astro:page-load は、ページ読み込みの最後に発生するライフサイクルイベントだ。 ページ遷移のたびに発生するため、基本的にはこれを使用すればよい。

TOC.astro
<script>
function setupTOC() {
...
}
setupTOC();
document.addEventListener("astro:page-load", setupTOC);
</script>

スムーススクロールの限定

ページ全体にスムーススクロールを設定していたので、クライアントサイドルーティングによってブラウザの戻る操作をした際にも、スクロールのアニメーションが発生するようになった。

スムーススクロールは見出しのアンカーリンクでのみ適用したかったため、:has():target を使って対応した。

Layout.Astro
<html
lang={site.lang}
class="scroll-smooth bg-base-100 text-base-content antialiased"
class="has-[:target]:scroll-smooth bg-base-100 text-base-content antialiased"
>

まとめ

  • <ClientRouter /> は、ページ遷移のアニメーションを追加したり、部分的な DOM 置換を可能にするコンポーネント。
  • astro:after-swapastro:page-load などのイベントを使用することで、ページ遷移後のスクリプト実行を制御できる。
  • :has():target を組み合わせれば、スムーススクロールの適用範囲をアンカーリンクのみに限定できる。

参考