BLOG

ブログ

【Nuxt3】ページ遷移アニメーションの実装について(CSS, JS/GSAP編)

こちらは、Mavs Advent Calendar2023の18日目の記事です!🧁

ハコザキです。

Webサイトのアクセントの一つとして、異なるページに遷移する際、
切り替わる瞬間にフェードインなどのアニメーションを入れる
ページ遷移アニメーションと呼ばれる表現があります。

jQueryを用いたサイトでは、プラグインの”Animsition”や”jquery.fademover”を使用することで、ページ遷移時にエフェクトをかけることができます。※プラグインを使わなくても実装することはできます
Animsition
jquery.fadeMover – Fadein and Fadeout for jQuery

Nuxtで作成したWebサイトでは、Transition機能を使うことで
実装ハードルを下げてリッチなページ遷移アニメーションを実装することができます!

前編(本記事)では、Nuxtで作成したWebサイトに対し、
CSSアニメーションやJSフックを使ったGSAPでのアニメーションの実装例についてご紹介します。
後編では、Chrome 111(2023年3月~)からの新機能である、View Transition APIを
Nuxtで作成したWebサイトに導入してページ遷移アニメーションを実装する方法についてご紹介します!

はじめに

本記事では、Nuxtを触ったことがない人でも最後まで実装を進めることができるよう、
Nuxtの環境構築から進めております!

いち早く実装だけを読みたい方は、
”1. CSSでの遷移アニメーション”から読んでいただければと思います!!

実装デモ

本記事を読み進めて実装できるアニメーションのデモをご紹介します。

CSSでのページ遷移アニメーション

GSAPでのページ遷移アニメーション

共通実装準備

まずはNuxtの環境を構築します。

pnpm dlx nuxi@latest init nuxt3-page-transition
cd nuxt3-page-transition 
pnpm run dev

以下のように初期画面が表示されることを確認します。

続いて共通部分を実装していきます。
app.vue, layouts/default.vueをそれぞれ以下のように記述します。

<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>
<template>
  <header>
    <NuxtLink to="/">Home</NuxtLink>
    <NuxtLink to="/about">About</NuxtLink>
    <NuxtLink to="/users">Users</NuxtLink>
  </header>
  <main>
    <slot />
  </main>
</template>

続いて、ページを行き来できるようにいくつか静的ページを作成します。
pagesフォルダ内にindex.vue, about.vue, users.vueを作成します。

<template>
  <h1>TOP</h1>
</template>
<template>
  <h1>About</h1>
</template>
<template>
  <h1>Users</h1>
</template>

NuxtLinkで、複数ページ間で遷移できるようになっていれば準備okです。

では、ページ遷移の際にアニメーションを動作させる方法をCSSのみ、
JSフックを使った方法をそれぞれご紹介します。

1. CSSでの遷移アニメーション

Nuxtプロジェクトのページの遷移の際、CSSクラスが付与されます。
このCSSクラスを利用することで、遷移時にCSSアニメーションをつけることが可能です。

nuxt.config.tsを以下のように記述します。

// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },

  app: {
    pageTransition: {
      name: 'page',
      mode: 'out-in',
    },
  },
})

続いて、app.vueのスタイル部分を以下のように記述します。

<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

<style>
.page-enter-active,
.page-leave-active {
  transition: all 0.4s;
}
.page-enter-from,
.page-leave-to {
  opacity: 0;
  filter: blur(1rem);
}
</style>

CSSプロパティのblurを用いてぼかしを加えつつフェードインするような
ページ間遷移アニメーションが実現できました。

CSSでの遷移アニメーション

トランジションのCSSクラスについて

付与されるenter/leaveのCSSクラスについて適用される順にご紹介します。

ページ遷移直後(ページ表示時)

  1. enter-from enterの開始状態。対象の要素が挿入される前に追加され、要素が挿入された 1 フレーム後に削除されます。
  2. enter-active enter のアクティブ状態。enter のすべてのフェーズで適用されます。対象の要素が挿入される前に追加され、トランジション / アニメーションが終了した時に削除されます。このクラスを使用して、entering トランジションの持続時間、遅延、イージング関数を定義することができます。
  3. enter-to enter の終了状態。要素が挿入された 1 フレーム後 (enter-from の削除と同時) に追加され、トランジション / アニメーションが終了したときに削除されます。

次ページ遷移直前(ページ離れる時)

  1. leave-from leave の開始状態。leave トランジションが発生するとすぐに追加され、1 フレーム後に削除されます。
  2. leave-active leave のアクティブ状態。leave のすべてのフェーズで適用されます。leaving トランジションが発生するとすぐに追加され、トランジション / アニメーションが終了すると削除されます。このクラスを使用して、entering トランジションの持続時間、遅延、イージング関数を定義することができます。
  3. leave-to leave の終了状態。leave トランジションが発生した 1 フレーム後 (leave-from の削除と同時) に追加され、トランジション / アニメーションが終了したときに削除されます。

詳しくはVue公式ドキュメントを確認すると良いです!!
トランジション | Vue.js

https://ja.vuejs.org/guide/built-ins/transition#transition-classes

