この記事の概要
View Transitions APIを使った画面遷移はスムーズで見栄えも良いです。
ただしtransitionの対象が画面外にあると一瞬表示崩れにも見える挙動をします。
上記の内容に対する、Astroでの解消方法を記事にしました。
起きることと、対処した後の結果
次のgifでは以下の操作をしています
- ページ遷移→すぐさま(= transition対象が画面内にある状態で)ブラウザバック
- ページ遷移→スクロールし(= transition対象が画面内にない状態で)ブラウザバック
transition対象が画面内にない状態でのブラウザバックでは、画面外から画像が降ってくるような挙動になっており、やや違和感があります。
これを、次のように「transition対象が画面内にない状態で遷移した場合、単なるディゾルブ効果」に変更します。
やること
遷移させるにあたって、次のようなコードがあるはずです。
<div transition:name={someName}>何かしらの要素</div>
AstroでView Transitionsを実装する方法自体はこの記事では触れません。公式ドキュメントなどをご覧ください。
遷移対象の要素にid
を付与します。
- <div transition:name={someName}>何かしらの要素</div>
+ <div id="something" transition:name={someName}>何かしらの要素</div>
その上で以下のコードを追加します。
<script>
function setupImageTransition() {
const somethingElement = document.querySelector("#something");
if (!somethingElement) return;
const initialScope = somethingElement.getAttribute("data-astro-transition-scope");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && initialScope) {
somethingElement.setAttribute("data-astro-transition-scope", initialScope);
} else {
somethingElement.removeAttribute("data-astro-transition-scope");
}
});
},
{
threshold: 0.1,
},
);
observer.observe(somethingElement);
}
document.addEventListener("astro:page-load", setupImageTransition);
</script>
ポイントは2点です。
-
setAttribute
,removeAttribute
する対象はtransition:name
ではなくdata-astro-transition-scope
-
initialScope
として最初の状態のdata-astro-transition-scope
を保持しておく
setAttribute
, removeAttribute
する対象はtransition:name
ではなくdata-astro-transition-scope
Astroに同一要素として判断してもらうためにはtransition:name
を記載する必要があります。
しかし、この値そのもので同一化を判断しているわけではありません。
この値をもとにして生成されたdata-astro-transition-scope
が判断材料です。
removeAttribute
でtransition:name
を消しても、既にdata-astro-transition-scope
が付与されてしまっており、最初に貼ったgifから動きは変わりません。
そのためdata-astro-transition-scope
を操作します。
initialScope
として最初の状態のdata-astro-transition-scope
を保持しておく
当たり前ですが、一度data-astro-transition-scope
を削除したら、単にsetAttribute
したところで値は戻ってきません。
そのため、最初のdata-astro-transition-scope
を保持しておく必要があります。