Blazor でも View Transition したい

## Web ブラウザの View Transition 機能

ここでいう "View Transition" というのは、Web ブラウザが提供する機能のことで、2 つの表示状態の遷移にアニメーション効果を付けることのできる、JavaScript API として公開されている機能です。

下記リンク先の冒頭の動画がわかりやすいです。画面間の遷移がアニメーション効果で滑らかに繋がってヌルヌル動きます。

https://developer.chrome.com/docs/web-platform/view-transitions

MDN の説明は以下のリンク先を参照ください。

https://developer.mozilla.org/ja/docs/Web/API/View_Transitions_API

基本的な使い方はとてもシンプルで、表示を変更・書換えを行なう処理を、`document` オブジェクトの `startViewTransition` メソッドに渡すだけです。こうすると、変更前の表示状態と、変更後の表示状態が、アニメーション効果で滑らかに繋がって遷移します。下記例は同期処理を `startViewTransition` の引数に渡していますが、`Promise` を返す非同期関数を渡しても動作します。

```javascript
document.startViewTransition(() => {
    // ここで表示の変更・画面の書換えを行なう
});
```

なお、View Transition は、MDN 上の記述を見ると、2023年12月現在では、実験的な機能、とのことです。実際、Google Chrome や Microsoft Edge など、Chromium 系のブラウザでは View Transition がサポートされていますが、Mozilla Firefox や Apple Safari など他のブラウザでは使えないようです (下記リンク先参照)。

https://caniuse.com/?search=View%20Transition

## Blazor でも View Transition したい!

### "Blazor View Transition" とその `ViewTransitionRouter` を使えば簡単

利用できるブラウザが限定的、且つ実験的機能とはいえ、この View Transition による視覚効果は極めて効果的であるため、Blazor アプリケーションにおいても積極的に使いたくなります。

では Blazor でも View Transition による画面遷移のアニメーション効果を実現するにはどうしたらいいでしょうか。

ひとつの方法としては、拙作の下記 NuGet パッケージを利用する方法があります。

https://www.nuget.org/packages/Toolbelt.Blazor.ViewTransition

この NuGet パッケージを Blazor アプリケーションプロジェクトに追加したあと、`App.razor` などに記述されている `<Router>` コンポーネントの使用を、`<ViewTransitionRouter>` に書き換えます (下記例)。

```html:App.razor
@* 👇 名前空間を開き... *@
@using Toolbelt.Blazor.ViewTransition 

@* 👇 "Router" を "ViewTransitionRouter" に置換! *@
<ViewTransitionRouter AppAssembly="@typeof(App).Assembly">
    ...
</ViewTransitionRouter>
```

たったこれだけで、あら不思議、ページ間の移動で View Transition による画面遷移のアニメーション効果が適用されるようになります!

![movie-000.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/0d8c45fb-aba9-603d-bc34-fa4bcc15446b.gif)

### 遷移アニメーションのカスタマイズは CSS で

既定の遷移アニメーション効果はフェード効果となっていますが、CSS スタイル定義によってカスタマイズすることが可能です。

例えば以下の CSS スタイル定義をページで読み込んでおくと、

```css
/* 遷移後の表示に適用されるスタイル定義で参照されるアニメーション効果 */
@keyframes slide-from-right {
    from { transform: translateX(100vw); }
}

/* 遷移前の表示に対するスタイル定義
   - 既定でフェードアウトが適用されるので
     それを打ち消すために animation: none を指定する */
::view-transition-old(root) {
    animation: none;
}

/* 遷移後の表示に対するスタイル定義
   - 画面右からスライド員してくるアニメーション効果を適用 */
::view-transition-new(root) {
    animation: 200ms ease-in-out both slide-from-right;
}
```

以下のように、フェード効果ではなく、スライド効果での遷移アニメーションになります。

![movie-001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/0a5e72a4-7fb2-cefa-10f3-2452dbae4929.gif)

### `view-transition-name` CSS 属性でアニメーション対象を制御

さらに、DOM 要素に `view-transition-name` という CSS 属性で、遷移前後の要素に名前を付けることで、ページ全体ではなく、その指定した要素間で遷移アニメーションを指定することが可能です。

