🛀

Astro × swupでシームレスなページ遷移を実装してみた

2023/08/28に公開

はじめに

ページ遷移がシームレスになるだけで、Webサイトのクオリティが格段に上がったように感じるのは私だけでしょうか。最近では、このようなサイトを見かけることも珍しくなくなった気がします。
今回はAstroでシームレスなページ遷移(以下「非同期遷移」と呼ぶ)を実装してみました。
完成したサイトはこちら

swup導入までの経緯

非同期遷移実現へのアプローチ

そもそも、非同期遷移の実装方法には、大きく2種類がある。1つ目はSPAレンダリングが可能なJavaScriptフレームワークを使用する方法で、ReactやVueなどが用いられる。2つ目はページのリロードなしでコンテンツを非同期に更新することができるJavaScriptのライブラリを利用する方法で、Barbaなどが用いられる。
今回はAstroを使用するという前提だったため、後者の方法を採用した。

ライブラリの選定

ライブラリの選定となるが、私はBarba一択だろうと考えていた。
しかし、Barbaをそのまま使うだけでは不完全であり、タイトル以外のhead要素の書き換えなどをカスタマイズして使用する必要があることが分かった。
そこで、参考となる記事やソースコードを探していたところ、こちらの記事を発見した。
こちらの記事はAstroにページ遷移アニメーションを実装する方法としてswupというライブラリを提案していた。
初めて知ったライブラリだったが、前述したbarbaでカスタマイズ必須の部分がプラグインでサポートされているらしい。また、その他のプラグインを利用することで、様々なユースケースに対するサポートが可能であるということだった。とてもアツい話だ。
さらにswupの知見を深めるため公式ドキュメントを読んでいると、なんとAstroのインテグレーションとしてのリリースが数日前に行われていた。さらにアツい話だ。(Announcing swup 4 | Official Astro integration )
この時、私の心は既にswupで満たされていた。
(この数日後、Astro2.9がリリースされ、View Transitionの機能が発表された。experimental(実験的)の段階ではあるが、今回swupを使用して実現しようとしていたことは、概ね実現可能な予感がした。しかし私の心は既にswupと共にあった。)

swupの設定

公式ドキュメントを参考にswupの導入を進めていく。
以下に設定方法を記していくが、基本的に公式ドキュメントにならって使用しています。

インストール

パッケージをインストール

npm install @swup/astro

設定ファイルのintegrationsに適用する。

astro.config.mjs
import { defineConfig } from 'astro/config';
import swup from '@swup/astro';

export default defineConfig({
  integrations: [swup()]
});

この時点で一度、開発サーバーを起動して確認してみてください。
異なるページに移動すると、ブラウザの更新無しでmainタグ以下の要素が書き換わっているはずです。

Astroの設定ファイルを修正

次にswupのオプションを変更します。
先程と同じく、Astroの設定ファイルを修正します。
各オプションのデフォルト値とオプションの説明一覧を確認しながらプロジェクトの性質に合わせて設定してください。
オプション設定の変更が、ライブラリとして利用した際のプラグインのインストールと同じ役割を果たすようです。めちゃくちゃ楽ですね。

astro.config.mjs
import { defineConfig } from 'astro/config';
import swup from '@swup/astro';

export default defineConfig({
  integrations: [
    swup({ 
      theme: false, //デフォルトで用意されている遷移アニメーションは使用しない
      smoothScrolling: false, //スムーズスクロール無効化
      updateBodyClass: true, //ページ遷移時にbody要素のクラス名を更新する
      reloadScripts: false //遷移後にスクリプトを再読み込みさせない
    }),
  ]
});

遷移アニメーションの実装

次に、アニメーションの実装に移ります。
swupではページ遷移の開始から終了までの工程をhtmlタグのクラス名に反映しています。
is-animating
リンクがクリックされたときに割り当てられ、ページの内容が置き換えられた後に削除されます。未ロードのページのスタイルを定義するために使用されます。
is-changing
リンクがクリックされたときに割り当てられ、全体の遷移プロセスが終了した後に削除されます。ローディング状態を表示するために使用されます。
is-leaving
リンクがクリックされたときに割り当てられ、内容が置き換えられる直前に削除されます。遷移の離脱フェーズを識別するために使用されます。is-animatingと組み合わせて、異なる離脱と入力の遷移を作成します。
is-rendering
内容が置き換えられる直前に割り当てられます。全体の遷移プロセスが終了した後に削除されます。遷移の入力フェーズを識別するために使用されます。is-animatingと組み合わせて、異なる離脱と入力の遷移を作成します。
to-[custom-transition]
クリックされたリンクに[data-swup-transition]属性がある場合に割り当てられます。特定のURLのアニメーションを変更するために使用できます。

正直、私自身も上手く使い分けができていません。
公式サンプルが用意されているので、こちらのソースコードを参考にしながら作ってみるのが良いかもしれません。

JavaScriptを書く

必要に応じて、ブラウザ上で実行するJavaScriptを書きます。
今回は、jsファイルをsrcディレクトリで管理し、ベースレイアウトでインポートする方法で実装しています。

フックを利用して、ページ遷移に合わせて任意の処理を実行する

swupには様々なタイミングを検知するフックが用意されているため、こちらを利用します。
フックの一覧を確認しながら、実装を進めます。
ページ遷移中のライフサイクルについては図式化されているので非常にわかりやすいです。

↓以下は今回私が実装で活用したフックとその実装例です。↓

swupのセットアップを検知する(enable)
/src/scripts/hoge.js
// 実装例:swupの設定が完了するまでローディング画面を表示
swup.hooks.on('enable',() => {
    // ローディング画面の非表示処理
    // ...
});
離脱アニメーションが始まる前に発火する処理(visit:start)
/src/scripts/hoge.js
// 実装例:ハンバーガーメニューを閉じる
// gsapのスクロールトリガーを削除する
swup.hooks.on('enable',() => {
    // ハンバーガーメニューを閉じる
    // ...
    // gsapのスクロールトリガーを削除する
     ScrollTrigger.killAll();
});
遷移後アニメーションが始まる前に発火する処理(content:replace)
/src/scripts/hoge.js
// 実装例:遷移先のページを識別する
// ナビのcurrentクラスを付け替える
// ページ固有の処理を実行する
swup.hooks.on('content:replace',() => {
    // 遷移先のページを識別する
    const $body = document.getElementsByTagName("body")[0];
    // ナビのcurrentクラスを付け替える
    header.setCurrentPage($body);
    // ページ固有の処理を実行する
    if($body.classList.contains('top')) {
        topAnimation.init();
    }
});

まとめ

Astroのインテグレーションとしてリリースされたswupを使用してみました。
設定内容をしっかりと理解したうえで使用すれば、独自のカスタマイズ無しでも使えるので、手軽に非同期遷移を実装できると思います。

Discussion