2. JavaScriptフックでの遷移アニメーション

JavaScriptフックを活用することで、
1のCSSアニメーションよりもよりリッチなページ遷移アニメーションを実装することができます!

Nuxt3の標準で提供されているcomposables関数のdefinePageMeta
pageTransitionでnameやmodeといった設定の他に、 JavaScriptフックを使う事ができます。

1のCSSの方法でご紹介したトランジションのCSSクラスのように、
JavaScriptフックも同様の形式で用意されています。

// 要素が DOM に挿入される前に呼ばれる
// 要素の "enter-from" 状態を設定するために使用する
function onBeforeEnter(el) {}

// 要素が DON に挿入された次のフレームで呼ばれる
// アニメーションを開始するときに使用する
function onEnter(el, done) {
  // トランジションの終了を示すために done コールバックを呼ぶ
  // CSS と組み合わせて使う場合は省略可能
  done()
}

// enter トランジションが完了したときに呼ばれる
function onAfterEnter(el) {}

// enter トランジションが完了前にキャンセルされたときに呼ばれる
function onEnterCancelled(el) {}

// leave フックの前に呼ばれる
// 大体の場合は、leave フックだけ使用するべき
function onBeforeLeave(el) {}

// leave トランジションの開始時に呼ばれる
// leave アニメーションを開始する時に使用する
function onLeave(el, done) {
  // トランジションの終了を示すために done コールバックを呼ぶ
  // CSS と組み合わせて使う場合は省略可能
  done()
}

// leave トランジションが完了して
// 要素が DOM から取り除かれた時に呼ばれる
function onAfterLeave(el) {}

// v-show トランジションでのみ有効
function onLeaveCancelled(el) {}

https://ja.vuejs.org/guide/built-ins/transition#javascript-hooks

GSAPでのページ遷移アニメーション

このフック内でGSAPでのアニメーションを行うことで
ページ遷移のアニメーションが可能になります。
今回は左から右にカーテンのように要素を移動させる
アニメーションを実装してみたいと思います!

GSAPの導入

まずはNuxt3プロジェクトに、GSAPを導入します。

pnpm i gsap

続いて、gsapをNuxt内で使用できるようにpluginsで定義します。
~/plugins/gsap.tsを作成し以下のように記述します。

import { gsap } from 'gsap'

export default defineNuxtPlugin(() => {
  return {
    provide: {
      gsap,
    },
  }
})

provideすることで、useNuxtApp()でgsapが使えるようになりました。

続いて、~/app.vueにトランジションの設定をgsapを利用して実装します。

<script setup lang="ts">
import type { TransitionProps } from 'vue'

const { $gsap: gsap } = useNuxtApp()

/**
 * ページのトランジション設定
 */
let tl: gsap.core.Timeline = gsap.timeline()
const transition: TransitionProps = {
  name: 'page',
  mode: 'out-in',
  onEnter: (el, done) => {
    tl.to('.js-mask', { left: '200vw' })
    done()
  },
  onBeforeLeave: (el) => {
    tl.set('.js-mask', { left: '-200vw' })
  },
  onLeave: (el, done) => {
    tl.to('.js-mask', {
      left: 0,
      duration: 0.3,
    })
    done()
  },
}
</script>

<template>
  <NuxtLayout>
    <NuxtPage :transition="transition" />
    <div class="overlay js-mask" />
  </NuxtLayout>
</template>

<style lang="scss" scoped>
$transition-mask-color: rgb(0, 59, 220);
.overlay {
  position: fixed;
  top: 0;
  left: -200vw;
  width: 100vw;
  height: 100vh;
  z-index: 9999;
  background: $transition-mask-color;
  &:before,
  &:after {
    content: '';
    position: absolute;
    top: 0;
    width: 100vw;
    height: 100%;
  }
  &:before {
    right: 100vw;
    background: linear-gradient(
      to top left,
      $transition-mask-color 50%,
      transparent 50%
    );
  }
  &:after {
    left: 100vw;
    background: linear-gradient(
      to bottom right,
      $transition-mask-color 50%,
      transparent 50%
    );
  }
}
</style>

トランジション設定部分のポイントは以下の通りです。

  1. onBeforeLeave(ページが離れる直前):マスク要素(js-mask)を左奥にセット
  2. onLeave(ページが離れている間):0.3秒かけてマスク要素を画面左端(left: 0)に画面いっぱいになるように表示
  3. onEnter(次ページ表示中):マスク要素を右奥へ移動させる

この状態でページ遷移をすると以下のようなアニメーションが動作するはずです!!

※ before, afterで斜めに要素を色つけている表現をしているので
左上から右下へカーテンが流れるように見えます。

おわり

前編では、NuxtでのサイトでCSSやJSフックによるページ遷移アニメーションを実装する方法についてご紹介しました。
特にJSフックの例では、GSAPと組み合わせることで シンプルな記述で少し複雑なアニメーションを実装することができました。
弊社コーポレートサイトのページ遷移アニメーションもこの技術を応用して実現しています。

後編では、新しい機能のViewTransition APIの実装例についてご紹介します!!

RELATED ARTICLE