最終更新日: 2023年08月15日

トランジション / Transitions

Nuxtは、ページとレイアウト間のトランジションにVueの<Transition>コンポーネントを活用しています。

ページ トランジション

ページトランジションを有効にすると、すべてのページに自動的にトランジションが適用されます。

  • nuxt.config.ts
  • ts
export default defineNuxtConfig({
  app: {
    pageTransition: { name: "page", mode: "out-in" },
  },
});

ページ遷移にトランジションを追加するために、次のCSSをapp.vueに追加してください:

  • app.vue
  • vue
<template>
  <NuxtPage />
</template>

<style>
  .page-enter-active,
  .page-leave-active {
    transition: all 0.4s;
  }
  .page-enter-from,
  .page-leave-to {
    opacity: 0;
    filter: blur(1rem);
  }
</style>
  • pages/index.vue
  • vue
<template>
  <div>
    <h1>Home page</h1>
    <NuxtLink to="/about">About page</NuxtLink>
  </div>
</template>
  • pages/about.vue
  • vue
<template>
  <div>
    <h1>About page</h1>
    <NuxtLink to="/">Home page</NuxtLink>
  </div>
</template>

特定のページに異なるトランジションを設定するには、ページのdefinePageMeta内にpageTransitionキーを設定します。

  • pages/about.vue
  • ts
<script setup lang="ts">
  definePageMeta({
    pageTransition: {
      name: 'rotate'
    }
  })
</script>
  • app.vue
  • vue
<template>
  <NuxtPage />
</template>

<style>
  /* ... */
  .rotate-enter-active,
  .rotate-leave-active {
    transition: all 0.4s;
  }
  .rotate-enter-from,
  .rotate-leave-to {
    opacity: 0;
    transform: rotate3d(1, 1, 1, 15deg);
  }
</style>

レイアウト トランジション

レイアウトのトランジションを有効にすると、すべてのレイアウトに自動的にトランジションが適用されます。

  • nuxt.config.ts
  • ts
export default defineNuxtConfig({
  app: {
    layoutTransition: { name: "layout", mode: "out-in" },
  },
});

ページとレイアウトにトランジションを追加するには、以下のCSSをapp.vueに追加してください。

  • app.vue
  • vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

<style>
.layout-enter-active,
.layout-leave-active {
  transition: all 0.4s;
}
.layout-enter-from,
.layout-leave-to {
  filter: grayscale(1);
}
</style>
  • layouts/default.vue
  • vue
<template>
  <div>
    <pre>default layout</pre>
    <slot />
  </div>
</template>

<style scoped>
div {
  background-color: lightgreen;
}
</style>
  • layouts/orange.vue
  • vue
<template>
  <div>
    <pre>orange layout</pre>
    <slot />
  </div>
</template>

<style scoped>
div {
  background-color: #eebb90;
  padding: 20px;
  height: 100vh;
}
</style>
  • pages/about.vue
  • vue
<script setup lang="ts">
definePageMeta({
  layout: "orange",
});
</script>

<template>
  <div>
    <h1>About page</h1>
    <NuxtLink to="/">Home page</NuxtLink>
  </div>
</template>

pageTransitionと同様に、definePageMetaを使用してカスタムなLayoutTransitionをページ コンポーネントに適用できます。

  • pages/about.vue
  • vue
<script setup lang="ts">
definePageMeta({
  layout: "orange",
  layoutTransition: {
    name: "slide-in",
  },
});
</script>

グローバル設定

nuxt.configを使用して、これらのデフォルトのトランジション名をグローバルにカスタマイズすることができます。

pageTransitionlayoutTransitionの両方のキーは、TransitionPropsとしてJSONシリアライズ可能な値を受け入れます。カスタムCSSトランジションのnamemodeおよび他の有効なトランジションプロパティを渡すことができます。

  • nuxt.config.ts
  • ts
export default defineNuxtConfig({
  app: {
    pageTransition: {
      name: "fade",
      mode: "out-in", // default
    },
    layoutTransition: {
      name: "slide",
      mode: "out-in", // default
    },
  },
});

nuxt.configファイルでグローバルに定義されたページまたはレイアウトのトランジションを上書きするには、definePageMetaを使用して単一のNuxtページのトランジションを定義し、グローバルに定義されたページまたはレイアウトのトランジションを上書きします。

  • pages/some-page.vue
  • ts
<script setup lang="ts">
  definePageMeta({
    pageTransition: {
      name: 'bounce',
      mode: 'out-in' // default
    }
  })
</script>

トランジションの無効化

特定のルートでpageTransitionlayoutTransitionを無効にするには、ルートのコンポーネント内でtransitionプロパティを使用します。

  • pages/some-page.vue
  • vue
<script setup lang="ts">
definePageMeta({
  pageTransition: false,
  layoutTransition: false,
});
</script>

または、nuxt.configでグローバルに設定する場合は以下のようになります。

  • nuxt.config.ts
  • ts
defineNuxtConfig({
  app: {
    pageTransition: false,
    layoutTransition: false,
  },
});

JavaScript フック

