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.