How to Create Hover Animation in Vue.js

To create a hover animation in Vue.js, use the “mouseover, mouseout event, and the selected property, which will change the css3 properties and create an animation.”

Here are steps to implement hover animation in Vue.js.

Step 1: Install Vue.js.

npm install -g @vue/cli

# OR

yarn global add @vue/cli

Create a new Vue.js project using the following command.

vue create animation

Inside the src >> App.vue file, add the following code to create a Card. Remember, we are not using the Bootstrap framework, so that we will write the css from scratch.

<!-- App.vue -->

<div id="app">
  <div class="card-row">
    <div class="card">
      
      <img class="card-image" src="https://www.gstatic.com/webp/gallery3/2_webp_ll.png">
      
      <div class="card-footer">
        <h3 class="card-title">Title</h3>
        <p class="card-text">by 
          <span class="card-author">Author</span>
        </p>
      </div>
    </div>
  </div>
</div>

So, we created the card, but we needed to build its styles. So inside the src >> assets folder, create one file called style.css and add the css code.

body {
  background-color: #E1E7E7;
}

.card-row {
  display: flex;
  justify-content: center;
  align-items: center;  
  min-width: 780px;
  width: 100%;
  height: 500px;
}

We use Flexbox for styling because it is effortless to use. The next step is to style the card.

Step 2: Style the Card

Write the following code inside the style.css file.

.card {
  position: relative;
  background-color: #FFFFFF;
  height: 370px;
  width: 240px;
  margin: 10px;
  overflow: hidden;
  box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.5);
}

The position of the card will be relative. Overflow must be hidden because we do not need to display the image outside the card when resized.

Overflow will always be hidden. The box-shadow property adds the shadow to the card.

Step 3: Style the Image

Add the following code inside the style.css file.

.card-image {
  position: absolute;
  left: -9999px;
  right: -9999px;
  margin: auto;
  height: 220px;
  min-width: 100%;
}

I have taken a left and right to -9999px because when we hover the image, the animation effect will be applied, so it should center the image horizontally. Therefore, the position is absolute, and the min-width is 100%.

Step 4: Style the Footer

Write the following code inside a style.css file.

.card-footer {
  position: absolute;
  bottom: 0;
  height: 130px;
  padding: 10px 15px;
  font-family: Helvetica;
}
.card-text {
  font-size: 14px;
  color: rgba(0, 0, 0, 0.7);
}
.card-title {
  font-family: Serif;
}
.card-author {
  font-size: 14px;
  color: #BAB096;
}

It is pretty much the same stuff; we have assigned different classes to its styles. Nothing is more complicated.

Step 5: Add the data

We have created one card, but now, we will create five cards. So we need an array of data. So let us define the data inside the App.vue file. Also, we have to import the style.css inside the App.vue file to see the changes.

// App.vue

import './assets/style.css';

export default {
  name: 'app',
  data() {
    return {
      cards: [
        {
         title: 'Gallery', 
         author: 'Walder Frey', 
         image: 'http://www.gstatic.com/webp/gallery/1.webp'
        },
        {
          title: 'Penguin', 
          author: 'Ramsey Bolton', 
          image: 'https://www.gstatic.com/webp/gallery3/2_webp_ll.png'
        },
        {
          title: 'Flower', 
          author: 'Joffrey Baratheon', 
          image: 'https://www.gstatic.com/webp/gallery3/1.png'
        },
         {
          title: 'Flower Pot', 
          author: 'Cersie Lannister', 
          image: 'https://www.fiftyflowers.com/site_files/FiftyFlowers/Image/Product/Make_Your_Own_Centerpiece_Close_Up_350_a425aad8.jpg'
        },
         {
          title: 'Rose', 
          author: 'Roose Bolton', 
          image: 'https://res.cloudinary.com/prestige-gifting/image/fetch/fl_progressive,q_95,e_sharpen:50,w_480/e_saturation:05/https://www.prestigeflowers.co.uk/images/NF4016-130116.jpg'
        }
      ]
    }
  }
}

And now, in our template, we can render those cards with a v-for directive.

<!-- App.vue -->
<div id="app">
  <div class="card-row">
    <div v-for="(card, index) in cards" 
      :key="index"
      :ref="`card_${index}`"
         class="card">
      
      <img class="card-image" :src="card.image">
      
      <div class="card-footer">
        <h3 class="card-title">{{card.title}}</h3>
        <p class="card-text">by 
          <span class="card-author">{{card.author}}</span>
        </p>
      </div>
    </div>
  </div>
</div>

How To Create Hover Animation In Vuejs

Step 6: Add the hover effect

I am writing the whole code here. So bear with me.

First, I am showing the complete code of the style.css file.

