Gemcook Tech Blog
🧢

【Chome126】View Transitions APIで滑らかな画面遷移を実装する

2024/06/14に公開

こんにちは!
Chrome 111からView Transitions APIが利用可能になりましたが、今まで試す機会がありませんでした。
今回満を持して試してみたところ非常に面白かったので、この記事で共有したいと思います。
また、2024年6月11日にリリースされたChrome 126からView Transitions APIが強化されましたので、その点についても触れてみたいと思います。

View Transitions APIとは

https://developer.mozilla.org/ja/docs/Web/API/View_Transitions_API
View Transitions APIは一言で言うと、

異なる DOM 状態間のアニメーション遷移を簡単に作成する仕組み

だそうです。
ほう...??🤔
百聞は一見にしかずということで、以下のサイトにView Transitions APIを使ったデモがわかりやすくまとまっており、イメージがつきやすいので触ってみてください!
https://ics.media/entry/230510/

View Transitions APIはCSSのanimationtransitionだけでは実現が難しかったアニメーション(MPAの画面遷移のアニメーションなど)を、簡単に実装可能とするAPIのようです。
View Transitions APIを使うことで、スマホのネイティブアプリのような滑らかなUIを実現することが可能になります。

実際に触ってみる

今回はSSRの画面遷移のアニメーションをView Transitions APIを使用して実装します。
(今回はRemixを使用しています。)
完成したのがこちらになります。

Step1 シンプルにView Transitionを有効にする

まずはシンプルにView Transitions APIを使って、View Transitionを有効にします。
View Transitionを有効にすると、以下のように画面遷移時にデフォルトのアニメーションが適用されます。

また初めに述べた通り、Chrome 126でView Transitions APIが強化された点についても関わってくるので合わせて触れていきます。

実装方法その1:JavaScriptでView Transitions APIを使う(〜Chrome125)

Chrome 125以前のバージョンでは、View Transitions APIを使う場合はJavaScriptでdocument.startViewTransition()メソッドを呼び出す必要がありました。

// View Transitions APIを呼び出す
document.startViewTransition(() => {
  // もろもろの処理
});

使用例としては以下の通りです。(スタイリングは省略しています。)

PostPage.jsx
const PostPage = () => {
  return (
    <div>
      {POSTS.map((post) => {
        return <PostCard key={post.id} post={post} />;
      })}
    </div>
  );
};

const PostCard = ({ post }) => {
  const navigate = useNavigate();

  const handleViewTransition = (e) => {
    e.preventDefault();
    document.startViewTransition(() => {
      navigate(`/post/${post.Id}`);
    });
  };

  return (
    <a onClick={handleViewTransition}>
      <h2>{post.title}</h2>
      <p>By {post.author}</p>
    </a>
  );
};

カードを押下したときのonClickイベントでdocument.startViewTransition()を呼び、コールバック関数内で画面遷移させるようなイメージです。
これで画面遷移時にフェードインとフェードアウトするアニメーションができました。

実装方法その2:CSSでView Transitions APIを使う(Chrome 126〜)

Chrome 126以降では、以下の通りスタイルを記載するだけでView Transitions APIを呼び出すことができます。

@view-transition {
  navigation: auto;
}

JavaScriptを実行せずに、CSSだけでView Transitions APIを扱えるのがポイントです。
また、上記を見ていただくとわかるように今回のバージョンアップでは画面遷移(navigation)が強化されました。
navigation以外の強化も楽しみです。

さて、Chrome 126以降の実装としては以下の通りとなります。

global.css
/* 画面遷移前後のCSSに適用すればよいが、今回はglobal.cssに適用 */
@view-transition {
  navigation: auto;
}
PostPage.jsx
const PostPage = () => {
  return (
    <div>
      {POSTS.map((post) => {
        return <PostCard key={post.id} post={post} />;
      })}
    </div>
  );
};

const PostCard = ({ post }) => {
  return (
    <a href={`/post/${post.id}`}>
      <h2>{post.title}</h2>
      <p>By {post.author}</p>
    </a>
  );
};

PostPage.jsxの記載量が少なくなり、かなりスッキリしました!
やはりCSSだけで完結するのはとってもコードが健全で見やすくなりますね。
これで実装方法その1と同じView Transitionを実装できました。

Step2 よりリッチなアニメーションへ

画面遷移時にアニメーションが効くようになりましたが、何か物足りない感じがしませんか?
この章では、よりリッチなアニメーションを実現するための方法をご紹介します。

指定したDOM間でアニメーションする

View Transitions APIは、画面遷移前のDOMと遷移後のDOM間でアニメーションさせることができます。
完成系の例で言うと選択したカードが広がって次のページに遷移するように、遷移前のカードのDOMと遷移後のページのDOMを結びつけてアニメーションさせることができます。
やり方はとてもシンプルです。
紐づける遷移前後のDOMのどちらにも以下のCSSプロパティを適応するだけでできます。
注意点としては、識別名は同じ名前をつける必要があります。(以下の例ではawesome-transitionが識別名になります。)

view-transition-name: awesome-transition

https://developer.mozilla.org/ja/docs/Web/CSS/view-transition-name
以下が実装例になります。

PostPage.jsx
const PostCard = ({ post }) => {
  return (
    <a
      href={`/post/${post.id}`}
+     style={{ "view-transition-name": `card-${post.id}` }}
    >
+     <h2 style={{ "view-transition-name": `title-${post.id}` }}>
        {post.title}
      </h2>
      <p>By {post.author}</p>
    </a>
  );
};
PostDetail.jsx
const PostDetail = () => {
  // 省略
  return (
+   <div style={{ "view-transition-name": `card-${post.id}` }}>
      <a href={"/post"}>Go Back</a>
+     <h1 style={{ "view-transition-name": `title-${post.id}` }}>
        {post.title}
      </h1>
      <p>By {post.author}</p>
      <div>{post.body}</div>
    </div>
  );
};

これでフェードイン・フェードアウトだけでなく、カードを拡大/縮小して画面遷移するようなアニメーションを作成できました。
(カードだけでなく、タイトルについてもDOMを結びつけた方が見た目がイケていたのでつけてます。カードを拡大/縮小するだけならタイトルの結びつきは不要です。)
これらはView Transitionのデフォルトのアニメーションを使用しただけであり、アニメーションを作り込まなくても実現できるのが嬉しいですね。

他にも...

今回はデフォルトのアニメーションのままですが、当然アニメーションについてもカスタマイズ可能です。
view-transition-nameごとのアニメーション指定も可能ですので、またトライしてみようと思います!
https://developer.mozilla.org/ja/docs/Web/API/View_Transitions_API#アニメーションのカスタマイズ

まとめ

現在は一部のブラウザしか対応していないView Transitions APIですが、Safari 18 Betaでも使用できるようになるなど、今後より一層使われていくAPIになるのではないかと思います。
Next.jsなどのフレームワークでもView Transitions APIをラップしたAPIが提供されており、より使いやすくより便利になるのかもしれません。
またAstroでも以下のような記事も出ていました。
https://astro.build/blog/future-of-astro-zero-js-view-transitions/?tw
今後の動向に注目です!

参考

https://developer.chrome.com/docs/web-platform/view-transitions?hl=ja

Gemcook Tech Blog
Gemcook Tech Blog

Discussion