DEV Community

Cover image for Create Animated Mobile Navigations in Vue
James Sinkala
James Sinkala

Posted on • Edited on • Originally published at jamesinkala.com

Create Animated Mobile Navigations in Vue

This is how I created the mobile navigation for my website jamesinkala.me.

What we are trying to achieve is the following:

Cool Mobile Nav

Since this tutorial is based on the mobile navigation that I've used on my website, I have decided to use some of it's source code and as you'll notice, I used the UIKit CSS framework for my website's layout.

The Navigation Template

<section class="uk-navbar-container uk-margin">  
  <div class="uk-container-fluid">  
    <div class="js-visible-mobile uk-position-z-index">  
      <div class="cool-mobile-nav">  
        <div class="header">  
          <div class="logo">  
            <router-link to="/" title="Home">  
              <logo :dimensions="40" v-if="!_loading"></logo>  
              <loading-logo :dimensions="40" v-else></loading-logo>  
            </router-link>  
          </div>  
          <div @click="navToggle = !navToggle" class="snackbar">  
            <span v-if="!navToggle" uk-icon="icon: menu; ratio: 2"></span>  
            <span v-else uk-icon="icon: close; ratio: 2"></span>  
          </div>  
        </div>  
        <div v-show="hideNav" :class="navToggle ? 'list-item animate-in' : 'list-item animate-out'">  
          <router-link to="/work" title="Work">WORK</router-link>  
        </div>  
        <div v-show="hideNav" :class="navToggle ? 'list-item animate-in' : 'list-item animate-out'">  
          <router-link to="/personal-projects" title="Personal Projects">PERSONAL PROJECTS</router-link>  
        </div>
        <div v-show="hideNav" :class="navToggle ? 'list-item animate-in' : 'list-item animate-out'">
          <router-link to="/awesomeness">AWESOMENESS</router-link>
        </div>  
        <div v-show="hideNav" :class="navToggle ? 'list-item animate-in' : 'list-item animate-out'">  
          <router-link to="/blog" title="Blog">BLOG</router-link>
        </div>
      </div>
    </div>
  </div>
</section>
Enter fullscreen mode Exit fullscreen mode

From the layout above the main blocks that we'll focus on are:

<!-- THE SNACKBAR -->

<div @click="navToggle = !navToggle" class="snackbar">  
  <span v-if="!navToggle" uk-icon="icon: menu; ratio: 2"></span>  
  <span v-else uk-icon="icon: close; ratio: 2"></span>  
</div>
Enter fullscreen mode Exit fullscreen mode

AND

<!-- THE NAVIGATION LINKS -->

<div v-show="hideNav" :class="navToggle ? 'list-item animate-in' : 'list-item animate-out'">
  <router-link to="/awesomeness">AWESOMENESS</router-link>
</div>  
<div v-show="hideNav" :class="navToggle ? 'list-item animate-in' : 'list-item animate-out'">  
  <router-link to="/blog" title="Blog">BLOG</router-link>
</div>
Enter fullscreen mode Exit fullscreen mode

From the above code we notice the following boolean variables that we'll be working with:

data() {
  return {
    navToggle: false,
    hideNav: false
  }
}
Enter fullscreen mode Exit fullscreen mode

TD;LR

When an onclick event is detected on the snackbar block, we update the boolean variable navToggle. When it's value is changed we update the classes on the navigation list items by adding either the animate-in or animate-out classes.

These two classes apply the following animations on the navigation links based on their even and odd positioning.

.animate-in:nth-child(even){
  left: 0;
  animation: appear-from-left 0.5s ease-in 0s 1 alternate;
}
.animate-out:nth-child(even){
  left: -300px;
  animation: disappear-to-left 0.5s ease-out 0s 1 alternate;
}

.animate-in:nth-child(odd){
  right: 0;
  animation: appear-from-right 0.5s ease-in 0s 1 alternate;
}

.animate-out:nth-child(odd){
  right: -300px;
  animation: disappear-to-right 0.5s ease-out 0s 1 alternate;
}

/* Animations */
@keyframes appear-from-left {
  0% {
    left: -300px;
    opacity: 0;
  }
  100% {
    left: 0;
    opacity: 1.0;
  }
}
@keyframes disappear-to-left {
  0% {
    left: 0;
    opacity: 1.0;
  }
  100% {
    left: -300px;
    opacity: 0;
  }
}
@keyframes appear-from-right {
  0% {
    right: -300px;
    opacity: 0;
  }
  100% {
    right: 0;
    opacity: 1.0;
  }
}
@keyframes disappear-to-right {
  0% {
    right: 0;
    opacity: 1.0;
  }
  100% {
    right: -300px;
    opacity: 0;
  }
}
Enter fullscreen mode Exit fullscreen mode

Thus animating the navigation items in and out of view.

We also add watchers on the vue-router path and the boolean variable navToggle.

watch: {
  "$route.path" (){
    this.navToggle = false;
  },
  navToggle(){
    if(this.navToggle){
      this.hideNav = this.navToggle
    }else{
      setTimeout(() => {
        this.hideNav = this.navToggle
      }, 500)
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

When the route path changes, meaning we have navigated onto another page which is detected by watching "$route.path", we would like the navigation links to be out of view and only be animated into view when we toggle the snackbar, emulating regular link navigation.

When the value of navToggle changes we use it to update the value of hideNav, prompting whether to hide or show our navigation links. We hide the navigation links completely after 500ms

setTimeout(() => {...}, 500)

as that is the same amount of time that we expect our navigation links to be animated out of view as described on our animation style animation: appear-from-right 0.5s ease-in 0s 1 alternate;.

You can avoid applying hideNav on each of the navigation link items by placing the links as children to a parent block which you'll be applying visibility status to v-show="hideNav", I guess I was too lazy to make that change.

Top comments (0)