How to Animate Objects When Shown Inside Viewport with VueJS and Animate.css
Jian Jye • October 29, 2019
vuejsAnimate.css has made animation superbly simple for all web developers. One problem however is that, it will always animate the objects on pageload. If our elements are below the fold / viewport, then it would have already been animated by the time we scroll to that position.
With the help of VueJS and Vue Observe Visibility plugin however, we can add some finer control as to when to animate our objects.
The logic behind this is that, the Vue Observe Visibility plugin would do the necessary calculations to see if an element is visible in the viewport, then VueJS would set the necessary flag to animate the object accordingly.
With this, we can make sure that the animations would only be triggered when they are visible.
It's very simple. Let's begin!
Step 1. Include VueJS, Vue Observe Visibility Plugin and Animate.css
Let's include all the necessary files into our web page.
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-observe-visibility/dist/vue-observe-visibility.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">
</head>
<body>
...
</body>
</html>
If you are not using Tailwind CSS, you may need these 2 CSS classes to be added in <head>
.
<style>
.visible { visibility: visible; }
.invisible { visibility: hidden; }
</style>
Step 2. Basic Example
<html>
<head>...</head>
<body>
<div id="demo">
<div v-observe-visibility="{ callback: isViewableNow, once: true }" :class="{ 'visible animated slideInRight': showAnimation, 'invisible': !showAnimation }">
Can you see this animation?
</div>
</div>
<script>
var demo = new Vue({
el: '#demo',
data: {
showAnimation: false,
},
methods: {
isViewableNow(isVisible, entry) {
this.showAnimation = isVisible;
}
}
});
</script>
</body>
</html>
Step 3. Detailed Explanations
So what happened there? Let's us delve into how this works.
Vue Observe Visibility
First, we made Vue Observe Visibility plugin to check this particular object by adding the v-observe-visibility
attribute. It takes a function callback that we named isViewableNow
. You can name this function anything as long as it matches what you have declared in Javascript.
Then we made sure it is to be called only once by setting once: true
. Otherwise your animation would restart itself everytime it's viewable in your viewport, which may or may not be what you want.
<div v-observe-visibility="{ callback: isViewableNow, once: true }" ...></div>
VueJS + Animate.css
The second part of the same div
, we have the VueJS :class
attribute.
If you are not familiar with VueJS, what :class
does is let VueJS decide if it should add or remove any classes based on some value, which in our case is the showAnimation
variable.
When the object is not visible, we add in the CSS class invisible
to hide the element. When it's visible, we add in the CSS class visible
to show the element.
In addition to visible
, we are also adding in the Animate.css classes animated
slideInRight
. This is to trigger the animation effects as we desired when the object becomes visible.
<div ... :class="{ 'visible animated slideInRight': showAnimation, 'invisible': !showAnimation }"></div>
Step 4. Animating Multiple Objects
Now what if you need to animate more than 1 object on the same page? Having to declare multiple callbacks doesn't seem like such a good idea.
One way is to make the isViewableNow
method reusable. Thankfully it accepts a third optional argument that we can use to set our objects visibilities.
The new codes would look like this:
<html>
<head>...</head>
<body>
<div id="demo2">
<div v-observe-visibility="{ callback: (isVisible, entry) => isViewableNow(isVisible, entry, 'a') }" :class="{ 'visible animated slideInRight': showAnimationFor.a, 'invisible': !showAnimationFor.a }">
Can you see this animation part 2?
</div>
<div v-observe-visibility="{ callback: (isVisible, entry) => isViewableNow(isVisible, entry, 'b') }" :class="{ 'visible animated slideInLeft': showAnimationFor.b, 'invisible': !showAnimationFor.b }">
Can you see this animation part 3?
</div>
</div>
<script>
var demo = new Vue({
el: '#demo2',
data: {
showAnimationFor: {
a: false,
b: false,
c: false,
}
},
methods: {
isViewableNow(isVisible, entry, section) {
this.showAnimationFor[section] = isVisible;
}
}
});
</script>
</body>
</html>
Step 5. Detailed Explanations Part 2
So what have we done?
First we added a third argument for our isViewableNow
method to show which section is being triggered at the moment.
// V2
isViewableNow(isVisible, entry, section) {
this.showAnimationFor[section] = isVisible;
}
// V1
isViewableNow(isVisible, entry) {
this.showAnimation = isVisible;
}
Then we updated the callback codes for isViewableNow
into the new form, allowing the callback to take the new third argument for our sections.
// V2
<div v-observe-visibility="{ callback: (isVisible, entry) => isViewableNow(isVisible, entry, 'a') }" ...></div>
// V1
<div v-observe-visibility="{ callback: isViewableNow, once: true }" ...></div>
Finally we updated our :class
attribute to check the respective sections on the new showAnimationFor
object.
// V2
<div ... :class="{ 'visible animated slideInRight': showAnimationFor.a, 'invisible': !showAnimationFor.a }"></div>
// V1
<div ... :class="{ 'visible animated slideInRight': showAnimation, 'invisible': !showAnimation }"></div>
And with these minor modifications, you can have as many objects to be animated as you like!
Closing
That's all! It's surprisingly simple isn't it?
I hope you find this guide helpful.