例えば以下のように、Blazor Web アプリケーションのサンプルコンテンツのうち、本体エリアに "body" という View Transition 名を適用し、

```html:Layout/MainLayout.razor
...
<div class="page">
  <div class="sidebar">
    <NavMenu />
  </div>

  <main>
    <div class="...">
      <a href="..." ...>
        About
      </a>
    </div>

    <!-- 👇 "body" という View Transition 名を CSS 属性で指定 -->
    <article class="..." style="view-transition-name:body;">
      @Body
    </article>
  </main>
</div>
...
```

そして先の遷移間のアニメーション効果定義を、以下のように、View Transition 名 = "body" に対して適用するように書き換えます。

```css
...
/* "root" ではなく、View Transition 名 "body" を指定 */

::view-transition-old(main) {
    animation: none;
}
::view-transition-new(main) {
    animation: 200ms ease-in-out both slide-from-right;
}
```

そうすると、ページまるごとがスライド効果で遷移アニメーションするのではなく、ナビゲーションやトップバーはそのままに、本文エリアのみがスライド効果での遷移アニメーションとなります。

![movie-002.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/13fb8851-1e4b-e379-c7f1-5bb8a61a9529.gif)

このように、`view-transition-name` で遷移前後で対応する要素に同じ名前を付けると、以下の 𝕏 上への投稿のように、画像などの要素単位での連続的なアニメーション効果を実現できます。

<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="en" dir="ltr">The &quot;Blazor View Transion&quot; was rolled out!🎉<a href="https://t.co/vZwC7ZnBNj">https://t.co/vZwC7ZnBNj</a><br>This package includes a router component and a service both make your Blazor apps have pretty animated transition effects between pages with the View Transitions API!🚀<br>Live Demo:<a href="https://t.co/JQh5hIYE3S">https://t.co/JQh5hIYE3S</a> <a href="https://twitter.com/hashtag/Blazor?src=hash&amp;ref_src=twsrc%5Etfw">#Blazor</a> <a href="https://t.co/JnbPSCDJAg">pic.twitter.com/JnbPSCDJAg</a></p>&mdash; @jsakamoto (@jsakamoto) <a href="https://twitter.com/jsakamoto/status/1718257011740312011?ref_src=twsrc%5Etfw">October 28, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

実際にお手元の Chromium 系ブラウザでライブで試したい場合は、以下のリンク先にライブデモページがあるので、どうぞお試しください。

https://jsakamoto.github.io/Toolbelt.Blazor.ViewTransition/

## View Transition をサポートしないブラウザでの動作

冒頭で述べたとおり、2023年12月現在では、Mozilla Firefox や Apple Safari では、View Transition API は提供されていません。このようなブラウザで、`ViewTransitionRouter` を使った場合ですが、その場合は単純に、ページ遷移間でのアニメーション効果なしで、今までどおり表示が切り替わるのみとなります。

## まとめと補足

Web ブラウザの View Transition API はまだ実験的な機能であり、2023年12月現在では Chromium 系のブラウザでしか利用できません。しかし極めて効果的な視覚効果を提供できるため、とても魅力的です。

Blazor アプリケーションにおいては、"Blazor View Transition" NuGet パッケージと、それに収録の `ViewTransitionRouter` コンポーネントを Blazor 標準の `Router` コンポーネントの代わりに使うだけで、ページ遷移間に、View Transition API を使った遷移アニメーションが適用されます。未対応のブラウザでは普通にアニメーションなしの遷移で動作します。

遷移のアニメーション効果をカスタマイズするには、CSS スタイル定義で行ないます。とくに、要素に `view-transition-name` CSS 属性で名前を付けることで、より効果的なアニメーションを実現できます。

なお、今回の投稿では触れませんでしたが、ページ遷移のみならず、開発者が指定したタイミングで View Transition を適用することも可能です。詳しくは Blazor View Transition の GitHub リポジトリの README ドキュメントを参照ください。

https://github.com/jsakamoto/Toolbelt.Blazor.ViewTransition?tab=readme-ov-file

Happy Coding! :)