高度なユースケースとしては、Nuxtページのカスタムトランジションを作成するためにJavaScriptフックを使用します。

この方法は、GSAPやTween.jsなどのJavaScriptアニメーションライブラリにとって完璧なユースケースを提供します。

  • pages/some-page.vue
  • ts
<script setup lang="ts">
  definePageMeta({
    pageTransition: {
      name: 'custom-flip',
      mode: 'out-in',
      onBeforeEnter: (el) => {
        console.log('Before enter...')
      },
      onEnter: (el, done) => {},
      onAfterEnter: (el) => {}
    }
  })
</script>

InfoTransitionコンポーネントで利用可能な追加のJavaScriptフックについて詳しく学びましょう。

動的なトランジション

動的なトランジションを条件付きロジックを使用して適用するには、inlineなミドルウェアを活用して、to.meta.pageTransitionに異なるトランジション名を割り当てることができます。

  • pages/id.vue
  • vue
<script setup lang="ts">
  definePageMeta({
    pageTransition: {
      name: 'slide-right',
      mode: 'out-in'
    },
    middleware (to, from) {
      to.meta.pageTransition.name = +to.params.id > +from.params.id ? 'slide-left' : 'slide-right'
    }
  })
</script>

<template>
  <h1>#{{ $route.params.id }}</h1>
</template>

<style>
  .slide-left-enter-active,
  .slide-left-leave-active,
  .slide-right-enter-active,
  .slide-right-leave-active {
    transition: all 0.2s;
  }
  .slide-left-enter-from {
    opacity: 0;
    transform: translate(50px, 0);
  }
  .slide-left-leave-to {
    opacity: 0;
    transform: translate(-50px, 0);
  }
  .slide-right-enter-from {
    opacity: 0;
    transform: translate(-50px, 0);
  }
  .slide-right-leave-to {
    opacity: 0;
    transform: translate(50px, 0);
  }
</style>
  • layouts/default.vue
  • vue
<script setup lang="ts">
  const route = useRoute()
  const id = computed(() => Number(route.params.id || 1))
  const prev = computed(() => '/' + (id.value - 1))
  const next = computed(() => '/' + (id.value + 1))
</script>

<template>
  <div>
    <slot />
    <div v-if="$route.params.id">
      <NuxtLink :to="prev">⬅️</NuxtLink> |
      <NuxtLink :to="next">➡️</NuxtLink>
    </div>
  </div>
</template>

ページは次のIDに移動するときにslide-leftのトランジションを適用し、前のIDに移動するときにslide-rightを適用します。

NuxtPageでのトランジション

app.vue<NuxtPage />を使用する場合、transition-propsをコンポーネントのプロパティとして直接渡すことで、グローバルなトランジションをアクティブにすることができます。

  • app.vue
  • vue
//ページが複数ある場合はpagesディレクトリを利用する。必ずしもapp.vueは必要ない。
//例えば「ランディングページ(ペライチ)」のような場合は、直接app.vueを利用して制作することになる。
<template>
  <div>
    <h1>Welcome to the homepage</h1>
  </div>
</template>

View Transitions API (実験的な機能)

Nuxt には、View Transitions APIの実験的な実装が同梱されています (MDNを参照)。 これは、(とりわけ) 異なるページ上の無関係な要素間を遷移する機能を備えた、ネイティブ ブラウザ トランジションを実装するエキサイティングな新しい方法です。

Nuxt 統合は現在開発中ですが、構成ファイルのExperimental.viewTransitionオプションで有効にすることができます。

  • nuxt.config.ts
  • ts
export default defineNuxtConfig({
  experimental: {
    viewTransition: true,
  },
});

もし新しいView Transitions APIと同じ結果を得るためにpageTransitionlayoutTransitionなどのVueのトランジションも使用している場合、ユーザーのブラウザが新しいネイティブWeb APIをサポートしている場合にVueのトランジションを無効にすることができます。以下の内容で~/middleware/disable-vue-transitions.global.tsを作成してください。

  • nuxt.config.ts
  • ts
export default defineNuxtRouteMiddleware((to) => {
  if (!document.startViewTransition) {
    return;
  }

  // Disable built-in Vue transitions
  to.meta.pageTransition = false;
  to.meta.layoutTransition = false;
});

既知の問題

  • ネストされたページ/レイアウト/非同期コンポーネントを使用する場合、ビュートランジションは予期通りに機能しない場合があります。これは、次のVueのバグに起因するものです: https://github.com/vuejs/core/issues/5513。このパターンを使用している場合は、この実験的な機能の導入を遅らせるか、自分で実装する必要があるかもしれません。フィードバックは大歓迎です。
  • もしページのセットアップ関数内でデータのフェッチを行っている場合、この機能を一時的に使用することを再考することをお勧めします。(設計上、ビュートランジションは実行中にDOMの更新を完全に停止します。)我々はビュートランジションを<Suspense>が解決される直前の最後の瞬間に制限することを検討していますが、その間、これが該当する場合は慎重に検討してこの機能を採用するかどうかを考えることをお勧めします。