Astro 3.0 の ViewTransitions はどうなってるの?
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ ViewTransitions コンポーネントを追加するとそのページからの遷移は SPA になる
◆ JSON ではなく HTML を fetch して DOM を更新してる
◆ JSON ではなく HTML を fetch して DOM を更新してる
Astro の 3.0 が出たというニュースを見ました
https://astro.build/blog/astro-3/
CSR で SPA 好きの私的には SSR で MPA の方針である Astro はあんまり興味がなく使ったこともなかったのですが メジャーアップデートですし どんな感じになったのかなと軽い気持ちで見てみました
View Transitions に対応したそうです
Chrome 111 で追加されたアレですね
こんな感じにすると更新前後をいい感じにアニメーションしてくれます
CSS プロパティの view-transition-name を使って同じ要素であることを明示しておけば DOM の更新前後のその要素の位置に応じてアニメーションで移動してくれたりもします
並び替えや画像の拡大などをリッチに見せることができます
でもこれって 今のところは SPA のみの対応だったはずです
将来的には MPA にも対応予定とか見た覚えはありますが 対応したという情報は見ていません
Astro は MPA の方針なので MPA だと思うのですけど
それに 3.0 の新機能説明のデモのところで すべてサーバーでレンダーされた HTML だと書いています
どうやってるのか気になったので試してみることにしました
説明にあるように
を実行するとテンプレートから環境を準備してくれます
Astro では .astro ファイルに
という感じでコードを記述します
Astro View Transitions を使うには astro:transitions から ViewTransitions をインポートして HTML 内に含めます
同じ要素であることを明示するには属性に transition:name を指定します
page1 と page2 をこんな感じで用意しました
foo1, foo2, foo3 の並びだけ変わってます
上部が各ページへのリンクです
リンクから page1 と page2 間を移動すると foo1 と foo3 がアニメーションして入れ替わってます
すると MPA ではなく SPA になってました
発生している HTTP リクエストは fetch によるバックグラウンド通信のみで ページのナビゲーションは発生していません
それなら上に書いたように startViewTransition を実行するだけなので 特別すごいことはしていません
でも サーバーで HTML を作ってると MPA ぽいことを書いていましたがあれはなんだったのでしょう
もう少し色々見ているとその理由がわかりました
fetch で受け取っているものが JSON ではなく HTML でした
JSON を受け取ってそれをもとにブラウザ内で HTML を作るということはせず サーバーから HTML を受け取ってそれにそのまま置き換えてしまうということをしてるのですね
そういえば昔 私もそんなことしてみたことがありました
静的 SPA ページを作る
document.write で疑似 SPA
この HTML を fetch する実質 SPA は Astro の全体方針ではなく View Transitions 用の機能みたいです
通常は MPA として通常のブラウザのページ遷移が発生します
ViewTransitions コンポーネントを含めたページでは そのページからの遷移が MPA にならず SPA になるようです
https://github.com/withastro/astro/blob/astro%403.0.3/packages/astro/components/ViewTransitions.astro#L237-L260
という感じで HTML を取得して document.startViewTransition の中で DOM を更新しています
この updateDOM の処理では単純に innerHTML の全置換だけではなく ページ遷移後にも継続して保持したい要素を残したり スクロール位置を上に戻したりなど色々と工夫してるようです
見た感じでは document.body.replaceWith で body を全部置き換えて 保持したい要素を個別に後から置き換えてるみたいです
再生中の video タグの再生も維持できるそうですが 一旦ツリーから切断されることがあっても再生って維持できるのですね
https://astro.build/blog/astro-3/
CSR で SPA 好きの私的には SSR で MPA の方針である Astro はあんまり興味がなく使ったこともなかったのですが メジャーアップデートですし どんな感じになったのかなと軽い気持ちで見てみました
View Transitions に対応したそうです
Chrome 111 で追加されたアレですね
document.startViewTransition(() => {
/* ここで DOM を更新 */
})
こんな感じにすると更新前後をいい感じにアニメーションしてくれます
CSS プロパティの view-transition-name を使って同じ要素であることを明示しておけば DOM の更新前後のその要素の位置に応じてアニメーションで移動してくれたりもします
並び替えや画像の拡大などをリッチに見せることができます
<!DOCTYPE html>
<style>
div { font-size: 10vmin; margin: 10vmin; }
#e1 { view-transition-name: e1; }
#e2 { view-transition-name: e2; }
</style>
<script type="module">
b.onclick = () =>
document.startViewTransition(() => {
Array.from(document.querySelectorAll("div")).reverse().forEach(x => document.body.append(x))
})
</script>
<button id="b">REVERSE</button>
<div id="e1">1</div>
<div id="e2">2</div>
でもこれって 今のところは SPA のみの対応だったはずです
将来的には MPA にも対応予定とか見た覚えはありますが 対応したという情報は見ていません
Astro は MPA の方針なので MPA だと思うのですけど
それに 3.0 の新機能説明のデモのところで すべてサーバーでレンダーされた HTML だと書いています
どうやってるのか気になったので試してみることにしました
Astro View Transitions
使い始めるのは簡単でした説明にあるように
npm create astro@latest
を実行するとテンプレートから環境を準備してくれます
Astro では .astro ファイルに
---
// ここに JavaScript
// import など
---
ここに HTML
という感じでコードを記述します
Astro View Transitions を使うには astro:transitions から ViewTransitions をインポートして HTML 内に含めます
同じ要素であることを明示するには属性に transition:name を指定します
page1 と page2 をこんな感じで用意しました
---
import { ViewTransitions } from "astro:transitions"
---
<div>
<ViewTransitions />
<div><a href="/">TOP</a></div>
<div><a href="/page1">PAGE1</a></div>
<div><a href="/page2">PAGE2</a></div>
<hr/>
<div transition:name="foo1">foo1</div>
<div transition:name="foo2">foo2</div>
<div transition:name="foo3">foo3</div>
</div>
---
import { ViewTransitions } from "astro:transitions"
---
<div>
<ViewTransitions />
<div><a href="/">TOP</a></div>
<div><a href="/page1">PAGE1</a></div>
<div><a href="/page2">PAGE2</a></div>
<hr/>
<div transition:name="foo3">foo3</div>
<div transition:name="foo2">foo2</div>
<div transition:name="foo1">foo1</div>
</div>
foo1, foo2, foo3 の並びだけ変わってます
上部が各ページへのリンクです
リンクから page1 と page2 間を移動すると foo1 と foo3 がアニメーションして入れ替わってます
仕組み
どうなってるのか devtools を見てみましたすると MPA ではなく SPA になってました
発生している HTTP リクエストは fetch によるバックグラウンド通信のみで ページのナビゲーションは発生していません
それなら上に書いたように startViewTransition を実行するだけなので 特別すごいことはしていません
でも サーバーで HTML を作ってると MPA ぽいことを書いていましたがあれはなんだったのでしょう
もう少し色々見ているとその理由がわかりました
fetch で受け取っているものが JSON ではなく HTML でした
JSON を受け取ってそれをもとにブラウザ内で HTML を作るということはせず サーバーから HTML を受け取ってそれにそのまま置き換えてしまうということをしてるのですね
そういえば昔 私もそんなことしてみたことがありました
静的 SPA ページを作る
document.write で疑似 SPA
この HTML を fetch する実質 SPA は Astro の全体方針ではなく View Transitions 用の機能みたいです
通常は MPA として通常のブラウザのページ遷移が発生します
ViewTransitions コンポーネントを含めたページでは そのページからの遷移が MPA にならず SPA になるようです
https://github.com/withastro/astro/blob/astro%403.0.3/packages/astro/components/ViewTransitions.astro#L237-L260
// 略
const { html, ok } = await getHTML(href);
// If there is a problem fetching the new page, just do an MPA navigation to it.
if (!ok) {
location.href = href;
return;
}
document.documentElement.dataset.astroTransition = dir;
if (supportsViewTransitions) {
finished = document.startViewTransition(() => updateDOM(html, state)).finished;
} else {
finished = updateDOM(html, state, getFallback());
}
// 略
という感じで HTML を取得して document.startViewTransition の中で DOM を更新しています
この updateDOM の処理では単純に innerHTML の全置換だけではなく ページ遷移後にも継続して保持したい要素を残したり スクロール位置を上に戻したりなど色々と工夫してるようです
見た感じでは document.body.replaceWith で body を全部置き換えて 保持したい要素を個別に後から置き換えてるみたいです
再生中の video タグの再生も維持できるそうですが 一旦ツリーから切断されることがあっても再生って維持できるのですね