SvelteKit 1.24 で view transitions API を使ってスムーズな画面遷移を実現する方法が簡単だった！

# はじめに

一般的なWebサイトの場合、あるリンクをクリックしたときに画面遷移が発生します。ブラウザは遷移先の URL を読み込んで画面全体を再描画します。

SPA(Single Page Application) の場合は画面全体の再描画ではなく部分的に再描画されます。例えばヘッダ領域はそのままで、メイン領域を再描画する、という感じです。この際、あまりにも早く切り替わってしまうためユーザーは何が起きたか認識しづらいケースがあります。

例えば実物の書籍であればページをめくることで次のページに遷移したことを認識できます。Webサイトでもそのような認識しやすさを導入できると良いですよね。

これを簡単に実現するために [view transitions API](https://svelte.dev/blog/view-transitions) という仕組みがあります。

:::note warn
2023年9月13日現在はまだ実験段階のようです。
https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition
:::

[SvelteKit] 1.24 で view transitions API を使って簡単に画面遷移にアニメーションを導入できることが [こちらのブログ](https://svelte.dev/blog/view-transitions)に掲載されていました。

今回は上記ブログを参考にして view transition API を試してみました。

# 実装

実装は簡単です。 `src/routes/+layout.svelte` に以下を記載するだけです。

```html:src/routes/+layout.svelte
<script>
...
import { onNavigate } from '$app/navigation';
...

onNavigate((navigation) => {
    if (!document.startViewTransition) return;

    return new Promise((resolve) => {
        document.startViewTransition(async () => {
            resolve();
            await navigation.complete;
        });
    });
});
</script>
```

`src/routes/+layout.svelte` が何なのかを知りたい方は [こちらのチュートリアル](https://learn.svelte.dev/tutorial/layouts)（[日本語](https://learn.svelte.jp/tutorial/layouts)）をご確認ください。

# 動作確認

[こちら](https://www.sveltelab.dev/?files=.%2Fsrc%2Froutes%2F%2Bpage.svelte%2C.%2Fsrc%2Froutes%2Fother%2F%2Bpage.svelte%2C.%2Fsrc%2Froutes%2F%2Blayout.svelte#code=N4IgdA5glgLlEDsD2AnApiAXKAZlANhtiAMZIIxoUDOWoA1lAgCZYjUBua%2Bl%2BAhgCMAtAFcoADj4gANCAEicONCiwBtACwA2aZvHTxAZmkBOAKz6jARkvbrl6dfUOADPcvOH7z2%2Bcf39sxdjbxc-SwB2Fz1-T3MvdUjjaIiXOOdo3xdpBOzbSzjLDJ9k21dstMj3AtLsyssAJhNE4PdEyucrMvjSty9rDNyXXrC9LWzGrwMjMZjrEcHZ%2Bo9jdpaGqKGs-tTPHsHjNeGXCec06dK88xmbHfcWrvzdpqDPRvUrk88M6s2xg5C5sdbh0FjdrFc8qU0vdej8Vi9rG8Pi4ALoAXwxsjAAAd0DA4MoUCQ6CA8IQSWQKFQYLRiIwWGxONxeIJRBIpLJ5IplGoGp0TNIDE5rHU0vZxE54UlYoKnKY9AYJmDLMKUjF1MLlrKZVVPH4Qe4ivpenVenshdJ5YKlXlVe17BqssELdZbc9dYbbn0QZpTQjnMF4RarYrtYC7HrNhbHV5naqlZqCmFtOJ2mlky4nMGFW9gupRqNNQKXetPSKXJ0kzLs9aTPYSwnNq6nh6Hk53q8NuX3JXIx3wV8m%2BkW2ULcZpkW452y2qDadI4ZNvDHCZ7k5dF7VeYa6HjPX29oxxOnWHrIPZirPInQk3HjvGnuHPUjKGXc4TmkjQP79r1G9LueXTDs2MTRlmjQlr0Npekc35yjmT4vhB8bupeA4Xlm8G1iWBRfsBYKjuBT7bhM9TmOOWxkaiGJorI2J8CQ9B8BAaBgAAVtQ5AkmSRCgJSlA0CS9KsJg7BcDw3CsmIkgyHIChKComCqHyJ4lssqxRlhr6Snoy6PLq-xgapqpfmh%2BnzhGgI-tGozaPmgzqFOMZag2V5erpdTmlp0Ert2ZTOcWW6rm5Hqlsq27eYhJ5Tu4%2Bq9AqkUlt8I71iccWDkZsaBSYyRpl2mTWSZXrmg%2BuXAhkHiZVqMVhZq8XAr0U4hshgE-KBSqNheyUXk5k7ZWWFl9DchXTmhDyQg1bmhh2-alvh7S9oCs1iqhkpruUN6hURYzTVc5HrTE-ytLWO3tn1MXvgCY2Bp52rNaenXjSOK0rrtG2Il2s6LfEBQrXpa2Zu9mRbSdh5Iu9lhrNeIGjv%2BYZag0Vx9W%2B6XbBuF4nLBwMPMs9wvXekUqVlU6aEF2yzPhezuABOTLpkek%2BW2G16bdEYjcYcoeGM9ncwl2TndqpM6oUQ4lEONPtHlzbs%2B2ebaKYXO2ZaLUBYGD0hU9MP45hloIWOnODKYdl2Xzqv9bVt4Ta2vTtgUJxlT2Xpc79gHFCld165KBvc3mSuOb%2BAs4a7n1ebr2Fe8rDlK6YL5ndFp7dQR%2B5h9pJhynDpgZ5VfWI-zxktvUUGaSnLV3ACwOzkaVX9djRcXvqqOxnjt4RSXUXE6euGi%2B7HZHc4dXBcdMuWg68sZzrWW530VHuOimLsESJLMFA6AkDAqAAJ4knw2LYmAAAWMAALb4NxBC8aQ5ACTSQlMCJYnMpJwjSRycncopqiaJVRgbuEwS%2BvoJw4hgjiA8JoZ0JxVSlHuHoTQnwv6AxhjA2sno9L6h-sneugtPj-31APOmYCcECgQWXC82ggwPnWv9HUT1NCYLVARcGRttTTUiHA%2BOJDgKDX1JEUMvkgKwMwfOI6Z4rJEXcKqAe7hGh0JYaKYOM4qbOCljcP48j0KazvJEHI0jULJREUca4Sp0EsLeGwohuD-RmmeHw2MGkYiyKSpNawawlQ2yeBaXchxIww1gjcRxqpm6xRHOuHwjd9EwghkEiupQdasJ0BYwU6iRYUzFhTFRxtEFlAIUkk8CCdH9yXO0QheTljJDCU%2BVKN49LkO0S7cmAj3bHVCnZO2Gs3YRhyf2emt14QBMQaIlJTMLTsI7pw-UXdbFtULvlew-TgmhTaagyoMz7oGJ8UnDZAERkQWSXhNJQEMn7HKZtGZBg2Fc2Ke5BJpTag5XLn4GZoywGXIGdAjYzy560RAPgKAAgl4rzQGvTeJIADCSARBUhQGAJkEkz7kmIPxaktIGB30ZOJFkz92SyS5ApNQJDHgiOhmFbQzyBQDWsV4q6dQMyhkcW8PQph7iqXlghVsEE3i42pVs2s7D6XZF9tkKpRNqrui4e45s6hljkO8d2IaYMvQkWqTSist5VQmhodEM5kDgSdCzEYYwdl7BMvjusuVtKZFVNMJEE1k8Z76nJZdc1g8CIFCOHwwpaDNrip0O0CJLhtFc2Fc%2BU1sqGEWuyBgk6wRbUI3tToV5A4iVemgmSrwCDpRyqtoMyqbjIxWj7v646siRWShVQsn1ACBr7QDcRG5WUq1cJrc0oCuaopmvDQXNI5KQ0dvLcNS1Og5lVP9nSpCgo1hQisRO2s90DCTuBJE78LR435MSA7ZUeQjifJorIO%2BaAAAe7EUWknPhSK%2ByLb4MlErCzFbIZKcnkjyJSOQci2Pts8PuwqnUWR9d%2BUivQNW2Jujy2xW6UG-tcVdKBKCCKSO5Y7CRsHYlRgfIeUo%2BjdIKrpvo%2BRHqqxgayS7D1eaBqNwPNRGi3yUAQsoCe5eq914oC3sQAA1PwDetGYUYovjxc9VJBJ0jRTenj-AsUPrfnipSBLm1jSWf4ohrYoOWTMgq%2BdDkFqfQCB5DYfw1jEZjcy6JynBkwb4SG2xRxwg6YaWcVCJU60kZCqIgM2FnS1NGmYyMeluoghqTBSM6nY2OvJTm6Q1m9G6vs78LmYR1KtVVf50KhiqmyPYeZ-kEDsIcuBDlqVgpOhhACGsexOMnjXDhHUGD4gp09UAW5L1Gi2qDRS7BqRyoqv5qM6pHLr5HrWLlaqNt4YHhZdAc5nwQTzIOli%2B04WHShkOlS3MnLIriy9Y29liDRWXWlb8Zk9CNxqHNhq84yG9WVyNfMs1t1fZ4voRmYCQynKhW8pWygkNWU%2Btbe%2B79zbtj2u3ZnEafL6hjXdb%2Bz9-70PUIgZabB%2B7Qy7NJZa32GV5dlN-s2cFrLkO8ekSuODnrUO61g8tN13OZPgtrplMm0KqbPjpri5FslliKEDKkZdfpb71w6ssq5hxry%2BlEIzbwvnY0fCDujH6GG7WdajMGShjCCa7nC6yDTp7dRYGM5eZqq6Cqcg7vnqx%2BiLFuOP3hRfJFgnUXXofhJMT97X64ufZ-PBAqbnhFIwL2GnY6adDmYmwp-s02678tr251b61LCfI8uPseE8NHj0nxPMeU8p4102%2BtWpOHJVGWngvyfC%2Bp6L6XhPme88i-1JXkvtf0-F-r2XxvKuCk14bdXnY%2Bem8N5793svFfO9V-yuYLvdfe9j77%2BXoPbec8d91KP5vi-x9L-79Pwf6vE2VwSV82QEB8BIAEHwfAYASDUBPXxxFF6bcgGEuix%2BjuX44qfR-K0vlBmUtIpljay1a29x033OpQGe6BWbIRlOUbrGaepZRZmf-e4QA0wB0NIMmYcYAiAvaGhQA6UKUOA7-GNNlQpDRUYRWPOaaBUbRbaQVeyc5V7HHb-KAzA2A3-cwEA%2B6JDQg7IYgx0Ug3JLg3MUA-g6gqnNAiGCoGAz9HAjsBAtuNg8yIgy0Yg0wOOUMRQyOQQoia1S0Q8bRInLKSAjAsQ7ApgyOVggg2Qjg%2BQ-glQ3g4w3ZEgxoDQqQwQnQrUPQjRBg8QowmOaQ0wz8cwkA%2ByKw9Q4gtQ2dE2Hg5wgUVw8yQA3xRPVRK4PAiDZAuQnmbaMguwj3Rw7Q8nE8KI0Q2aKmNPeIiwkw5I8w1Ik6dI6wlg7cbI2gvIow2I9PYoqQ0ovXfLFghlDI5hEI5Q%2Bw2woQ3I9AtwiGJXICSJGaRIj1Mo0HGNY8aaSgqo9QowLwpwnI3Q4Y6I0YrJSbX4ZgjwNo9gjog4ro6orQ7o-o8I9YlwzY-I5rTnCY5g41fAmYg4hQt4Cg-gqg8g2dOUesOo4Qn-Y6bpUjeVNudTP%2BBRMyB8ZJbcPMbaciOoDqWZEQypYWJReE3lDDJ2WtcINoYKRcBoWEJpVzcIHbcMVRIidTQkoCKwFzKpcQcwcIF8TE0McQPNTNRXEIawyE%2BvHwAPPsIiRk%2B5Z1ECFIM2f%2BfEikjzfhDpYcawiEiZBrMXCwVCMIOEjI9TdGMyHwdMWsRcK7DUhU4IL3buBpAbYREDUMCLC8e0GdawpNftW4tVXLa4yI504EtIUEjMbpMNHbOdE0pUy7FUvEq6HbdTB0gXMLFTNpQwmIYLKeB1IWUhVtHYdnfLD6WUoEZXAcXuWVfCdxH-PuB4zYEwxHTUbIjLE8V-HU-XD7L-PMD06Av-Dwz0zIl49ozgtIngz474mg7rRs1EtsrA5oTwg4jso4rsyons6NTQq42gwcoE5s8iRgts1oicsw0HQsac3ovgzOecgcug-QlsuM5c4wjc3wrcjIvs6ot4g8%2BOBo4c1cs8rww4zcqc7g3cyOG8iItWR8s8pooo1pdspIzsr47sr8jQn8t0v8psmIzZZo4Clgi83TD8royCsItYhco8kYgopsICjadc0Cyc8Cncn45QuUF8AEk8RM6KE5BZbVduUVM1AstyIsg6cY0s-A8s2tWg2i-ispB5NEqs4mZ8zTN-DVEbZ2F1BbdxVgkWahUHOCgw0ctcpbGCmSrTNyeSmzS8JSocgChCgiyY-smi1zY7OcKse6HmeWZggUsuPip1aM4o3ROmaJLVZ42DXS9saSpcmIpy-bUy4mUcr9HlPM8ueiy8HS1aco5SvCtgzi9UBIoKx5NIHfEAJAGAfeZ9UABjIFJjFjUAE3ZiViW9XjM9S-ATG%2BITO3Mqh-bFR9d%2BfFd3EPRoXkuDF099MVAUzPWWbPDfRdVVXcP1J4eZQlexOaKucRfSS8f4eZUw7NJUZg0YbRKWcy8Sh4CETwJ06cYcPSJA-YfMvMJEgZAbM8EylQ185g5Ky641A4-Yy0ZK7pHwY1Zg0oUqS0G1NKZ4UwZg3haa6JDMJDbnRY3JaXbfKjSG2QagGAPgOAYkYgPK4FZjbiPgDgKASkHEBACAS3fja%2BE9W-ETe-KSBqyTV3Z8FoR8QoEBDwCLcINwfkeoGoDwFmhwIwZk8LGRPQdk6QVmrmbQPm38QUXmkWjwCmhwKm4BfQcwcWyGNwKWhoSIQWqYfQWmlMdcYIQW2WyW-%2BJwMW9TOWhwKWoWfWym%2BW3WkW7W82nQPW6QK2o2-%2BcwU2iW62k2u2g2nWnQJ292s2h2r2y2j21222%2B26mm2kWi0CUH2l2v2lIQWrknmiLRcZ2w20OkOqWtOi2nIDO9YkWbOvOtqu2yIem0WkWqDU0hWx4Vmy8bOqupwbO%2BwbO9QKwOupWku7OjmjcTQcwSOlPPOwOv2vu320OlIRurVKOlOqWx8Q1cez2we6O0O5Oz29YOeie4IbOqQmZFepeowLe62ywHevQdetql8Ok4UeoCCFdGW-u1O6%2B9O2%2Bte%2B%2B8LB%2Boeu%2Bl%2BteyUUiUoHex%2Bzex%2BkWK%2Bt%2Bme62qwRoeobm8BzwOk0BtWoBmO87eu8%2B2B0OyIBB7%2BwB7O9hdej%2BgO9B66nB%2BeqW8QQPJB1%2Bgh5%2BshkhvMaYFYlBv%2Bx4JwU0rwvOhun%2Bn%2BlZRevegBihhBuuuh9sNB7h1hwB6ux%2ByEpuwUO8yE8bevdm2h9BoRihz0Xegen%2B0sXkm1ZgtqtwO2iyAwFh%2BR4Rma3hgxxR%2BcDBmNLh1eiW4UUMlcZh5ugRqxhB-kodGUE1VBjaZRm%2Bwx-RxRs8LxyexlTYyIHumPYUgJqDYwUBhRqxsuZxyh17DcKiCJtExu7QFJkA9TQuSoaglJxcRu0cqiAwbQU07OyOgwF2eu6Aik2OHQRxz28RlJppiphwfsW1fx87fIWBaSlJzQep62wW2mn%2BE02BQ%2Bx%2BzQchdJ%2B%2Br5eeMqk-cgPACAY9XGyq-Gq9e%2BOqkmiTF3D%2BJTUaCVAdMVRHRmdxJzCSl4V8C2w7fZEkiWI51CE5tixE7alsM8ILZleIbRN4HLZMsER7OaYNRaKM0EmDfLLUsmRbEOcWGUApI5CM0eX1MM7M39EBpVP8O5JuJFw7bDP05FuzOlQFsyo5Vgz7UVV9FUnJBmJpPS55rNEISzHxYCRiw7E6zM0zV5pVQ7XY9qW8eYEGFTfUJdME3M6al6X3GQxatxlajF6pwaA7Gam52ImYWuQcApHbERK4KUnpUaKmGl1CVmN5k4EF2sdnKPbFhYMl1a2sDm3RczQDF516TGDZROdVRloViNRZBHOsqZB1sKY1pogqY1u17lH1shEcPCYbMLYa2DJZbJaJD8YKD1PxF1rFn3QKh0maqbdHJDBlulwjBKqpSl1lhCvSmoP8q1tk%2By8Vha15pasOcl2teHCrBRSmX4UocJGV9V-TVXK5KlposyTlgKqaE4MNAefDRl-19a56JF6NzkySw5otnVl03MstgURdtl3VyKddklF00HHwHtbtXOBM1GIo-1w5itSXfVqFqlAVvF1VWNdK9GygeZhARZ5Z4gC-PiK-aq23DZ0TLZ53Z-XkSDfZ5zBVFSUNyFxRIcOFgnCDTqFzXHK5hVs0hC5wO5ltH4HRJHd2d5rYEDtlg58Dizb6imBNkbOZGXb0cjkEczQdhD3Yy5hLWIvD70fCsIM98DlV1yuoEa6WUjoCcj70Sj1Nmj6YR5L-TM%2BaVVUKdUtuKmlD1JEko5PdkwfkSnZwmZoAA) で動作確認できます。（※Chrome で確認するのがおすすめです）

`other` リンクをクリックすると、現在の画面がフェードアウトしつつ other 画面がフェードインするのが分かると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2773745/0c6c82c4-1eec-7ce6-a393-1bfd73436aa4.png)

# まとめ

[SvelteKit] 1.24 で view transition API を使って認識しやすいスムーズな画面遷移を実現できることが分かりました。`startViewTransition()` メソッドの各ブラウザの [対応状況](https://developer.mozilla.org/en-US/docs/Web/API/Document/startViewTransition#browser_compatibility) を見るとまだ半分ぐらいといったところですが、今後はすべてのブラウザで実装されると思われます。画面遷移のユーザビリティに革命（？）が起きるかもしれませんね。:smile:


[SvelteKit]: https://kit.svelte.dev/