/ transitions

Material Design navigation transition for Vue Router

Material Design navigation transition for Vue Router

vue-router-md-transition

The MaterialDesignTransition.vue SFC(Single File Component) wraps Vue's built-in <transition> component with additional CSS styles to achieve Material Design transition effect.

Usage

<md-transition>
  <router-view></router-view>
</md-transition>

Install

Direct Download / CDN

Include the UMD build after vue and vue-router, the component will be registered automatically:

<script src="/path/to/vue.js"></script>
<script src="/path/to/vue-router.js"></script>
<script src="/path/to/vue-router-md-transition.umd.min.js"></script>

📦 This package is available on bundle.run, unpkg and jsdelivr.

ES module

Install via npm:

npm install vue-router-md-transition

Import into your application:

import MaterialDesignTransition from 'vue-router-md-transition';

Register the component:

// globally
Vue.component('md-transition', MaterialDesignTransition);

or

// locally
export default {
  components: {
    'md-transition': MaterialDesignTransition,
  },
};

Customize:

Transition direction
<md-transition :reverse="true">
  <router-view></router-view>
</md-transition>
Disable transition
<md-transition :disabled="true">
  <router-view></router-view>
</md-transition>

You can dynamically control the transition by watching router's behavior. For example:

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <md-transition :reverse="routeBack" :disabled="transitionDisabled">
      <router-view></router-view>
    </md-transition>
  </div>
</template>

<script>
import MaterialDesignTransition from 'vue-router-md-transition';

export default {
  components: {
    'md-transition': MaterialDesignTransition,
  },
  data: () => ({
    routeBack: false,
    transitionDisabled: false,
  }),
  watch: {
    $route(to, from) {
      // disabled for browser refresh
      this.transitionDisabled = !from.name;
      // dynamically set direction
      if (to.path === '/') {
        this.routeBack = true;
        return;
      }
      if (from.path === '/') {
        this.routeBack = false;
        return;
      }
      const toDepth = to.path.split('/').length;
      const fromDepth = from.path.split('/').length;
      this.routeBack = toDepth < fromDepth;
    },
  },
};
</script>
Transition speed

Use CSS variable to override the default (250ms) animation duration:

<style>
:root {
  --md-transition-duration: 400ms;
}
</style>
The fading layer

The fading effect is achieved by adding an additional layer between the current view element and the upcoming view element. This fading layer is just the ::after psuedo element of the element of current view (or previous view in reversed direction), with its background set to the same with the element container's background and gradually increasing its opacity from 0 to 1. This creates a visual effect of fading.

Change fading layer background

To get the best result, the the fading layer's background should match the background of the element's container.

Use CSS variable to override the default background:

<style>
:root {
  /* set a color to match container's background, default is #fafafa */
  --md-fading-background: white;
}
</style>

If your app is in dark mode you may want the fading background to be dark:

<md-transition class="md-dark">
  <router-view></router-view>
</md-transition>

<style>
:root {
  /* set a color to match container's background, default is #121212 */
  --md-fading-background-dark: black;
}
</style>
Change fading layer offset top

By default, during transition there will be an offset top for the fading layer in order to not overlap with the Material Design top app bar. This can also be overriden by CSS variables:

<style>
:root {
  /* default is 56px, when viewport width < 960px */
  --md-app-bar-height: 0;
  /* default is 64px, when viewport width >= 960px */
  --md-app-bar-height-large: 0;
}
</style>

You can use .md-no-app-bar to quickly disable the offset top if your page is not using the app bar:

<md-transition class="md-no-app-bar">
  <router-view></router-view>
</md-transition>

Or use .md-app-bar-extended to set it to 128px if you're using an extended top app bar:

<md-transition class="md-app-bar-extended">
  <router-view></router-view>
</md-transition>
Beyond Vue Router

By default, the <md-transition></md-transition> will treat the element inside as a full width (block-level) element. This should be fine under most circumstances as the <router-view></router-view> is usually a full width element. But you can add the .md-auto-width class to disable this feature in case you don't use a full width router view:

<md-transition class="md-auto-width">
  <router-view></router-view>
</md-transition>

In fact, with .md-auto-width applied, you can not only use this package for Vue Router, but also any arbitrary transitions supported by Vue:

<md-transition class="md-auto-width">
  <div key="foo" v-if="show">Foo</div>
  <div key="bar" v-else>Bar</div>
</md-transition>

If you want more customizations, simply take the src/components/MaterialDesignTransition.vue, tweak it and use it just as any normal Vue SFC the way you like. Or you can submit a pull request to help me make it better.

GitHub