body {
    background-color: #E1E7E7;
  }
  
  .card-row {
    display: flex;
    justify-content: center;
    align-items: center;  
    min-width: 780px;
    width: 100%;
    height: 500px;
  }
  
  .card {
    position: relative;
    background-color: #FFFFFF;
    height: 370px;
    width: 240px;
    margin: 10px;
    overflow: hidden;
    box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.5);
  }
  
  .card-image {
    /* center horizontally overflown image */
    position: absolute;
    left: -9999px;
    right: -9999px;
    margin: auto;
  
    height: 220px;
    min-width: 100%;
  
    transition: height 0.3s, opacity 0.3s;
  }
  .card-image.selected {
    height: 410px;
    opacity: 0.3;
  }
  
  .card-footer {
    position: absolute;
    bottom: 0;
    height: 130px;
    padding: 10px 15px;
    font-family: Helvetica;
  }
  .card-text {
    font-size: 14px;
    color: rgba(0, 0, 0, 0.7);
  }
  .card-title {
    font-family: Serif;
  }
  .card-author {
    font-size: 14px;
    color: #BAB096;
    transition: color 0.3s;
  }
  .card-author.selected {
    color: #6a6456;
  }
  .card {
    /* the other rules */
    transition: height 0.3s, box-shadow 0.3s;
  }
  .card:hover {
    height: 410px;
    box-shadow: 20px 20px 40px 0px rgba(0,0,0,0.5);
  }

Write the following code inside App.vue file.

<!-- App.vue -->

<template>
  <div id="app">
    <div class="card-row">
    <div v-for="(card, index) in cards" 
        :key="index"
        :ref="`card_${index}`"
        @mouseover="hoverCard(index)"
        @mouseout="hoverCard(-1)"
        class="card">
      
      <img class="card-image" 
        :class="{'selected': isSelected(index)}"
        :src="card.image">
      
      <div class="card-footer">
        <h3 class="card-title">{{card.title}}</h3>
        <p class="card-text">by 
          <span 
            class="card-author" 
            :class="{'selected': isSelected(index)}">
                {{card.author}}
          </span>
        </p>
      </div>
    </div>
  </div>
  </div>
</template>

<script>

import './assets/style.css';

export default {
  name: 'app',
  data() {
    return {
      selectedCard: -1,
      cards: [
        {
         title: 'Gallery', 
         author: 'Walder Frey', 
         image: 'http://www.gstatic.com/webp/gallery/1.webp'
        },
        {
          title: 'Penguin', 
          author: 'Ramsey Bolton', 
          image: 'https://www.gstatic.com/webp/gallery3/2_webp_ll.png'
        },
        {
          title: 'Flower', 
          author: 'Joffrey Baratheon', 
          image: 'https://www.gstatic.com/webp/gallery3/1.png'
        },
         {
          title: 'Flower Pot', 
          author: 'Cersie Lannister', 
          image: 'https://www.fiftyflowers.com/site_files/FiftyFlowers/Image/Product/Make_Your_Own_Centerpiece_Close_Up_350_a425aad8.jpg'
        },
         {
          title: 'Rose', 
          author: 'Roose Bolton', 
          image: 'https://res.cloudinary.com/prestige-gifting/image/fetch/fl_progressive,q_95,e_sharpen:50,w_480/e_saturation:05/https://www.prestigeflowers.co.uk/images/NF4016-130116.jpg'
        }
      ]
    }
  },
  methods: {
    hoverCard(selectedIndex) {
      this.selectedCard = selectedIndex
    },
    isSelected(cardIndex) {
      return this.selectedCard === cardIndex
    }
  }
}
</script>

So, here, I have defined the two events.

  1. @mouseover
  2. @mouseout

So when we hover any image, we pass an index to the function defined in the mouseover event.

Now, that function assigns that index to the selected property.

The reason behind that is straightforward when the user hovers over the image at that time, that image is selected, and we need to apply the hover css classes to that image. 

<img class="card-image" 
        :class="{'selected': isSelected(index)}"
        :src="card.image">

If the selected image has that index, we bind the selected class, and the animation effect will be applied. The following style.css code helps us to apply the animated effect. It is a simple CSS 3 rule.

.card-image {
  /* the other rules */
  transition: height 0.3s, opacity 0.3s;
}
.card-image.selected {
  height: 410px;
  opacity: 0.3;
}

If you have written style.css and App.vue files, go to the browser and see the result.

That’s it for this tutorial.

2 thoughts on “How to Create Hover Animation in Vue.js”

  1. Why even using Vue just to toggle a `selected` class on `card-image` when you can use CSS and do `.card:hover .card-image` ? ? (Note: i’m ok to use Vue to build the markup)

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.